GIF handling in Blitzmax?

BlitzMax Forums/BlitzMax Beginners Area/GIF handling in Blitzmax?

Hey,
I'm new to BlitzMax and tried a few things out today. I'm really keen on getting more knowledge because BlitzMax is a wonderful language. But now there's a problem: I can't load GIF graphics / display them.

----------------------------------------
Here's the code:
----------------------------------------
SuperStrict
Graphics 320, 240, 0

IncBin "images/sample.gif"
Local myGif:TImage = LoadImage("incbin::images/sample.gif")

While not KeyHit(KEY_ESCAPE)
Cls
DrawImage myGif, 10, 10
Flip
Wend
----------------------------------------


So what's wrong?

Thanks in advance

There's no GIF support in Bmax

it support png and bmp.
in case you don't know, you can save your image into a png or a bmp image with microsoft paint program. Just load it in to the paint program and use "save as" and choose the format in the save as type.

Gif is an aweful image format anyway, unless its a photograph, png is your friend

Import - BMP, JPG, PNG and TGA
Export - PNG and JPG

PNG was designed to succeed GIF and does pretty much everything better, except animation frames.

I think this answeres my question...

So in order to get a full animation I'll need an animation-sprite-strip and load it with LoadAnimImage() ?

yep

I'm not quite ready but there should be gif support added to the axe modules shortly. Here is the reader in it's current state, use LoadImage(pixmap) with the pixmap result in my test code if you want to play with it:

' readgif.bmx

Strict

Global CODEMASK[]=[0,$0001,$0003,$0007,$000F,$001F,$003F,$007F,$00FF,$01FF,$03FF,$07FF,$0FFF]

Const MAXCODES=4096

Const HASALPHA=1

Global stack:Short[MAXCODES]
Global suffix:Short[MAXCODES]
Global prefix:Short[MAXCODES]

Global lzhbuffer:Byte[256]
Global bbptr,bits,bytes,bval

rem

'this is my testcode...

Local stream:TStream
Local pixmaps:TList
Local pix:TPixmap
stream=ReadFile("tweety.gif")
'stream=ReadFile("acidsoftware.gif")
'stream=ReadFile("grid.gif")
pixmaps=ReadGifPixmaps(stream)
pix=TPixmap(pixmaps.valueatindex(0))
SavePixmapPNG pix,"testpng.png"

endrem

Function ReadGifPixmaps:TList(stream:TStream)
	Local pixmaps:TList=New TList
	Local pix:TPixmap
	Local pal:Int Ptr
	Local bgcol
	Local aspect
	Local i,r,g,b,w,h,f,n,t
	Local _delay,_start,_end,_loop,_flags

	Local hdr:Byte[6]

	If stream.Read(hdr,6)<>6 Return
	If hdr[0]<>Asc("G") Or hdr[1]<>Asc("I") Or hdr[2]<>Asc("F") Return
' 89A	
	Print hdr[3]+Chr(hdr[3])
	Print hdr[4]+Chr(hdr[4])
	Print hdr[5]+Chr(hdr[5])
	w=stream.ReadShort()
	h=stream.ReadShort()
	f=stream.ReadByte()
	bgcol=stream.ReadByte()
	aspect=stream.ReadByte()
	If f&128
		n=2Shl(f&7)
		pal=New Int[n]
		For i=0 Until n
			r=stream.ReadByte()
			g=stream.ReadByte()
			b=stream.ReadByte()
			pal[i]=$ff000000|(r Shl 16)|(g Shl 8)|(b)
		Next
	EndIf
	_delay=-1
	While True
		n=stream.ReadByte()
		Select n
		Case -1
			Return pixmaps
		Case $2c
			parsegif(pixmaps,stream,pal,0)
			DebugLog "gif $2c complete pixmaps.count()="+pixmaps.count()
			Return pixmaps		
'			DebugStop
		Case $21
			n=stream.ReadByte()
			Select n
				Case $f9'graphic control block
					n=stream.ReadByte()
					f=stream.ReadByte()
					_delay=stream.ReadShort()
					t=stream.ReadByte()
					If f&1 
						pal[t]:&$ffffff
						_flags=HASALPHA
					EndIf
					stream.seek(stream.pos()+n-4)
					While True
						n=stream.ReadByte()
						If n=0 Exit
						stream.seek(stream.pos()+n)
					Wend
			Default
				n=stream.ReadByte()
				stream.Seek stream.pos()+n
				While True
					n=stream.ReadByte()
					If n=0 Exit
					stream.seek(stream.pos()+n)
				Wend				
			End Select
		End Select
	Wend
End Function

Function lzhread(stream:TStream,currsize)
	Local	i,r
	If bits=0
		If bytes<=0
			bbptr=0
			bytes=stream.readbyte()
			For i=0 Until bytes
				lzhbuffer[i]=stream.ReadByte()
			Next
		EndIf
		bval=lzhbuffer[bbptr]
		bbptr:+1
		bits=8
		bytes:-1
	EndIf
	r=bval Shr(8-bits)
	While bits<currsize
		If bytes<=0
			bbptr=0
			bytes=stream.ReadByte()
			For i=0 Until bytes
				lzhbuffer[i]=Stream.ReadByte()
			Next
		EndIf
		bval=lzhbuffer[bbptr]
		bbptr:+1
		r:|(bval Shl bits)
		bits:+8
		bytes:-1
	Wend
	bits:-currsize
	Return r&CODEMASK[currsize]
End Function

