@@ -50,46 +50,38 @@ public override SimpleBitmap Decode(byte[] src) {
5050 const ushort MARKER_IMAGE_BEG = 0xFFD8 ;
5151 const ushort MARKER_IMAGE_END = 0xFFD9 ;
5252 const ushort MARKER_APP0 = 0xFFE0 ;
53- const ushort MARKER_APP1 = 0xFFE1 ;
53+ const ushort MARKER_APP15 = 0xFFEF ;
5454 const ushort MARKER_TBL_QUANT = 0xFFDB ;
5555 const ushort MARKER_TBL_HUFF = 0xFFC4 ;
5656 const ushort MARKER_FRAME_BEG = 0xFFC0 ;
5757 const ushort MARKER_SCAN_BEG = 0xFFDA ;
58+ const ushort MARKER_COMMENT = 0xFFFE ;
5859
5960 void ReadMarkers ( byte [ ] src , SimpleBitmap bmp ) {
6061 for ( ; ; )
6162 {
6263 int offset = AdvanceOffset ( 2 ) ;
6364 ushort marker = MemUtils . ReadU16_BE ( src , offset ) ;
6465
65- switch ( marker )
66- {
67- case MARKER_IMAGE_BEG :
68- break ; // Nothing to do
69- case MARKER_IMAGE_END :
70- return ;
71- case MARKER_APP0 :
72- case MARKER_APP1 :
73- SkipMarker ( src ) ;
74- break ;
75-
76- case MARKER_TBL_HUFF :
77- ReadHuffmanTable ( src ) ;
78- break ;
79- case MARKER_TBL_QUANT :
80- ReadQuantisationTables ( src ) ;
81- break ;
82- case MARKER_FRAME_BEG :
83- ReadFrameStart ( src ) ;
84- break ;
85- case MARKER_SCAN_BEG :
86- ReadScanStart ( src ) ;
87- DecodeMCUs ( src ) ;
88- break ;
89-
90- default :
91- Fail ( "unknown marker:" + marker . ToString ( "X4" ) ) ;
92- break ;
66+ if ( marker == MARKER_IMAGE_BEG ) {
67+ // Nothing to do
68+ } else if ( marker == MARKER_IMAGE_END ) {
69+ return ;
70+ } else if ( marker >= MARKER_APP0 && marker <= MARKER_APP15 ) {
71+ SkipMarker ( src ) ;
72+ } else if ( marker == MARKER_COMMENT ) {
73+ SkipMarker ( src ) ;
74+ } else if ( marker == MARKER_TBL_HUFF ) {
75+ ReadHuffmanTable ( src ) ;
76+ } else if ( marker == MARKER_TBL_QUANT ) {
77+ ReadQuantisationTables ( src ) ;
78+ } else if ( marker == MARKER_FRAME_BEG ) {
79+ ReadFrameStart ( src , bmp ) ;
80+ } else if ( marker == MARKER_SCAN_BEG ) {
81+ ReadScanStart ( src ) ;
82+ DecodeMCUs ( src , bmp ) ;
83+ } else {
84+ Fail ( "unknown marker:" + marker . ToString ( "X4" ) ) ;
9385 }
9486 }
9587 }
@@ -137,10 +129,12 @@ void ReadHuffmanTable(byte[] src) {
137129 // length *includes* 2 bytes of length
138130 offset = AdvanceOffset ( length - 2 ) ;
139131
140- // TODO multi tables
141132 byte flags = src [ offset ++ ] ;
142133
143- HuffmanTable table ;
134+ HuffmanTable table = new HuffmanTable ( ) ;
135+ HuffmanTable [ ] tables = ( flags >> 4 ) != 0 ? ac_huff_tables : dc_huff_tables ;
136+ tables [ flags & 0x03 ] = table ;
137+
144138 table . firstCodewords = new ushort [ HUFF_MAX_BITS ] ;
145139 table . endCodewords = new ushort [ HUFF_MAX_BITS ] ;
146140 table . firstOffsets = new ushort [ HUFF_MAX_BITS ] ;
@@ -150,11 +144,11 @@ void ReadHuffmanTable(byte[] src) {
150144 // Codewords are ordered, so consider this example tree:
151145 // 2 of length 2, 3 of length 3, 1 of length 4
152146 // Codewords produced would be: 00,01 100,101,110, 1110
153- int code = 0 ;
147+ int code = 0 ;
154148 int total = 0 ;
155149 byte [ ] counts = new byte [ HUFF_MAX_BITS ] ;
156150
157- for ( int i = 0 ; i < HUFF_MAX_BITS ; i ++ )
151+ for ( int i = 0 ; i < HUFF_MAX_BITS ; i ++ )
158152 {
159153 byte count = src [ offset ++ ] ;
160154 if ( count > ( 1 << ( i + 1 ) ) ) Fail ( "too many codewords for bit length" ) ;
@@ -167,11 +161,8 @@ void ReadHuffmanTable(byte[] src) {
167161 // Last codeword is actually: code + (count - 1)
168162 // However, when decoding we peform < against this value though, so need to add 1 here.
169163 // This way, don't need to special case bit lengths with 0 codewords when decoding.
170- //
171164 if ( count != 0 ) {
172165 table . endCodewords [ i ] = ( ushort ) ( code + count ) ;
173- } else {
174- table . endCodewords [ i ] = 0 ;
175166 }
176167 code = ( code + count ) << 1 ;
177168 }
@@ -181,28 +172,27 @@ void ReadHuffmanTable(byte[] src) {
181172 // Read values for each codeword.
182173 // Note that although codewords are ordered, values may not be.
183174 // Some values may also not be assigned to any codeword.
184- for ( int i = 0 ; i < counts . Length ; i ++ )
175+ for ( int i = 0 ; i < counts . Length ; i ++ )
185176 {
186177 for ( int j = 0 ; j < counts [ i ] ; j ++ )
187178 {
188179 table . values [ total ++ ] = src [ offset ++ ] ;
189180 }
190181 }
191-
192- HuffmanTable [ ] tables = ( flags >> 4 ) != 0 ? ac_huff_tables : dc_huff_tables ;
193- tables [ flags & 0x03 ] = table ;
194182 }
195183
196- void ReadFrameStart ( byte [ ] src ) {
184+ void ReadFrameStart ( byte [ ] src , SimpleBitmap bmp ) {
197185 int offset = AdvanceOffset ( 2 ) ;
198186 int length = MemUtils . ReadU16_BE ( src , offset ) ;
199187 // length *includes* 2 bytes of length
200188 offset = AdvanceOffset ( length - 2 ) ;
201189
202190 byte bits = src [ offset + 0 ] ;
203191 if ( bits != 8 ) Fail ( "bits per sample" ) ;
204- int height = MemUtils . ReadU16_BE ( src , offset + 1 ) ;
205- int width = MemUtils . ReadU16_BE ( src , offset + 3 ) ;
192+
193+ bmp . Height = MemUtils . ReadU16_BE ( src , offset + 1 ) ;
194+ bmp . Width = MemUtils . ReadU16_BE ( src , offset + 3 ) ;
195+ bmp . AllocatePixels ( ) ;
206196
207197 byte numComps = src [ offset + 5 ] ;
208198 if ( ! ( numComps == 1 || numComps == 3 ) ) Fail ( "num components" ) ;
@@ -251,14 +241,138 @@ void SetHuffTables(byte compID, byte tables) {
251241
252242 comps [ i ] . DCHuffTable = ( byte ) ( tables >> 4 ) ;
253243 comps [ i ] . ACHuffTable = ( byte ) ( tables & 0x0F ) ;
244+ comps [ i ] . PredDCValue = 0 ;
254245 return ;
255246 }
256247 Fail ( "unknown scan component" ) ;
257248 }
258249
259- void DecodeMCUs ( byte [ ] src ) {
250+ static byte [ ] zigzag_to_linear = new byte [ 64 ]
251+ {
252+ 0 , 1 , 8 , 16 , 9 , 2 , 3 , 10 ,
253+ 17 , 24 , 32 , 25 , 18 , 11 , 4 , 5 ,
254+ 12 , 19 , 26 , 33 , 40 , 48 , 41 , 34 ,
255+ 27 , 20 , 13 , 6 , 7 , 14 , 21 , 28 ,
256+ 35 , 42 , 49 , 56 , 57 , 50 , 43 , 36 ,
257+ 29 , 22 , 15 , 23 , 30 , 37 , 44 , 51 ,
258+ 58 , 59 , 52 , 45 , 38 , 31 , 39 , 46 ,
259+ 53 , 60 , 61 , 54 , 47 , 55 , 62 , 63 ,
260+ } ;
261+
262+ void DecodeMCUs ( byte [ ] src , SimpleBitmap bmp ) {
263+ int mcus_x = ( bmp . Width + 7 ) / 8 ;
264+ int mcus_y = ( bmp . Height + 7 ) / 8 ;
265+ bit_offset = AdvanceOffset ( 0 ) ;
266+
267+ JpegComponent [ ] comps = this . comps ;
268+ int [ ] block = new int [ 64 ] ;
269+
270+ for ( int y = 0 ; y < mcus_y ; y ++ )
271+ for ( int x = 0 ; x < mcus_x ; x ++ )
272+ {
273+ for ( int i = 0 ; i < comps . Length ; i ++ )
274+ {
275+ // DC value is relative to DC value from prior block
276+ var table = dc_huff_tables [ comps [ i ] . DCHuffTable ] ;
277+ int dc_code = ReadHuffman ( table , src ) ;
278+ int dc_delta = ReadBiasedValue ( src , dc_code ) ;
279+
280+ int dc_value = comps [ i ] . PredDCValue + dc_delta ;
281+ comps [ i ] . PredDCValue = dc_value ;
282+
283+ byte [ ] dequant = quant_tables [ comps [ i ] . QuantTable ] ;
284+ for ( int j = 0 ; j < block . Length ; j ++ ) block [ j ] = 0 ;
285+ block [ 0 ] = dc_value * dequant [ 0 ] ;
286+
287+ // 63 AC values
288+ table = ac_huff_tables [ comps [ i ] . ACHuffTable ] ;
289+ int idx = 1 ;
290+ do {
291+ int code = ReadHuffman ( table , src ) ;
292+ if ( code == 0 ) break ;
293+
294+ int bits = code & 0x0F ;
295+ int num_zeros = code >> 4 ;
296+
297+ if ( bits == 0 ) {
298+ if ( code == 0 ) break ; // 0 value - end of block
299+ // TODO is this right?
300+ if ( num_zeros != 15 ) Fail ( "too many zeroes" ) ;
301+ idx += 16 ;
302+ } else {
303+ idx += num_zeros ;
304+ int lin = zigzag_to_linear [ idx ] ;
305+ block [ lin ] = ReadBiasedValue ( src , bits ) * dequant [ idx ] ;
306+ idx ++ ;
307+ }
308+ } while ( idx < 64 ) ;
309+
310+ Fail ( "DE" ) ;
311+ }
312+ }
260313 Fail ( "MCUs" ) ;
261314 }
315+
316+ uint bit_buf ;
317+ int bit_cnt ;
318+ int bit_offset ;
319+
320+ int ReadBits ( byte [ ] src , int count ) {
321+ while ( bit_cnt <= 24 ) {
322+ byte next = src [ bit_offset ++ ] ;
323+ // JPEG byte stuffing
324+ // TODO restart markers ?
325+ if ( next == 0xFF ) {
326+ byte type = src [ bit_offset ++ ] ;
327+ if ( type != 0 ) Fail ( "unexpected marker" ) ;
328+ }
329+
330+ bit_buf <<= 8 ;
331+ bit_buf |= next ;
332+ bit_cnt += 8 ;
333+ }
334+
335+ int read = bit_cnt - count ;
336+ int bits = ( int ) ( bit_buf >> read ) ;
337+
338+ bit_buf &= ( uint ) ( ( 1 << read ) - 1 ) ;
339+ bit_cnt -= count ;
340+ return bits ;
341+ }
342+
343+ byte ReadHuffman ( HuffmanTable table , byte [ ] src ) {
344+ int codeword = 0 ;
345+ // TODO optimise
346+ for ( int i = 0 ; i < HUFF_MAX_BITS ; i ++ )
347+ {
348+ codeword <<= 1 ;
349+ codeword |= ReadBits ( src , 1 ) ;
350+
351+ if ( codeword < table . endCodewords [ i ] ) {
352+ int offset = table . firstOffsets [ i ] + ( codeword - table . firstCodewords [ i ] ) ;
353+ byte value = table . values [ offset ] ;
354+ return value ;
355+ }
356+ }
357+
358+ Fail ( "no huffman code" ) ;
359+ return 0 ;
360+ }
361+
362+ int ReadBiasedValue ( byte [ ] src , int bits ) {
363+ if ( bits == 0 ) return 0 ;
364+
365+ int value = ReadBits ( src , bits ) ;
366+ int midpoint = 1 << ( bits - 1 ) ;
367+
368+ // E.g. for two bits, bits/values are:
369+ // 00, 01, 10, 11
370+ // -3, -2, 2, 3
371+ if ( value < midpoint ) {
372+ value += ( - 1 << bits ) + 1 ;
373+ }
374+ return value ;
375+ }
262376 }
263377
264378 struct JpegComponent
@@ -269,9 +383,10 @@ struct JpegComponent
269383 public byte QuantTable ;
270384 public byte ACHuffTable ;
271385 public byte DCHuffTable ;
386+ public int PredDCValue ;
272387 }
273388
274- struct HuffmanTable
389+ class HuffmanTable
275390 {
276391 // Maximum of 256 values/symbols and 16 bit length codes
277392
0 commit comments