Prev: Linux
Next: The BIG Picture (VB vs the OS)
From: Karl E. Peterson on 28 Jan 2010 16:34 It happens that argusy formulated : > I'm trying to open a jpg file, find the position of "FF C0 00 01 08" and get > the next four bytes of info. (width and height of said jpg) > > That data never stays in one fixed spot, so I have to find it. > > Anyone interested in giving me a hand with the code? Mike Sutton might. Grab the JPG Info sample here: http://edais.mvps.org/Files/Demo/Page3.html It's got all this stuff, and a lot more, in it. (As interesting as the InstrB thing is, and it is certainly a technique to be aware of, why pound sand when you can actually pick through the header as it was designed to be picked through?) -- ..NET: It's About Trust! http://vfred.mvps.org
From: Karl E. Peterson on 28 Jan 2010 21:27 argusy pretended : > I'm trying to open a jpg file, find the position of "FF C0 00 01 08" and get > the next four bytes of info. (width and height of said jpg) I've opened a couple of JPGs, and none of them seem to have that signature in them. Are you sure that's what you want to look for? At any rate, I was pretty surprised about how little known the InstrB functionality was for scanning byte arrays, so I thought this would be a good thing to throw out in a column sometime. I haven't seen anyone else post a working snippet for the thread, so here's a very simple and quick preview of what may show up at VSM Online one of these days... Public Sub Main() Dim Buffer() As Byte Dim Search() As Byte Dim Found As Long Const jpg As String = "D:\Images\Projects\freeways\city01.jpg" If ReadFileB(jpg, Buffer()) Then If ReadHexBytes("4A464946", Search) Then Found = InStrB(Buffer, Search) ' This is a one-based offset, so we need to correct ' for using zero-based arrays. Found = Found - 1 If Found >= 0 Then Debug.Print "Found byte pattern at offset:"; Found Else Debug.Print "Byte pattern not found." End If End If End If End Sub Does anyone have a more elegant way to bust a string of hex bytes down into a byte array? Putting together the following routine was actually half the purpose of going through this exercise of me. It seems I routinely want to do something like this, but never took the time to make it a standalone function. (Waiting for Rick's won-liner. <g>) Private Function ReadHexBytes(ByVal HexValues As String, Data() As Byte) As Boolean Dim i As Long, n As Long n = Len(HexValues) ' Input string must be a multiple of two chars. If (n > 0) And (n Mod 2 = 0) Then ReDim Data(0 To n \ 2 - 1) As Byte For i = 0 To UBound(Data) Data(i) = Val("&h" & Mid$(HexValues, i * 2 + 1, 2)) Next i ReadHexBytes = True End If End Function And then there's just the standard slurp of an entire file into a JPG. Actually, taking Larry's idea, it might be kind of fun to modify this so that it would (optionally) return a segment of the file starting at a given offset? Private Function ReadFileB(ByVal FileName As String, Data() As Byte) As Boolean Dim hFile As Long On Error GoTo Hell hFile = FreeFile Open FileName For Binary As #hFile ReDim Data(0 To LOF(hFile) - 1) As Byte Get #hFile, , Data Close #hFile Hell: ReadFileB = Not CBool(Err.Number) End Function There ya go... -- ..NET: It's About Trust! http://vfred.mvps.org
From: Larry Serflaten on 29 Jan 2010 08:53 "Karl E. Peterson" <karl(a)exmvps.org> wrote > argusy pretended : > > I'm trying to open a jpg file, find the position of "FF C0 00 01 08" and get > > the next four bytes of info. (width and height of said jpg) > > I've opened a couple of JPGs, and none of them seem to have that > signature in them. Are you sure that's what you want to look for? I think he just wanted the first occurance of "FF C0" (maybe not, but that's what worked for me....) > At any rate, I was pretty surprised about how little known the InstrB > functionality was for scanning byte arrays, so I thought this would be > a good thing to throw out in a column sometime. I haven't seen anyone > else post a working snippet for the thread, so here's a very simple and > quick preview of what may show up at VSM Online one of these days... <snipped> I understood it as being something like this: Private Sub Form_Load() Dim buf() As Byte Dim fnd() As Byte Dim rst() As Byte Dim pos As Long Const FILE = "D:\temp\testimage.jpg" ' Get file data ReDim buf(0 To 4095) Open FILE For Binary As 1 Get #1, , buf Close 1 ' Find marker fnd = ChrW(&HC0FF) pos = InStrB(1, buf, fnd, vbBinaryCompare) If pos > 0 Then ' Print size rst = MidB(buf, pos + 5, 4) Debug.Print "File:", FILE Debug.Print "Size: ", rst(2) * 256& + rst(3); "x"; rst(0) * 256& + rst(1) End If End Sub > Does anyone have a more elegant way to bust a string of hex bytes down > into a byte array? For me, it depends on the number of bytes desired. For a predetermined constant value you can use the Chr, ChrW, or if you stuff them all into some longer string; StrConv. But for a general purpose routine, I'd go with something like this: Function ByteArray(ParamArray Data()) As Variant Dim D() As Byte Dim ub As Long, i As Long ub = UBound(Data) If ub >= 0 Then ReDim D(0 To ub) For i = 0 To ub D(i) = Data(i) And 255 Next End If ByteArray = D End Function Mind you that will choke if you send it string data, but you get the idea.... Note that the returned array will also work in the search routine above, specifically, the line to assign the search argument could be: fnd = ByteArray(&HFF, &HC0) FWIW... LFS
From: Schmidt on 31 Jan 2010 11:44 "Schmidt" <sss(a)online.de> schrieb im Newsbeitrag news:ewQDQxnoKHA.3948(a)TK2MSFTNGP06.phx.gbl... Sorry, the code needs a small change with regards to "LBound-Awareness" of the passed BFind()-Array: Please serach for this sequence in the Class... '**** brute-force loops for very short find-sequences (<= 2Chars) If FndLen <= 2 Then If Comp = vbBinaryCompare Then Char = BFind(0) If FndLen = 2 Then Char2 = BFind(1) Else Char = LCaseLUT(BFind(0)) If FndLen = 2 Then Char2 = LCaseLUT(BFind(1)) End If And change it to: '**** brute-force loops for very short find-sequences (<= 2Chars) If FndLen <= 2 Then Char = BFind(LBound(BFind)) If FndLen = 2 Then Char2 = BFind(LBound(BFind) + 1) If Comp <> vbBinaryCompare Then Char = LCaseLUT(Char) Char2 = LCaseLUT(Char2) End If That will ensure, that the BFind-Array-Param can be used with LBounds, different from Zero - this patch is relevant only for BFind-Length' <=2 (in the BruteForce-Scanning-part of the Function). The Boyer-Moore-Section is already correctly covered regarding the "BFind-LBounds", since in this section an appropriate copy-over from BFind into a ZeroBound-Array (BF) is done beforehand. Olaf
From: Karl E. Peterson on 2 Feb 2010 12:46
Larry Serflaten explained : > "Karl E. Peterson" <karl(a)exmvps.org> wrote >> argusy pretended : >>> I'm trying to open a jpg file, find the position of "FF C0 00 01 08" and >>> get the next four bytes of info. (width and height of said jpg) >> >> I've opened a couple of JPGs, and none of them seem to have that >> signature in them. Are you sure that's what you want to look for? > > I think he just wanted the first occurance of "FF C0" > (maybe not, but that's what worked for me....) I dunno. I trusted Mike's implementation of JpgInfo when I needed to pick those headers apart. Worked like a charm. This problem just interested me from a more generic perspective, as I realized how few folks were aware of the byte array scanning available with InstrB. >> At any rate, I was pretty surprised about how little known the InstrB >> functionality was for scanning byte arrays, so I thought this would be >> a good thing to throw out in a column sometime. I haven't seen anyone >> else post a working snippet for the thread, so here's a very simple and >> quick preview of what may show up at VSM Online one of these days... > <snipped> > > I understood it as being something like this: > > Private Sub Form_Load() > Dim buf() As Byte > Dim fnd() As Byte > Dim rst() As Byte > Dim pos As Long > Const FILE = "D:\temp\testimage.jpg" > > ' Get file data > ReDim buf(0 To 4095) > Open FILE For Binary As 1 > Get #1, , buf > Close 1 > > ' Find marker > fnd = ChrW(&HC0FF) > pos = InStrB(1, buf, fnd, vbBinaryCompare) > > If pos > 0 Then > ' Print size > rst = MidB(buf, pos + 5, 4) > Debug.Print "File:", FILE > Debug.Print "Size: ", rst(2) * 256& + rst(3); "x"; rst(0) * 256& + > rst(1) End If > > End Sub Yeah, that's a specific implmentation. >> Does anyone have a more elegant way to bust a string of hex bytes down >> into a byte array? > > For me, it depends on the number of bytes desired. For a predetermined > constant value you can use the Chr, ChrW, or if you stuff them all into some > longer string; StrConv. But for a general purpose routine, I'd go with > something like this: > > Function ByteArray(ParamArray Data()) As Variant > Dim D() As Byte > Dim ub As Long, i As Long > > ub = UBound(Data) > If ub >= 0 Then > ReDim D(0 To ub) > For i = 0 To ub > D(i) = Data(i) And 255 > Next > End If > ByteArray = D > > End Function > > > Mind you that will choke if you send it string data, but you get the idea.... Not a bad idea! It's more typing, which folks always seem to want to avoid <g>, of course. Certainly more efficient, but that's unlikely to be a concern for something of this nature. I dunno why, but so often I overlook the ParamArray solutions. I'll have to think about that as another option. One nice thing about it is, the inputs wouldn't *have* to be hex. Yeah, a lot to recommend that. > Note that the returned array will also work in the search routine above, > specifically, the line to assign the search argument could be: > > fnd = ByteArray(&HFF, &HC0) I like! :-) -- ..NET: It's About Trust! http://vfred.mvps.org |