GIF and LZW

BlitzPlus Forums/BlitzPlus Programming/GIF and LZW

Moore(Posted 2007) [#1]
Ok, I am trying to write a GIF editor. So I need to encode and decode GIF files... I have writen the code below based on a few tutorials I have found. I can open a GIF, read all the headers fine but all I get is static for an image the error is somewhere in the LZW decompression. Can anyone help?

Here are some refferences I found:
http://stars.hybd.net/developer/lzw.php#compression
http://www.w3.org/Graphics/GIF/spec-gif87.txt
http://en.wikipedia.org/wiki/LZW

Type GIF_FILE
	Field w
	Field h
	Field pf
	Field gFlg
	Field cRes
	Field sort
	Field size
	Field gPallet 
	Field frst.GIF_IMG
End Type

Type GIF_IMG
	Field x 
	Field y 
	Field w 
	Field h 
	Field mixed		
	Field lmFlg 	
	Field iFlg 		
	Field lSize 	
	Field imgBank 
	Field img 		
	Field lpallet 	
End Type

Global LZW_rCount
Global LZW_rValue
Global LZW_byteSize
Global LZW_codeSize 
Global LZW_table$[4100]
Global LZW_tIndex


Graphics 800, 600

file = ReadFile(RequestFile("Gif..", "gif", False))
	gf.GIF_FILE = Load_GIFHeader(file) ; 
	While Not Eof(file)
		Select ReadByte(file) ; ............................ search for image discriptor
			Case $2C ; Image	
			gI.GIF_IMG = Load_ImageDescriptor(file)
			If gI\lPallet = 0 Then gI\lPallet = gf\gPallet
			; Clear LZW tables
			For i = 0 To 4099
				LZW_table[i] = ""
			Next
			Stop
			; set code size
			If gI\lmFlg Then 
				LZW_byteSize = gI\lSize
				LZW_codeSize = gI\lSize
			Else
				LZW_byteSize = gF\size
				LZW_codeSize = gF\size
			EndIf
			
			First_Code = get_codeChr(file)
			PokeByte  gI\imgBank, imgIndex, First_Code
			imgIndex = imgIndex + 1
			
			While True 
 				next_code = get_codeChr(file)
				
 				If Codeword = (2 ^ LZW_codeSize) Then; clear code
  					; Clear LZW tables
					For i = 0 To 4099
						LZW_table[i] = ""
					Next
					Stop
					LZW_byteSize = LZW_codeSize
					First_Code = get_codeChr(file)
				ElseIf CodeWord = (2 ^ LZW_codeSize) + 1 Then; end of image
   					Stop
					Exit
				Else
     				inTable = True
					If next_code > 255 Then
						If LZW_table[next_code - 256] = "" Then inTable = False
					EndIf
					
					If Not inTable Then 
					;If Next_Code is Not in the String table Then
						String_buffer$ = get_codeWord(First_code) + Mid(get_codeWord(First_code), 1,1)
						;String_Buffer = translated First_code + 
    					;First byte of First_Code
					Else
						; String_Buffer = Translation of Next_Code
						String_buffer = get_codeWord(Next_code)
						; add translated First_code + First byte of First_Code to the table 
						If LZW_tIndex < 4095 Then
							LZW_table[LZW_tIndex] = get_codeWord(First_code) + Mid(get_codeWord(First_code), 1,1)
							LZW_tIndex = LZW_tIndex + 1
						EndIf
						
						First_Code = Next_Code
						; display String_Buffer
						For i = 1 To Len(String_buffer)
							PokeByte gI\imgBank, imgIndex, Asc(Mid(String_Buffer, i, 1))
							imgIndex = imgIndex + 1
							If imgIndex = gI\w * gI\h Then Goto done
						Next
					EndIf 
  				EndIf
				
				If next_code = (LZW_byteSize ^2) -1  And LZW_byteSize < 12 Then 
					LZW_byteSize = LZW_ByteSize + 1 
				EndIf
			Wend
		End Select 
		.done
		render_palletedImg(gI\lPallet, gI\imgBank, gI\img)
		SetBuffer BackBuffer()
		Cls
			DrawBlock gI\img, 100, 100
		Flip		
		WaitKey()
	Wend
	
Function get_codeWord$(codeChr)
	If codeChr < 256 Then 
		Return Chr(codeChr)
	ElseIf codeChr > 4095 Then
		RuntimeError "Code Character exceeds the 12 bit limit"
	Else
		Return LZW_table[codeChr - 256] 
	EndIf
End Function

Function Load_ImageDescriptor.GIF_IMG(file)
	x = ReadShort(file)
	y = ReadShort(file)
	w = ReadShort(file)
	h = ReadShort(file)
	mixed = ReadByte(file)
	
	lmFlg = mixed Shr 7 				; local map flag
	iFlg = (mixed And 64) Shr 6 		; interlaced image flag
	lSize = (pf And 7) + 1	 			; bits per pixel
	imgBank = CreateBank(w * h)			; buffer to hold img indexes
	img = CreateImage(w, h)
			
	; load local pallet if one exists
	If lmFlg Then
		lpallet = CreateBank(3 * (2 ^ lSize))
		For i = 0 To lSize - 1
			PokeByte lpallet, i, ReadByte(file)
		Next	
	EndIf
	
	; Create data type
	g.GIF_IMG = New GIF_IMG
	g\x = x
	g\y = y
	g\w = w
	g\h = h
	g\mixed		= mixed
	g\lmFlg 	= lmFlg
	g\iFlg 		= iFlg
	g\lSize 	= lSize
	g\imgBank   = imgBank
	g\img 		= img
	g\lpallet 	= lpallet
	Return g
End Function	
	
Function Load_GIFHeader.GIF_FILE(file)
	; Read Header
	For i = 1 To 6						; read 6byte signature
		sig$ = sig + Chr(ReadByte(file))
	Next
	sig = Lower(sig)
	If Instr(sig, "gif") = 0 Then
		CloseFile file
		Return Null
	EndIf
		
	w = ReadShort(file) 				; image width
	h = ReadShort(file) 				; image height
	pf = ReadByte(file)					; packed field
	bg = ReadByte(file) 				; background color
	pa = ReadByte(file) 				; pixel aspect ratio
	
	; Unpack packed field
	gFlg = pf Shr 7						; global color pallet flag
	cRes = ((pf And 112) Shr 4) + 1		; color resolution
	sort = (pf And 8) Shr 3				;
	size = ((pf And 7) + 1)			 	; global pallet size in bytes 
	
	; Read global pallet each color is made of 3 bytes for red, green and blue
	If gFlg Then 
		gPallet = CreateBank(3 * (2 ^ size))
		For i = 0 To  (3 * (2 ^ size))- 1
			PokeByte gPallet, i, ReadByte(file)
		Next
	EndIf
	
	; Create Type
	g.GIF_FILE = New GIF_FILE
	g\w = w
	g\h = h
	g\pf = pf
	g\gFlg = gFlg
	g\cRes = cRes
	g\sort = sort
	g\size = size
	g\gPallet = gPallet
	Return g
End Function


Function get_codeChr(file)
	While LZW_rCount < LZW_byteSize ; keep reading bytes from file till you have enough bits
		nByte = ReadByte(file)	; read the next byte
		LZW_rCount = LZW_rCount + 8 ; increment bit count by 8 (8 bits per byte)
		LZW_rvalue = (LZW_rValue Shl 8) Or nByte
	Wend
	

	
	r = (LZW_rCount - LZW_byteSize)
	For i = 0 To r
		rMask = rMask + (2 ^ i)
	Next
	For i = 0 To (32 - r)
		rvMask = rvMask + (2 ^ i)
	Next 
	rvMask = rvMask Shl r
	
	chrCode = (LZW_rValue And rMask) Shr r
	LZW_rValue = LZW_rValue And rvMask
	
	If chrCode = (2 ^ LZW_byteSize) Then LZW_byteSize = LZW_byteSize + 1
	LZW_rCount = LZW_rCount - LZW_byteSize
	Return chrCode
End Function

Function render_palletedImg(pallet, bank, img)
	w = ImageWidth(img)
	h = ImageHeight(img)
	pSize = BankSize(pallet)
	bSize = BankSize (bank)
	LockBuffer ImageBuffer(img)
	For y = 0 To h - 1
		For x = 0 To w - 1
			ci = PeekByte(bank, bOffset) * 3
			r = PeekByte(pallet, ci)
			g = PeekByte(pallet, ci + 1)
			b = PeekByte(pallet, ci + 2)
			WritePixelFast x, y, return_Color(r, g, b, 255), ImageBuffer(img)
			bOffset = bOffset + 1	
		Next
	Next
	UnlockBuffer ImageBuffer(img)
	Return img
End Function

Function return_Color(r, g, b, a)
	colour = b + (g Shl 8) + (r Shl 16) + (a Shl 24)
	Return colour
End Function



markcw(Posted 2008) [#2]
Well I don't know about encoding gif but I converted some C to PB a while ago and have translated it to b+/b3d.

http://www.blitzbasic.com/codearcs/codearcs.php?code=2207

How did you get on with your code?


Vic 3 Babes(Posted 2008) [#3]
I can't say what's wrong with the code - but thanks for posting the links - I've wanted to do this myself for some time. I'll get back to you if I figure anything out.