basic JPEG decoder- and encoder

Post your FreeBASIC source, examples, tips and tricks here. Please don’t post code without including an explanation.
Post Reply
DamageX
Posts: 130
Joined: Nov 21, 2009 8:42

basic JPEG decoder- and encoder

Post by DamageX »

handles baseline, 8-bit component (grayscale or YCbCr), sequential scan only

Code: Select all

#lang "fblite"
option gosub
option explicit

dim shared as ushort rstint,s
dim shared as ubyte a,r,g,b,cnum,sambits,bbits,bcom,dbuf,ybh,ybv
dim shared as integer x,y,z,ff1,h,v,l,xx,yy,zz,bh,bv,m,i0,i1,i2,c0,c1,c2
dim shared as integer bbytes,bho,bvo,blksdone
dim shared as single z1,z2,z3,pi
dim shared cr(1 to 4) as ubyte
dim shared cq(1 to 4) as ubyte
dim shared ced(1 to 8) as ubyte
dim shared olddc(1 to 4) as short
dim shared qtable(0 to 3,0 to 63) as ubyte
dim shared htl(0 to 7,0 to 15) as ubyte
dim shared htable(0 to 7,0 to 2047) as ubyte
dim shared hcode(0 to 7,0 to 2047) as ushort
dim shared blk(0 to 79) as short
dim shared blk2(0 to 63) as short
dim shared blk3(0 to 63) as single
dim shared blk4(1 to 6,0 to 63) as ubyte
dim shared filebuf(0 to 4095) as ubyte

dim shared zigzag(0 to 63) as ubyte => _
{ 0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5, _
  12,19,26,33,40,48,41,34,27,20,13,6,7,14,21,28, _
  35,42,49,56,57,50,43,36,29,22,15,23,30,37,44,51, _
  58,59,52,45,38,31,39,46,53,60,61,54,47,55,62,63 }

dim shared itable(0 to 4095) as single

pi=3.1415926

' build a lookup table to speed up iDCT later
zz=0
for y=0 to 7
for x=0 to 7
z1=1
if x=0 then z1=z1*.707107
if y=0 then z1=z1*.707107
for yy=0 to 7
for xx=0 to 7
itable(zz)=z1*cos(pi*x*((xx*2)+1)/16)*cos(pi*y*((yy*2)+1)/16)
zz+=1
next xx
next yy
next x
next y


? command$

ff1=freefile
open command$ for binary as #ff1


startparse:

get #ff1,,s

if s=&HD8FF then goto startparse     'start marker
if s=&HD9FF then sleep:end                 'end of image
if s=&HC2FF then ? "progressive mode not supported":sleep:end

if s=&HDDFF then                  'restart interval
get #ff1,,a:x=a:get #ff1,,a:x=(x shl 8)+a       ' header length
get #ff1,,a:rstint=a:get #ff1,,a:rstint=(rstint shl 8)+a
goto startparse
end if

if s=&HDBFF then                     'quantization table
get #ff1,,a:x=a:get #ff1,,a:x=(x shl 8)+a       ' header length
a209:
get #ff1,,a:b=(a and 15)        ' table number
        ' (bit 4 indicates 16-bit table, but only 8-bit is supported)
for y=0 to 63
get #ff1,,qtable(b,y)           ' quantization values in zigzag order
next y
if x>67 then x=x-65:goto a209
goto startparse
end if

if s=&HC4FF then                     'huffman table
get #ff1,,a:x=a:get #ff1,,a:x=(x shl 8)+a       ' header length
a208:
get #ff1,,a:b=(a and 15)        ' table number
if (a and 16) then b+=4
for y=0 to 15:get #ff1,,htl(b,y):next y
zz=0
for y=0 to 15
for z=0 to htl(b,y)-1
get #ff1,,htable(b,zz):zz+=1
next z
next y
' build huffman code table
xx=0:zz=0
for y=0 to 15
for z=0 to htl(b,y)-1
hcode(b,zz)=xx:zz+=1:xx+=1
next z
xx+=xx
next y
if x>zz+19 then x=x-zz-17:goto a208
goto startparse
end if