Function parsegif(pixmaps:TList,stream:TStream,pal:Int Ptr,flags,squash=False)
	Local x,y,w,h,f	'i,r,g,b,n
	Local size,csize,topslot,clear
	Local ending,slot,newcodes,avail,bitsleft
	Local c,code,oc,fc,sp,bptr
	Local yinc,lpass
	Local pix:TPixmap

	x=stream.ReadShort()
	y=stream.ReadShort()
	w=stream.ReadShort()
	h=stream.ReadShort()
	f=stream.ReadByte()

	yinc=1
	If (f&64) yinc=8

	DebugLog "createpixmap("+w+","+h+")"
	
	If flags&HASALPHA
		pix=CreatePixmap(w,h,PF_BGRA8888)
	Else
		pix=CreatePixmap(w,h,PF_BGR888)
	EndIf
	pixmaps.addlast pix
'	can->SetHandle(-x,-y)
'	If (squash)
'		can->resize(w,(h+1)>>1,canflags,False)
'	Else
'		can->resize(w,h,canflags,False)
' image data

	size=stream.readbyte()'system.debug("size="+size)
	csize=size+1
	topslot=1 Shl csize
	clear=1 Shl size
	ending=clear+1
	slot=ending+1
	newcodes=ending+1
	bbptr=0
	bits=0
	bytes=0
	bval=0
	
	While True
		c=lzhread(stream,csize)
		If c=ending Exit
		If c=clear
			csize=size+1
			slot=newcodes
			topslot=1 Shl csize
			While True 
				c=lzhread(stream,csize)
				If c<>clear Exit
			Wend
			If c=ending Exit
			If c>=slot c=0
			oc=c
			fc=c
'			If (squash)
'				If ((x&1)=(y&1)) WritePixel(x,y Shr 1,pal[c])
'			Else
				WritePixel(pix,x,y,pal[c])
'			EndIf
			x:+1
			If x=w
				x=0
				y:+yinc
				If y>=h 
					y=4 Shr lpass
					yinc=y*2
					lpass:+1
				EndIf
			EndIf
		Else
			code=c
			If code>=slot
				code=oc		
				stack[sp]=Short(fc)	'simon was here
				sp:+1
			EndIf
			While code>=newcodes
				stack[sp]=suffix[ code]
				sp:+1
				code=prefix[ code]
			Wend
			stack[sp]=Short(code)	'simon was here
			sp:+1
			If slot<topslot
				fc=code
				suffix[slot]=Short(fc)
				prefix[slot]=Short(oc)
				slot:+1
				oc=c
			EndIf	
			If slot>=topslot And csize<12
				topslot=topslot Shl 1
				csize:+1
			EndIf
			While sp>0
				sp:-1
				c=stack[sp]
				If squash
					If (y=h-1) Or (x&1)=(y&1)
						WritePixel(pix,x,y Shr 1,pal[c])
					EndIf
				Else
					WritePixel(pix,x,y,pal[c])
				EndIf
				x:+1
				If x=w 
					x=0
					y:+yinc
					If y>=h
						y=4 Shr lpass
						yinc=y*2
						lpass:+1
					EndIf
				EndIf
			Wend
		EndIf
	Wend
End Function


or try the following untested wrapper:
Function LoadGif:TImage(url:Object)
	Local stream:TStream
	Local pixmaps:TList
	Local pix:TPixmap
	stream=ReadFile(url)
	If stream
		pixmaps=ReadGifPixmaps(stream)
		CloseFile stream
		If pixmaps
			pix=TPixmap(pixmaps.valueatindex(0))
			Return LoadImage(pix)
		EndIf
	EndIf
End Function


saving too?

Interesting enough:

The last patents on the GIF file format expire on october 1st, 2006, making GIF truly 'free' to use again just 2 days from now.

http://www.freesoftwaremagazine.com/node/1772

@skidracer:
Thanks for the code. I haven't tried it out yet, but I will do today. I'll post my success here in this topic.

@xlsior:
Interesting. Could this mean that Mark will include a GIF support within the next Updates of BlitzMax?

I'm not quite ready but there should be gif support added to the axe modules shortly


@skidracer:
Your code works fine. The gif images are displayed correctly but there is just on problem: There is no transparency, instead of this a magenta color is shown.

I guess I can remove the magenta color by setting the mask color, correct? Anyone got a little piece of code for me?

It should already support alpha, if you can, please email me your gif so I can test.

The loader still needs per frame palette support which I can put in soon and there may be a bug with the background color support, will test.

This is the gif picture:


oops change ReadGifPixmaps at ~ line 84 to:

			parsegif(pixmaps,stream,pal,_flags)


yep, that works!
Thank you very much

I'm not quite ready but there should be gif support added to the axe modules shortly.


Hi, sorry for bumping an old thread like this, but might this still happen? I just synched with axe enabled but all I see is a module to load jpg2000.

(Don't worry, I'm not planning on using gif files as game graphics, it's for a program that can load image files from the user, so the more supported formats the better.)

Yeah gif would be nince since it is still in use quite a bit on the web, even though png is in most cases much nicer (then then png is nicer than bmp but we have that too). Anyone want to do an IFF/ILBM loader? I did one in basic a while ago, wasn't too hard.

Hmm...I can't get simon's code to work at all. Anyone have a clear example?

Another option, if you need GIF support... there is always my freeimage module - which supports GIF load and save, as well as conversion to lots of other file formats.

See link for more details...

http://brucey.net/programming/blitz/index.php#bahfreeimage

Even supports loading IFF/ILBM (whatever those are)... ;-)

Brucey, was your smiley there to indicate that you know what ILBM is from (Amiga), or a serious question?

Of note, IFF is the Interchangeable File Format developed by Electronic Arts for Deluxe Paint, but which is meant to be able to store several types of data including audio. It's kind of a flexible file format able to store multiple items - images, sounds, palettes, etc. ILBM is the InterLeaved BitMap which is the format for images that IFF uses.

IFF was probably a bit ahead of its time, as far as having the capability to store information other than images in it.
Clever idea, but sadly under-exploited.