1. GIF loader bug fix
- Posted by Michael Bolin <michaeltom at GEOCITIES.COM>
Apr 04, 1997
-
Last edited Apr 05, 1997
Hi all!
The GIF loader I posted to this list recently contained a bug that
would in rare cases cause it to crash. I have just fixed this, so
here's the new code:
-------------------------------------------
include machine.e
include file.e
global constant PCX_OPEN_FAILED=1,
PCX_UNEXPECTED_EOF=2,
PCX_UNSUPPORTED_FORMAT=3,
GIF_OPEN_FAILED=1,
GIF_UNEXPECTED_EOF=2,
GIF_UNSUPPORTED_FORMAT=3
object junk
sequence image,the_palette,bit_table
integer file_num,exit_flag,palette_at_end
integer x_size,y_size,bits_per_pixel,n_colors
integer background,bytes_per_line,x_min,x_max
integer y_min,y_max,n_planes
bit_table=repeat({},256)
for n=0 to 255 do
bit_table[n+1]=int_to_bits(n,8)
end for
function read_bytes(integer amount)
sequence bytes
bytes=repeat(0,amount)
for b=1 to amount do
bytes[b]=getc(file_num)
if bytes[b]=-1 then
exit_flag=GIF_UNEXPECTED_EOF
end if
end for
return bytes
end function
function bytes_left()
integer place,end_place
place=where(file_num)
if seek(file_num,-1)=0 then
end_place=where(file_num)
if seek(file_num,place)=0 then
return end_place-place
else
return -1
end if
else
return -1
end if
end function
procedure read_pcx_header()
if bytes_left()<128 then
exit_flag=PCX_UNEXPECTED_EOF
return
end if
junk=getc(file_num)
palette_at_end=0
if getc(file_num)=5 then
palette_at_end=1
end if
if getc(file_num)!=1 then
exit_flag=PCX_UNSUPPORTED_FORMAT
return
end if
bits_per_pixel=getc(file_num)
if bits_per_pixel!=1 and bits_per_pixel!=8 then
exit_flag=PCX_UNSUPPORTED_FORMAT
return
end if
x_min=getc(file_num)+getc(file_num)*256
y_min=getc(file_num)+getc(file_num)*256
x_max=getc(file_num)+getc(file_num)*256
y_max=getc(file_num)+getc(file_num)*256
x_size=x_max-x_min+1
y_size=y_max-y_min+1
junk=read_bytes(4)
the_palette={}
if palette_at_end then
junk=read_bytes(48)
else
for c=1 to 16 do
the_palette=append(the_palette,read_bytes(3))
end for
end if
if exit_flag then
return
end if
if getc(file_num) then
exit_flag=PCX_UNSUPPORTED_FORMAT
return
end if
n_planes=getc(file_num)
bytes_per_line=getc(file_num)+getc(file_num)*256
junk=read_bytes(6)
for x=1 to 54 do
junk=getc(file_num)
if junk=-1 then
exit_flag=PCX_UNEXPECTED_EOF
return
elsif junk then
exit_flag=PCX_UNSUPPORTED_FORMAT
return
end if
end for
end procedure
procedure read_pcx_image()
sequence one_row,bits,new_row
integer number,byte,line,count,and_value,place
integer plane_power,amount
image=repeat({},y_size)
one_row=repeat(0,bytes_per_line*n_planes)
line=1
while line<=y_size do
number=1
while number<=length(one_row) do
byte=getc(file_num)
if byte=-1 then
exit_flag=PCX_UNEXPECTED_EOF
return
end if
if byte>191 then
count=byte-193
byte=getc(file_num)
if byte=-1 then
exit_flag=PCX_UNEXPECTED_EOF
return
end if
one_row[number..number+count]=byte
number=number+count+1
else
one_row[number]=byte
number=number+1
end if
end while
if bits_per_pixel=1 then
bits=repeat(0,bytes_per_line*8*n_planes)
place=1
for p=0 to n_planes-1 do
plane_power=power(2,p)
for t=1 to bytes_per_line do
byte=one_row[p*bytes_per_line+t]
and_value=256
for z=1 to 8 do
and_value=and_value/2
if and_bits(byte,and_value) then
bits[place]=plane_power
end if
place=place+1
end for
end for
end for
amount=bytes_per_line*8
new_row=bits[1..amount]
for p=1 to n_planes-1 do
new_row=new_row+bits[amount*p+1..amount*(p+1)]
end for
if length(new_row)>x_size then
new_row=new_row[1..x_size]
end if
else
new_row=one_row
end if
image[line]=new_row
line=line+1
end while
if palette_at_end then
junk=getc(file_num)
for c=1 to 256 do
the_palette=append(the_palette,read_bytes(3))
if find(-1,the_palette[c]) then
exit_flag=PCX_UNEXPECTED_EOF
return
end if
end for
end if
end procedure
procedure read_gif_header()
object work
sequence stuff,bits
integer global_color_map
if bytes_left()<6 then
exit_flag=GIF_UNEXPECTED_EOF
return
end if
stuff=read_bytes(3)
if compare(stuff,"GIF") and compare(stuff,"GIF") then
exit_flag=GIF_UNSUPPORTED_FORMAT
return
end if
junk=read_bytes(3)
if bytes_left()<7 then
exit_flag=GIF_UNEXPECTED_EOF
return
end if
junk=read_bytes(4)
bits=bit_table[getc(file_num)+1]
global_color_map=bits[8]
bits_per_pixel=bits_to_int(bits[1..3])+1
n_colors=power(2,bits_per_pixel)
background=getc(file_num)
junk=getc(file_num)
the_palette={}
if global_color_map then
if bytes_left()<n_colors*3 then
exit_flag=GIF_UNEXPECTED_EOF
return
end if
for c=1 to n_colors do
the_palette=append(the_palette,read_bytes(3))
end for
end if
while 1 do
work=getc(file_num)
if work=-1 then
exit_flag=GIF_UNEXPECTED_EOF
return
elsif work=',' then
exit
end if
end while
end procedure
procedure read_gif_image()
object work
sequence strings,bits,output,work_bits,string,stream
integer interlace,code_size,clear_code,end_of_info
integer num_bits,code,old,done,pointer,block_length
integer bit_add
if bytes_left()<9 then
exit_flag=GIF_UNEXPECTED_EOF
return
end if
junk=read_bytes(4)
x_size=getc(file_num)+getc(file_num)*256
y_size=getc(file_num)+getc(file_num)*256
work=getc(file_num)
bits=bit_table[work+1]
if bits[8] then
bits_per_pixel=bits_to_int(bits[1..3])+1
n_colors=power(2,bits_per_pixel)
the_palette={}
for c=1 to n_colors do
the_palette=append(the_palette,read_bytes(3))
end for
if exit_flag then
return
end if
end if
interlace=bits[7]
image=repeat({},y_size)
output={}
if n_colors=2 then
n_colors=4
end if
strings=repeat({},n_colors+2)
for t=1 to n_colors do
strings[t]={t-1}
end for
code_size=getc(file_num)
if code_size=-1 then
exit_flag=GIF_UNEXPECTED_EOF
return
end if
clear_code=power(2,code_size)+1
end_of_info=clear_code+1
num_bits=code_size+1
stream={}
while 1 do
block_length=getc(file_num)
if block_length=0 then
exit
end if
for b=1 to block_length do
stream=append(stream,getc(file_num))
end for
end while
if find(-1,stream) then
exit_flag=GIF_UNEXPECTED_EOF
return
end if
stream=append(stream,0)
stream=append(stream,-1)
pointer=1
bits={}
while length(bits)<26 do
bits=bits & bit_table[stream[pointer]+1]
pointer=pointer+1
end while
bits=bits[num_bits+1..length(bits)]
work_bits=bits[1..num_bits]
code=bits_to_int(work_bits)+1
output=strings[code]
old=code
bits=bits[num_bits+1..length(bits)]
done=0
while 1 do
while length(bits)<26 and done=0 do
work=stream[pointer]
pointer=pointer+1
if work=-1 then
done=1
exit
end if
bits=bits & bit_table[work+1]
end while
if length(bits)<num_bits then
exit
end if
code=1
bit_add=1
for b=1 to num_bits do
if bits[b] then
code=code+bit_add
end if
bit_add=bit_add+bit_add
end for
bits=bits[num_bits+1..length(bits)]
if code=end_of_info then
exit
elsif code=clear_code then
strings=repeat({},n_colors+2)
for t=1 to n_colors do
strings[t]={t-1}
end for
num_bits=code_size+1
work_bits=bits[1..num_bits]
code=bits_to_int(work_bits)+1
for t=1 to length(strings[code]) do
output=append(output,strings[code][t])
end for
old=code
bits=bits[num_bits+1..length(bits)]
else
if code<=length(strings) then
string=strings[code]
for t=1 to length(string) do
output=append(output,string[t])
end for
work=strings[old] & string[1]
strings=append(strings,work)
old=code
else
work=strings[old] & strings[old][1]
for t=1 to length(work) do
output=append(output,work[t])
end for
strings=append(strings,work)
old=code
end if
end if
if length(strings)=power(2,num_bits) then
num_bits=num_bits+1
if num_bits=13 then
num_bits=12
end if
end if
end while
work=repeat({},y_size)
for r=0 to y_size-1 do
work[r+1]=output[r*x_size+1..r*x_size+x_size]
end for
if interlace then
image=repeat({},y_size)
pointer=1
for l=1 to y_size by 8 do
image[l]=work[pointer]
pointer=pointer+1
end for
for l=5 to y_size by 8 do
image[l]=work[pointer]
pointer=pointer+1
end for
for l=3 to y_size by 4 do
image[l]=work[pointer]
pointer=pointer+1
end for
for l=2 to y_size by 2 do
image[l]=work[pointer]
pointer=pointer+1
end for
else
image=work
end if
end procedure
global function read_pcx(sequence filename)
exit_flag=0
file_num=open(filename,"rb")
if file_num<0 then
return PCX_OPEN_FAILED
end if
read_pcx_header()
if exit_flag then
close(file_num)
return exit_flag
end if
read_pcx_image()
close(file_num)
if exit_flag then
return exit_flag
end if
the_palette=the_palette[1..power(2,bits_per_pixel*n_planes)]
return {the_palette,image}
end function
global function read_gif(sequence file_name)
exit_flag=0
file_num=open(file_name,"rb")
if file_num<0 then
return GIF_OPEN_FAILED
end if
read_gif_header()
if exit_flag then
close(file_num)
return exit_flag
end if
read_gif_image()
close(file_num)
if exit_flag then
return exit_flag
end if
return {the_palette,image}
end function
-------------------------------------------
Regards,
Michael Bolin
2. Re: GIF loader bug fix
> Hi all!
>
> The GIF loader I posted to this list recently contained a bug that
> would in rare cases cause it to crash. I have just fixed this, so
> here's the new code:
(eagerly snippity-snip-snip-snipping :) )
> Regards,
> Michael Bolin
Michael, I ran a few test runs with your fixxed source and it works great.
Thank you! With your permission, I would like to use it in "A Beginner's
Guide To Euphoria 2.00", as it would allow me to load GIFs instead of BMPs.
This would lighten my load in picture files by about 70%. I'll be sure to
put credit for your work in the documentation.
Thanks
David Gay
http://www.interlog.com/~moggie/Euphoria
"A Beginner's Guide To Euphoria"
3. Re: GIF loader bug fix
- Posted by Michael Bolin <michaeltom at GEOCITIES.COM>
Apr 05, 1997
-
Last edited Apr 06, 1997
> Michael, I ran a few test runs with your fixxed source and it works great.
> Thank you! With your permission, I would like to use it in "A Beginner's
> Guide To Euphoria 2.00", as it would allow me to load GIFs instead of BMPs.
> This would lighten my load in picture files by about 70%. I'll be sure to
> put credit for your work in the documentation.
Sure thing!
It's meant to be free anyway :)
Regards,
Michael Bolin