if s=&HC0FF then                     'baseline DCT JPEG header
get #ff1,,a:x=a:get #ff1,,a:x=(x shl 8)+a       ' header length
get #ff1,,sambits       ' bits per sample
get #ff1,,a:v=a:get #ff1,,a:v=(v shl 8)+a       ' number of lines
get #ff1,,a:h=a:get #ff1,,a:h=(h shl 8)+a       ' number of pixels/line
get #ff1,,cnum          ' number of components
for y=0 to cnum-1
get #ff1,,a             ' component identifier
get #ff1,,cr(a)         ' component resolution (h is the high nibble)
get #ff1,,cq(a)         ' quantization table selection
next y
goto startparse
end if

if s=&HDAFF then                     'start of scan           
get #ff1,,a:x=a:get #ff1,,a:x=(x shl 8)+a       ' header length
get #ff1,,a             ' number of components in scan
for y=0 to a-1
get #ff1,,b             ' component identifier
get #ff1,,g
ced(b)=(g shr 4)        ' DC entropy coding huffman table
ced(b+4)=(g and 15)+4     ' AC entropy coding huffman table
next y
get #ff1,,a             ' start of spectral selection (?)
get #ff1,,a             ' end of spectral selection (?)
get #ff1,,a             ' approximation bit positions (?)

' start decompressing and display data

screen 19,32

bbits=0:bbytes=4096:blksdone=0

ybh=(cr(1) shr 4):ybv=(cr(1) and 15)

for bv=0 to v-1 step ybv*8
for bh=0 to h-1 step ybh*8

for dbuf=1 to ybh*ybv
bcom=1
gosub decodeblk
next dbuf

if cnum=1 then
for y=0 to 7
for x=0 to 7
pset (x+bh,y+bv),blk4(1,x+(y shl 3))*&H10101
next x
next y
goto a207
end if

bcom=2:dbuf=5
gosub decodeblk
bcom=3:dbuf=6
gosub decodeblk

dbuf=0
for yy=1 to ybv
for xx=1 to ybh
dbuf+=1
bvo=((yy-1) shl 3)+bv
bho=((xx-1) shl 3)+bh
for y=0 to 7
for x=0 to 7
i0=blk4(dbuf,x+(y shl 3))

if ybh=1 then
z=x
else
z=(x shr 1)+((xx-1) shl 2)
end if
if ybv=1 then
z+=(y shl 3)
else
z+=(((y shr 1)+((yy-1) shl 2)) shl 3)
end if

i1=blk4(5,z)-128
i2=blk4(6,z)-128

' convert to RGB
c0=1.402*i2+i0
c1=i0-.34414*i1-.71414*i2
c2=1.772*i1+i0

if c0<0 then c0=0
if c0>255 then c0=255
if c1<0 then c1=0
if c1>255 then c1=255
if c2<0 then c2=0
if c2>255 then c2=255

pset (x+bho,y+bvo),(c0 shl 16)+(c1 shl 8)+c2
next x
next y
next xx
next yy

a207:
if inkey$="q" then end

blksdone+=1
if blksdone=rstint then
blksdone=0:bbits=0:bbytes+=2
for y=1 to 4:olddc(y)=0:next y
end if

next bh
next bv
sleep
end
end if

if (s and 255)<>255 then ? "error: unexpected data":sleep:end

skipchunk:
get #ff1,,a:x=a:get #ff1,,a:x=(x shl 8)+a
for y=3 to x:get #ff1,,a:next y
goto startparse


decodeblk:

' get DC coefficient
gosub readcode

blk(0)=olddc(bcom)+m:olddc(bcom)=blk(0)

' get AC coefficients
bcom+=4:z=1

a206:
gosub readcode

if x=0 then for y=z to 63:blk(y)=0:next y:goto a205
for y=1 to (x shr 4):blk(z)=0:z+=1:next y
blk(z)=m:z+=1
if z<64 then goto a206
a205:

bcom=bcom-4

' dequantize and un-zigzag
for x=0 to 63
blk2(zigzag(x))=blk(x)*qtable(cq(bcom),x)
next x

clear blk3(0),0,256

' iDCT
for y=0 to 63

z1=blk2(y)

if z1<>0 then
yy=(y shl 6)
for xx=0 to 63
blk3(xx)+=z1*itable(yy+xx)
next xx
end if

next y

' normalize
for x=0 to 63
y=blk3(x)+512
if y>1020 then y=1020
if y<0 then y=0
blk4(dbuf,x)=(y shr 2)
next x

