Author | Message | Time |
---|---|---|
Ringo | Ok, so, I got really bored and thought I would give loading MNG files ago, after looking at a few PNG/MNG files in hex. There is TONS of things im not sure about (thats an under-statement) but it does just about work! [s]A few images have slightly messed up color for some reassion[/s], and some of the multi framed images need abit more figgering out, as they dont always line up correctly. Im pretty sure that multiple frames can/should be bound together to create 1 frame tho, but havent really looked into it that much. Also, this requires transparent drawing, which I didnt bother with, so that doesnt help :P I basicly built it around as many BNCS MNG's I could get my hands on, so it only supports 16 and 256 colors images and probly wont load other/non-W3 MNG's. I also dunno where the frame delay is, so in my bot I just toggle the frames every 2 seconds. Below, is my testing code (with the debug crap removed) and its not very error checky, and boy is it a mess! Your welcome to use this code in anyway you see fit, it should be a good start/example of how to load MNG's! If anyone would like to add to this, feel free, but I persionaly have lost interest and am now working on some other stuff. It might be worth trying to find some documentation on MNG's, as I didnt bother and just worked from hex dumps mostly. (I got the PNG header from google tho) If the quality of the way SC/D2 displays SMK stuff is to go by, this will work abit better than that, hence why I lost interest :) Anyway, Injoy! Some other notes: The LoadMNG() function will return a BITMAPSTRUT array, which contains the handle to the image in memory, so you can then use a few GDI API's to draw etc. Just remember to DeleteObject() on that handle when your finished/load a fresh, otherwise you will be eating up ram! If your add banner is resizeable (like mine was when testing) you will need to do some math with the defalt animation width/height in the MNGDATAHEADER to scale everything correctly. If you use somthing like transparentBitblt() and only clear the image on the 1st bitmap, that should massive improove the quality of multi frame animation (but will be limited to win2000 and later) Other wise you will black out the last image and it wont look right (like i was doing in testing) That said, only 1 multi framed mng was offseted strangely, so it might also be advised to wrap around the frames if part of them go over the orginal frame dimentions! EDIT: ok, just glanced over the code after posting, and fixed the messed up colors. Turned out when i was shifting the pallet up for the bit map header, I was only shifting 768 bytes and not 1024 :p (woopsy) So, color is perfect now! Also, drawing with transparency should make the multi frame animations perfect as well, its only that 1 mng that was offsetted badly, but after seeing it on the client, it was offsetted badly there to! [code] Private Type RGBQUAD rgbBlue As Byte rgbGreen As Byte rgbRed As Byte rgbReserved As Byte End Type Private Type RGBTriple rgbBlue As Byte rgbGreen As Byte rgbRed As Byte End Type Private Type BITMAPINFOHEADER biSize As Long biWidth As Long biHeight As Long biPlanes As Integer biBitCount As Integer biCompression As Long biSizeImage As Long biXPelsPerMeter As Long biYPelsPerMeter As Long biClrUsed As Long biClrImportant As Long End Type Private Type MNGDATAHEADER FrameWidth As Long FrameHeight As Long Unknown0 As Long Unknown1 As Long Unknown2 As Long Unknown3 As Long Unknown4 As Long Unknown5 As Long Unknown6 As Long End Type Private Type PNGINFOHEADER 'IHDR Width As Long Height As Long Bits As Byte ColorType As Byte Compresion As Byte Filter As Byte Interlace As Byte Unknown1 As Long Unknown2 As Long End Type Private Declare Function uncompress Lib "zlib.dll" (dest As Any, destLen As Any, _ src As Any, ByVal srcLen As Long) As Long Private Declare Function GetDC Lib "user32" (ByVal hWnd As Long) As Long Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long Private Declare Function CreateDIBitmap Lib "gdi32" (ByVal hdc As Long, _ lpInfoHeader As Any, ByVal dwUsage As Long, lpInitBits As Any, _ lpInitInfo As Any, ByVal wUsage As Long) As Long Public Type BITMAPSTRUT Width As Long Height As Long Handle As Long OffX As Long OffY As Long End Type Public Function LoadMNG(ByVal strFilePath As String, BitMap() As BITMAPSTRUT) As Boolean Dim FF As Integer Dim S As String Dim lngPos As Long Dim bPal() As Byte Dim bData() As Byte Dim bOut() As Byte Dim pIH As PNGINFOHEADER Dim pBM As BITMAPINFOHEADER Dim mDH As MNGDATAHEADER Dim lngTest As Long 'check headers Dim BitMapCount As Long Dim lngBackCol As Long Dim bBackCol As Boolean BitMapCount = -1 lngPos = 1 If Dir(strFilePath) = vbNullString Then Exit Function FF = FreeFile() Open strFilePath For Binary As #FF S = String(LOF(FF), 0) Get #FF, 1, S Close #FF Call CopyMemory(lngTest, ByVal S, 4) lngPos = lngPos + 12 If Not lngTest = &H474E4D8A Then '.MNG Debug.Print "MNG Bad File Header ID" Exit Function End If LoadMNGNewHeader: Call CopyMemory(lngTest, ByVal Mid$(S, lngPos, 4), 4) lngPos = lngPos + 4 If lngTest = &H5244484D Then 'MHDR Call CopyMemory(mDH, ByVal Mid$(S, lngPos, Len(mDH)), Len(mDH)) lngPos = lngPos + Len(mDH) mDH.FrameWidth = lngReverse(mDH.FrameWidth) mDH.FrameHeight = lngReverse(mDH.FrameHeight) If mDH.FrameWidth < 1 Or mDH.FrameHeight < 1 Then Debug.Print "MNG Bad Animation Size " & mDH.FrameWidth & "/" & mDH.FrameHeight Exit Function End If ElseIf lngTest = &H4D524554 Then 'TERM lngPos = lngPos + 18 ElseIf lngTest = &H4B434142 Then 'BACK bBackCol = True Call CopyMemory(lngBackCol, ByVal Mid$(S, lngPos, 1) & Mid$(S, lngPos + 2, 1) & Mid$(S, lngPos + 4, 1), 3) lngPos = lngPos + 14 ElseIf lngTest = &H44474B62 Then 'bKGD lngPos = lngPos + 14 ElseIf lngTest = &H4D415246 Then 'FRAM lngPos = lngPos + 18 ElseIf lngTest = &H454D4974 Then 'tIME lngPos = lngPos + 15 ElseIf lngTest = &H52444849 Then 'IHDR (info) Call CopyMemory(pIH, ByVal Mid$(S, lngPos, Len(pIH)), Len(pIH)) lngPos = lngPos + Len(pIH) pIH.Width = lngReverse(pIH.Width) pIH.Height = lngReverse(pIH.Height) If pIH.Width < 1 Or pIH.Height < 1 Then Debug.Print "MNG Bad Image Size " & pIH.Width & "/" & pIH.Height Exit Function End If If Not pIH.Bits = 4 And Not pIH.Bits = 8 Then '8 bit only Debug.Print "MNG Bad File Bits " & pIH.Bits Exit Function End If If Not pIH.ColorType = 3 Then Debug.Print "MNG Bad Color type" Exit Function End If ElseIf lngTest = &H45544C50 Then 'PLTE (pallet) 'check we got a header If Not pIH.Bits = 4 And Not pIH.Bits = 8 Then Exit Function lngTest = InStr(lngPos, S, "IDATx") - lngPos If lngTest < 1 Then Debug.Print "MNG No Pallet" Exit Function End If ReDim bPal(lngTest - 1) Call CopyMemory(bPal(0), ByVal Mid$(S, lngPos, lngTest), lngTest) lngPos = lngPos + lngTest ElseIf lngTest = &H54414449 Then 'IDAT (image data) If Not pIH.Bits = 4 And Not pIH.Bits = 8 Then Exit Function 'check we got header lngTest = InStr(lngPos, S, "IENDŽB`") - lngPos lngTest = lngTest - 4 If lngTest < 1 Then Debug.Print "MNG No iEnd" Exit Function End If ReDim bData(lngTest - 1) ReDim bOut((((pIH.Width * pIH.Height) * 1.01) + 12)) Call CopyMemory(bData(0), ByVal Mid$(S, lngPos, lngTest), lngTest) lngPos = lngPos + lngTest + 4 Call uncompress(bOut(0), UBound(bOut) + 1, bData(0), lngTest) If pIH.Bits = 8 Then Call ClipLines(bOut(), pIH.Width, pIH.Height) ElseIf pIH.Bits = 4 Then Call ClipLines(bOut(), pIH.Width / 2, pIH.Height) End If Call SortPNGPallet8(bPal(), bBackCol, lngBackCol) ReDim Preserve bPal(UBound(bPal) + Len(pBM)) pBM.biSize = Len(pBM) pBM.biPlanes = 1 pBM.biBitCount = pIH.Bits pBM.biWidth = pIH.Width pBM.biHeight = pIH.Height '//Move pallet up 40 spaces Call CopyMemory(bPal(Len(pBM)), bPal(0), 1024) '//add info header Call CopyMemory(bPal(0), pBM, Len(pBM)) '//Create the diBitmap BitMapCount = BitMapCount + 1 ReDim Preserve BitMap(BitMapCount) BitMap(BitMapCount).Width = pBM.biWidth BitMap(BitMapCount).Height = pBM.biHeight BitMap(BitMapCount).OffX = 0 BitMap(BitMapCount).OffY = 0 lngTest = GetDC(0) BitMap(BitMapCount).Handle = CreateDIBitmap(lngTest, pBM, &H4, bOut(0), bPal(0), &H0) Call DeleteDC(lngTest) ElseIf lngTest = &H444E4549 Then 'IEND (end of image data) lngPos = lngPos + 8 ElseIf lngTest = &H49464544 Then 'DEFI If BitMapCount >= 0 Then Call CopyMemory(BitMap(BitMapCount).OffX, ByVal Mid$(S, lngPos + 4, 4), 4) Call CopyMemory(BitMap(BitMapCount).OffY, ByVal Mid$(S, lngPos + 8, 4), 4) BitMap(BitMapCount).OffX = lngReverse(BitMap(BitMapCount).OffX) BitMap(BitMapCount).OffY = lngReverse(BitMap(BitMapCount).OffY) End If lngPos = lngPos + 20 ElseIf lngTest = &H444E454D Then 'MEND (end of MNG) lngPos = lngPos + 8 LoadMNG = (BitMapCount >= 0) Exit Function Else Debug.Print "Unknown MNG Header: " & MakeDWORD(lngTest) Exit Function End If GoTo LoadMNGNewHeader End Function Private Function lngReverse(ByVal lngValue As Long) As Long Dim S As String * 4 Call CopyMemory(ByVal S, lngValue, 4) S = StrReverse(S) Call CopyMemory(lngReverse, ByVal S, 4) End Function Private Sub SortPNGPallet8(ByRef bPallet() As Byte, ByVal bBackGround As Boolean, _ ByVal lngBackColor As Long) Dim i As Integer Dim i2 As Integer Dim T(255) As RGBTriple Dim Q(255) As RGBQUAD Dim lngTest As Long Dim bTest As Boolean ReDim Preserve bPallet(1023) Call CopyMemory(T(0), bPallet(0), 768) For i = 0 To 255 Q(i).rgbRed = T(i).rgbBlue Q(i).rgbGreen = T(i).rgbGreen Q(i).rgbBlue = T(i).rgbRed Next i If bBackGround And (Not lngBackColor = 0) Then For i = 0 To 255 Call CopyMemory(lngTest, Q(i), 3) If lngTest = lngBackColor Then If bTest = False Then bTest = True Else lngTest = 0 Call CopyMemory(Q(i), lngTest, 4) End If End If Next i End If Call CopyMemory(bPallet(0), Q(0), 1024) End Sub Private Sub ClipLines(ByRef bData() As Byte, ByVal lngBPL As Long, ByVal lngHeight As Long) Dim i As Long Dim lngPos As Long Dim bOut() As Byte Dim lngWidth As Long lngWidth = lngBPL If Not (lngWidth Mod 4) = 0 Then lngWidth = lngWidth + (4 - (lngWidth Mod 4)) End If ReDim bOut(lngWidth - 1, lngHeight - 1) ReDim Preserve bData((lngWidth * lngHeight) - 1) For i = (lngHeight - 1) To 0 Step -1 Call CopyMemory(bOut(0, i), bData(lngPos + 1), lngBPL) lngPos = lngPos + lngBPL + 1 Next i ReDim bData((lngWidth * lngHeight) - 1) Call CopyMemory(bData(0), bOut(0, 0), (lngWidth * lngHeight)) End Sub [/code] | March 22, 2008, 8:11 AM |
warz | it's not like the format to an mng file is secret, or anything. you can quit guessing, and just use google. | March 22, 2008, 10:19 AM |
Ringo | [quote author=betawarz link=topic=17400.msg177169#msg177169 date=1206181157] it's not like the format to an mng file is secret, or anything. you can quit guessing, and just use google. [/quote] Yeah.. Ofc its not a secret, i never said it was :) But i persionaly would rather try figger this stuff out rather than useing google, it makes good practiss and cures bordom. Cant always rely on somthing like google to answer every question you have, what about when it cant answer it? :P Just thought by shareing this, it might help some people with adding MNG support to their bots, is all. | March 22, 2008, 9:35 PM |
ProjecT | [quote author=Ringo link=topic=17400.msg177196#msg177196 date=1206221730] [quote author=betawarz link=topic=17400.msg177169#msg177169 date=1206181157] it's not like the format to an mng file is secret, or anything. you can quit guessing, and just use google. [/quote] Yeah.. Ofc its not a secret, i never said it was :) But i persionaly would rather try figger this stuff out rather than useing google, it makes good practiss and cures bordom. Cant always rely on somthing like google to answer every question you have, what about when it cant answer it? :P Just thought by shareing this, it might help some people with adding MNG support to their bots, is all. [/quote] lol easy, when google cant answer your question then you try to figure it out yourself, if you have any troubles then you ask here :). | March 23, 2008, 4:59 AM |
Ringo | [quote author=AoD-Archangel link=topic=17400.msg177220#msg177220 date=1206248363] lol easy, when google cant answer your question then you try to figure it out yourself, if you have any troubles then you ask here :). [/quote] Well that might be yours and warez way of doing things, but i persionaly like to challenge my self :) I didnt do this so I could load MNG's, nore so I could have mng support in a bot, I did it just to pass the time and challenge my self. As stated above, it makes good practiss. People here probly have more use for this than I will, hence why I posted it. Can we keep on subject, or can a mod trash every reply so far? | March 23, 2008, 7:41 AM |