return


readbit:
if bbits=0 then
if bbytes>4095 then get #ff1,,filebuf():bbytes=bbytes-4096
a=filebuf(bbytes):bbits=8:bbytes+=1
if a=255 then bbytes+=1
end if
xx+=xx+(a shr 7)
a+=a:bbits=bbits-1
return


readcode:
xx=0:yy=0:zz=0
a200:
gosub readbit
y=htl(ced(bcom),yy)
for x=1 to y
if hcode(ced(bcom),zz)=xx then goto a201
zz+=1
next x
yy+=1:if yy=16 then ? "decode error":sleep:end
goto a200
a201:
x=htable(ced(bcom),zz)
m=0
if (x and 15)>0 then
gosub readbit
m=-2:if (xx and 1) then m=1
xx=0:for y=2 to (x and 15):gosub readbit:m+=m:next y
if m<0 then m+=1
m+=xx
end if
return
Last edited by DamageX on Jan 25, 2016 5:18, edited 1 time in total.
DamageX
Posts: 130
Joined: Nov 21, 2009 8:42

Re: basic JPEG decoder

Post by DamageX »

changed the decoder portion to use only integer math and combined multiple steps together for efficiency

Code: Select all

#lang "fblite"
option gosub
option explicit

dim shared as ushort rstint,s
dim shared as ubyte a,r,g,b,cnum,sambits,bbits,bcom,dbuf,ybh,ybv
dim shared as integer x,y,z,ff1,h,v,l,xx,yy,zz,bh,bv,m,i0,i1,i2,c0,c1,c2
dim shared as integer bbytes,bho,bvo,blksdone
dim shared as single z1,z2,z3,pi
dim shared cr(1 to 4) as ubyte
dim shared cq(1 to 4) as ubyte
dim shared ced(1 to 8) as ubyte
dim shared olddc(1 to 4) as short
dim shared qtable(0 to 3,0 to 63) as ubyte
dim shared htl(0 to 7,0 to 15) as ubyte
dim shared htable(0 to 7,0 to 2047) as ubyte
dim shared hcode(0 to 7,0 to 2047) as ushort
dim shared blk4(1 to 6,0 to 63) as integer
dim shared filebuf(0 to 4095) as ubyte

dim shared zigzag(0 to 79) as ubyte => _
{ 0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5, _
  12,19,26,33,40,48,41,34,27,20,13,6,7,14,21,28, _
  35,42,49,56,57,50,43,36,29,22,15,23,30,37,44,51, _
  58,59,52,45,38,31,39,46,53,60,61,54,47,55,62,63, _
  63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63 }

dim shared itable(0 to 4095) as integer

pi=3.1415926

' build a lookup table to speed up iDCT later
zz=0
for y=0 to 7
for x=0 to 7
z1=1
if x=0 then z1=z1*.707107
if y=0 then z1=z1*.707107
for yy=0 to 7
for xx=0 to 7
z2=z1*cos(pi*x*((xx*2)+1)/16)*cos(pi*y*((yy*2)+1)/16)
itable(zz)=(z2*65536)
zz+=1
next xx
next yy
next x
next y


? command$

ff1=freefile
open command$ for binary as #ff1


startparse:

get #ff1,,s

if s=&HD8FF then goto startparse     'start marker
if s=&HD9FF then sleep:end                 'end of image
if s=&HC2FF then ? "progressive mode not supported":sleep:end

if s=&HDDFF then                  'restart interval
get #ff1,,a:x=a:get #ff1,,a:x=(x shl 8)+a       ' header length
get #ff1,,a:rstint=a:get #ff1,,a:rstint=(rstint shl 8)+a
goto startparse
end if

if s=&HDBFF then                     'quantization table
get #ff1,,a:x=a:get #ff1,,a:x=(x shl 8)+a       ' header length
a209:
get #ff1,,a:b=(a and 15)        ' table number
        ' (bit 4 indicates 16-bit table, but only 8-bit is supported)
for y=0 to 63
get #ff1,,qtable(b,y)           ' quantization values in zigzag order
next y
if x>67 then x=x-65:goto a209
goto startparse
end if

if s=&HC4FF then                     'huffman table
get #ff1,,a:x=a:get #ff1,,a:x=(x shl 8)+a       ' header length
a208:
get #ff1,,a:b=(a and 15)        ' table number
if (a and 16) then b+=4
for y=0 to 15:get #ff1,,htl(b,y):next y
zz=0
for y=0 to 15
for z=0 to htl(b,y)-1
get #ff1,,htable(b,zz):zz+=1
next z
next y
' build huffman code table
xx=0:zz=0
for y=0 to 15
for z=0 to htl(b,y)-1
hcode(b,zz)=xx:zz+=1:xx+=1
next z
xx+=xx
next y
if x>zz+19 then x=x-zz-17:goto a208
goto startparse
end if

if s=&HC0FF then                     'baseline DCT JPEG header
get #ff1,,a:x=a:get #ff1,,a:x=(x shl 8)+a       ' header length
get #ff1,,sambits       ' bits per sample
get #ff1,,a:v=a:get #ff1,,a:v=(v shl 8)+a       ' number of lines
get #ff1,,a:h=a:get #ff1,,a:h=(h shl 8)+a       ' number of pixels/line
get #ff1,,cnum          ' number of components
for y=0 to cnum-1
get #ff1,,a             ' component identifier
get #ff1,,cr(a)         ' component resolution (h is the high nibble)
get #ff1,,cq(a)         ' quantization table selection
next y
goto startparse
end if

if s=&HDAFF then                     'start of scan           
get #ff1,,a:x=a:get #ff1,,a:x=(x shl 8)+a       ' header length
get #ff1,,a             ' number of components in scan
for y=0 to a-1
get #ff1,,b             ' component identifier
get #ff1,,g
ced(b)=(g shr 4)        ' DC entropy coding huffman table
ced(b+4)=(g and 15)+4     ' AC entropy coding huffman table
next y
get #ff1,,a             ' start of spectral selection (?)
get #ff1,,a             ' end of spectral selection (?)
get #ff1,,a             ' approximation bit positions (?)

' start decompressing and display data

screen 19,32

bbits=0:bbytes=4096:blksdone=0

ybh=(cr(1) shr 4):ybv=(cr(1) and 15)

'screenlock
for bv=0 to v-1 step ybv*8
for bh=0 to h-1 step ybh*8

for dbuf=1 to ybh*ybv
bcom=1
gosub decodeblk
next dbuf

if cnum=1 then
for y=0 to 7
for x=0 to 7
pset (x+bh,y+bv),((blk4(1,x+(y shl 3)) shr 18)+128)*&H10101
next x
next y
goto a207
end if

bcom=2:dbuf=5
gosub decodeblk
bcom=3:dbuf=6
gosub decodeblk

dbuf=0
for yy=1 to ybv
for xx=1 to ybh
dbuf+=1
bvo=((yy-1) shl 3)+bv
bho=((xx-1) shl 3)+bh
for y=0 to 7
for x=0 to 7
i0=(blk4(dbuf,x+(y shl 3)) shr 18)+128

if ybh=1 then
z=x
else
z=(x shr 1)+((xx-1) shl 2)
end if
if ybv=1 then
z+=(y shl 3)
else
z+=(((y shr 1)+((yy-1) shl 2)) shl 3)
end if

i1=(blk4(5,z) shr 18)
i2=(blk4(6,z) shr 18)

' convert to RGB
c0=1.402*i2+i0
c1=i0-.34414*i1-.71414*i2
c2=1.772*i1+i0

if c0<0 then c0=0
if c0>255 then c0=255
if c1<0 then c1=0
if c1>255 then c1=255
if c2<0 then c2=0
if c2>255 then c2=255

pset (x+bho,y+bvo),(c0 shl 16)+(c1 shl 8)+c2
'pset ((x+bho)\2,(y+bvo)\2),(c0 shl 16)+(c1 shl 8)+c2
next x
next y
next xx
next yy

a207:
if inkey$="q" then end

blksdone+=1
if blksdone=rstint then
blksdone=0:bbits=0:bbytes+=2
for y=1 to 4:olddc(y)=0:next y
end if

next bh
next bv
'screenunlock
sleep
end
end if

if (s and 255)<>255 then ? "error: unexpected data":sleep:end

skipchunk:
get #ff1,,a:x=a:get #ff1,,a:x=(x shl 8)+a
for y=3 to x:get #ff1,,a:next y
goto startparse


decodeblk:

' get DC coefficient
gosub readcode

olddc(bcom)+=m

m=olddc(bcom)*qtable(cq(bcom),0)*itable(0)
for y=0 to 63
blk4(dbuf,y)=m
next y


' get AC coefficients
bcom+=4:z=1

a206:
gosub readcode

if x=0 then goto a205
z+=(x shr 4)

m=m*qtable(cq(bcom+4),z)
i0=(zigzag(z) shl 6)
z+=1
for y=0 to 63
blk4(dbuf,y)+=m*itable(y+i0)
next y

if z<64 then goto a206
a205:

return


readbit:
if bbits=0 then
if bbytes>4095 then get #ff1,,filebuf():bbytes=bbytes-4096
a=filebuf(bbytes):bbits=8:bbytes+=1
if a=255 then bbytes+=1
end if
xx+=xx+(a shr 7)
a+=a:bbits=bbits-1
return


readcode:
xx=0:yy=0:zz=0
a200:
gosub readbit
y=htl(ced(bcom),yy)
for x=1 to y
if hcode(ced(bcom),zz)=xx then goto a201
zz+=1
next x
yy+=1:if yy=16 then ? "decode error":sleep:end
goto a200
a201:
x=htable(ced(bcom),zz)
m=0
if (x and 15)>0 then
gosub readbit
m=-2:if (xx and 1) then m=1
xx=0:for y=2 to (x and 15):gosub readbit:m+=m:next y
if m<0 then m+=1
m+=xx
end if
return
DamageX
Posts: 130
Joined: Nov 21, 2009 8:42

Re: basic JPEG decoder

Post by DamageX »

Here is the encoder. It does two passes which is a bit of a time waster. But it uses the first pass to generate custom huffman tables. It does not do chroma subsampling. It only outputs files with size conforming to 8x8 multiple.

One interesting thing I discovered was that you can't fill the quantization table with arbitrary stuff. For instance, filling it with all 1s does not produce the highest quality file, it actually adds some noise. So I copied somebody else's tables.

Code: Select all

' JPGS filename
' filename.bmp -> filename.jpg

#lang "fblite"
option gosub
option explicit

dim shared as ushort s
dim shared as ubyte a,r,g,b,bbits,bcom,dbuf,tpass,wbits
dim shared as integer x,y,z,ff1,ff2,h,v,l,xx,yy,zz,bh,bv,m,i0,i1,i2
dim shared as integer bbytes,bmp1h,bmp1v
dim shared as single z1,z2,pi
dim shared olddc(1 to 4) as short
dim shared htl(0 to 7,0 to 15) as ubyte
dim shared htable(0 to 7,0 to 2047) as ubyte
dim shared hcode(0 to 7,0 to 2047) as ushort
dim shared hcount(0 to 7,0 to 256) as integer
dim shared hlength(0 to 7,0 to 2047) as ubyte
dim shared blk(0 to 63) as integer
dim shared blk4(1 to 6,0 to 63) as integer
dim shared filebuf(0 to 4095) as ubyte
dim shared pixbuf(0 to 7,0 to 2) as ubyte


dim shared qtable(0 to 1,0 to 63) as ubyte => _
{{ 3,2,2,3,2,2,3,3,3,3,4,3,3,4,5,8,5,5,4,4,5,10,7,7,6,8,12,10,12,12,11,10, _
  11,11,13,14,18,16,13,14,17,14,11,11,16,22,16,17,19,20,21,21,21,12,15,23,24,22,20,24,18,20,21,20 }, _
 { 3,4,4,5,4,5,9,5,5,9,20,13,11,13,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, _
  20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20 }}

dim shared zigzag2(0 to 63) as ubyte => _
{ 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42, _
  3,8,12,17,25,30,41,43,9,11,18,24,31,40,44,53, _
  10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60, _
  21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 }

dim shared itable(0 to 4095) as integer

pi=3.1415926

' build a lookup table to speed up DCT/iDCT later
zz=0
for y=0 to 7
for x=0 to 7
z1=1
if x=0 then z1=z1*.707107
if y=0 then z1=z1*.707107
for yy=0 to 7
for xx=0 to 7
z2=z1*cos(pi*x*((xx*2)+1)/16)*cos(pi*y*((yy*2)+1)/16)
itable(zz)=(z2*65536)
zz+=1
next xx
next yy
next x
next y

dim ki2 as string


' open 24-bit BMP input file

ki2=command$+".bmp"
ff2=freefile
open ki2 for binary as #ff2

x=19:get #ff2,x,bmp1h
x=23:get #ff2,x,bmp1v

' open JPEG output file

ki2=command$+".jpg"
ff1=freefile
open ki2 for binary as #ff1
if lof(ff1)>0 then close #ff1:kill ki2:OPEN ki2 FOR BINARY AS #ff1

' write headers

s=&HD8FF:put #ff1,,s
s=&HE0FF:put #ff1,,s
s=&H1000:put #ff1,,s
s=&H464A:put #ff1,,s:s=&H4649:put #ff1,,s       ' JFIF
s=&H0100:put #ff1,,s:s=&H0101:put #ff1,,s
s=&H6400:put #ff1,,s:s=&H6400:put #ff1,,s       ' 100dpi
s=&H0000:put #ff1,,s

for y=0 to 1
s=&HDBFF:put #ff1,,s:s=&H4300:put #ff1,,s       ' quantization tables
a=y:put #ff1,,a
put #ff1,,qtable(y,0),64
next y


' do a test pass to compile data for building a custom huffman table

? "Pass 1..."
clear hcount(0,0),0,8224
tpass=1:gosub imgenc


' build huffman tables

clear htl(0,0),0,128
clear htable(0,0),0,16384

for i0=0 to 3

' how many symbols?
y=0
for x=0 to 255
if hcount(i0,x)>0 then y+=1
next x

' start assigning codes
zz=hcount(i0,256)
yy=2:xx=0:z=0
a256:
zz=(zz shr 1)
if y>yy then
for x=0 to 255
if hcount(i0,x)>zz then hcount(i0,x)=0:htl(i0,z)+=1:htable(i0,xx)=x:xx+=1:y=y-1:yy=yy-1
next x
z+=1:yy+=yy
goto a256
end if

' add any remaining symbols at current code length
if y>0 then
for x=0 to 255
if hcount(i0,x)>0 then htl(i0,z)+=1:htable(i0,xx)=x:xx+=1
next x
end if


' write table to file
s=&HC4FF:put #ff1,,s
s=19+xx:a=(s shr 8):put #ff1,,a:a=(s and 255):put #ff1,,a
a=(i0 and 1):if (i0 and 2) then a+=16
put #ff1,,a
put #ff1,,htl(i0,0),16
put #ff1,,htable(i0,0),xx

' build code table (needed for encoding later)
xx=0:zz=0
for y=0 to 15
for z=0 to htl(i0,y)-1
hlength(i0,htable(i0,zz))=y+1
hcode(i0,htable(i0,zz))=xx
xx+=1:zz+=1
next z
xx+=xx
next y

next i0


s=&HC0FF:put #ff1,,s            ' baseline DCT JPEG header
s=&H1100:put #ff1,,s            ' header length
a=8:put #ff1,,a                 ' sample bits
a=(bmp1v shr 8):put #ff1,,a:a=(bmp1v and 248):put #ff1,,a       ' vres
a=(bmp1h shr 8):put #ff1,,a:a=(bmp1h and 248):put #ff1,,a       ' hres
a=3:put #ff1,,a                 ' color components

a=1:put #ff1,,a                 ' component ID
a=17:put #ff1,,a                ' component resolution
a=0:put #ff1,,a                 ' quant table selection
a=2:put #ff1,,a                 ' component ID
a=17:put #ff1,,a                ' component resolution
a=1:put #ff1,,a                 ' quant table selection
a=3:put #ff1,,a                 ' component ID
a=17:put #ff1,,a                ' component resolution
a=1:put #ff1,,a                 ' quant table selection

s=&HDAFF:put #ff1,,s            ' start of scan
s=&H0C00:put #ff1,,s            ' header length
a=3:put #ff1,,a                 ' number of components

a=1:put #ff1,,a                 ' component ID
a=0:put #ff1,,a                 ' huffman table selection
                                ' (DC=top nibble, AC=bottom nibble)
a=2:put #ff1,,a                 ' component ID
a=17:put #ff1,,a                 ' huffman table selection
a=3:put #ff1,,a                 ' component ID
a=17:put #ff1,,a                 ' huffman table selection

a=0:put #ff1,,a                 ' ??
a=63:put #ff1,,a                ' ??
a=0:put #ff1,,a                 ' ??


? "Pass 2..."
bbits=0:bbytes=0
tpass=0:gosub imgenc

gosub writelast

end



imgenc:
olddc(1)=0:olddc(2)=0:olddc(3)=0

for bv=1 to bmp1v-7 step 8
for bh=0 to bmp1h-8 step 8

' load block and convert to YUV
z=0
for v=0 to 7
x=55+((((bmp1h*3)+3) and &HFFFFC)*(bmp1v-(v+bv)))+(bh*3)
get #ff2,x,pixbuf(0,0),24
for h=0 to 7
i0=0.114*pixbuf(h,0)+0.587*pixbuf(h,1)+0.299*pixbuf(h,2)
i1=(0-i0+pixbuf(h,0))*0.493
i2=(0-i0+pixbuf(h,2))*0.877
i0=i0-128
if i0<-128 then i0=-128
if i0>127 then i0=127
if i1<-128 then i1=-128
if i1>127 then i1=127
if i2<-128 then i2=-128
if i2>127 then i2=127
blk4(1,z)=i0:blk4(4,z)=i1:blk4(5,z)=i2
z+=1
next h
next v

bcom=1:dbuf=1:b=0
gosub encodeblk

bcom=2:dbuf=4:b=1
gosub encodeblk
bcom=3:dbuf=5:b=1
gosub encodeblk

next bh
next bv
return


writecode:
if tpass=1 then hcount(b,m)+=1:hcount(b,256)+=1:return
wbits=hlength(b,m):xx=hcode(b,m)

writebits:
if tpass=1 then return
writebits2:
if wbits=0 then return
wbits=wbits-1:a+=a
if (xx and (1 shl wbits)) then a+=1
bbits+=1
if bbits=8 then
bbits=0
a257:
filebuf(bbytes)=a:bbytes+=1
if bbytes=4096 then put #ff1,,filebuf():bbytes=0
if a=255 then a=0:goto a257
a=0
end if
goto writebits2

writelast:
if bbytes>0 then put #ff1,,filebuf(0),bbytes
return


encodeblk:
' DCT
for z=0 to 63
x=0:zz=(z shl 6)
for y=0 to 63
x+=blk4(dbuf,y)*itable(y+zz)
next y
blk(zigzag2(z))=(x shr 18)\qtable(b,zigzag2(z))
next z

' DC coefficient
x=blk(0)-olddc(bcom):olddc(bcom)=blk(0)
m=0
if x=0 then gosub writecode:goto a258
y=abs(x)
do:m+=1:y=(y shr 1):loop until y=0
gosub writecode
if x<0 then x+=(1 shl m)-1
xx=x:wbits=m:gosub writebits
a258:


' AC coefficients
b+=2

zz=1
for z=1 to 63
x=blk(z)
if x<>0 then
a260:
if z-zz>15 then zz+=16:m=240:gosub writecode:goto a260
y=abs(x):m=0
do:m+=1:y=(y shr 1):loop until y=0
if x<0 then x+=(1 shl m)-1
m+=((z-zz) shl 4)
zz=z+1:gosub writecode
xx=x:wbits=(m and 15):gosub writebits
end if
next z

if zz<64 then m=0:gosub writecode

a259:
return
Otter
Posts: 10
Joined: Nov 02, 2012 22:45

Re: basic JPEG decoder- and encoder

Post by Otter »

In the second post of the decoder it needs initiation, or next files can rise brightness.
For example, put the Sieg sag outside, make the RSTINT first variable, PI last,

CLEAR RSTINT, , CINT(VARPTR(PI)) - CINT(VARPTR(RSTINT))

it won't include PI. Not sure, will the variables be certainly continious in memory if declared continuously.... If adding initiation right there, DIM SHARED PI = , PI won't be stored at the same place.

And there's a mistake. There're lines in DECODEBLK:

bcom += 4
....
m=m*qtable(cq(bcom+4),z)

there's only 4 elements in CQ. Maybe should be like

M = M * QTABLE(CQ(BCOM - 4), Z)

Mostly it doesn't do anything, maybe 'cause there's memory padding around, but sometimes it makes the weird thing of JPEG being blurred, when adding variables to SHARED block.
Post Reply