@@ -31,6 +31,8 @@ public class JpegDecoder : ImageDecoder
3131 HuffmanTable [ ] ac_huff_tables = new HuffmanTable [ 4 ] ;
3232 HuffmanTable [ ] dc_huff_tables = new HuffmanTable [ 4 ] ;
3333 JpegComponent [ ] comps ;
34+ byte lowestHor = 1 ;
35+ byte lowestVer = 1 ;
3436
3537 public static bool DetectHeader ( byte [ ] data ) {
3638 return MatchesSignature ( data , jfifSig )
@@ -92,6 +94,7 @@ void SkipMarker(byte[] src) {
9294 AdvanceOffset ( length - 2 ) ;
9395 }
9496
97+ const int QUANT_DATA_LEN = 65 ; // 1 byte flags, 64 byte values
9598 void ReadQuantisationTables ( byte [ ] src ) {
9699 int offset = AdvanceOffset ( 2 ) ;
97100 int length = MemUtils . ReadU16_BE ( src , offset ) ;
@@ -103,8 +106,8 @@ void ReadQuantisationTables(byte[] src) {
103106 // Can have more than one quantisation table
104107 while ( length != 0 )
105108 {
106- if ( length < 65 ) Fail ( "quant table too short: " + length ) ;
107- length -= 65 ;
109+ if ( length < QUANT_DATA_LEN ) Fail ( "quant table too short: " + length ) ;
110+ length -= QUANT_DATA_LEN ;
108111
109112 byte flags = src [ offset ++ ] ;
110113 // As per Table B.4, 16 bit quantisation tables not in baseline JPEG
@@ -198,15 +201,26 @@ void ReadFrameStart(byte[] src, SimpleBitmap bmp) {
198201 offset += 6 ;
199202
200203 comps = new JpegComponent [ numComps ] ;
204+
201205 for ( int i = 0 ; i < numComps ; i ++ )
202206 {
203- JpegComponent comp = default ( JpegComponent ) ;
207+ JpegComponent comp = new JpegComponent ( ) ;
204208 comp . ID = src [ offset ++ ] ;
205209 byte sampling = src [ offset ++ ] ;
206210 comp . SamplingHor = ( byte ) ( sampling >> 4 ) ;
207211 comp . SamplingVer = ( byte ) ( sampling & 0x0F ) ;
208212 comp . QuantTable = src [ offset ++ ] ;
209- comps [ i ] = comp ;
213+
214+ lowestHor = Math . Max ( lowestHor , comp . SamplingHor ) ;
215+ lowestVer = Math . Max ( lowestVer , comp . SamplingVer ) ;
216+ comps [ i ] = comp ;
217+ }
218+
219+ // In most JPEG images there is chroma sub-sampling
220+ for ( int i = 0 ; i < numComps ; i ++ )
221+ {
222+ comps [ i ] . BlocksPerMcuX = comps [ i ] . SamplingHor ;
223+ comps [ i ] . BlocksPerMcuY = comps [ i ] . SamplingVer ;
210224 }
211225 }
212226
@@ -224,13 +238,8 @@ void ReadScanStart(byte[] src) {
224238 SetHuffTables ( compID , tables ) ;
225239 }
226240
227- byte spec_lo = src [ offset ++ ] ;
228- byte spec_hi = src [ offset ++ ] ;
229- byte succ_apr = src [ offset ++ ] ;
230-
231- if ( spec_lo != 0 ) Fail ( "spectral range start" ) ;
232- if ( spec_hi != 0 && spec_hi != 63 ) Fail ( "spectral range end" ) ;
233- if ( succ_apr != 0 ) Fail ( "successive approximation" ) ;
241+ // Spectral lo/hi data and successive approximation irrelevant
242+ offset += 3 ;
234243 }
235244
236245 void SetHuffTables ( byte compID , byte tables ) {
@@ -258,63 +267,37 @@ void SetHuffTables(byte compID, byte tables) {
258267 53 , 60 , 61 , 54 , 47 , 55 , 62 , 63 ,
259268 } ;
260269
270+ const int BLOCK_SAMPLES = 8 ;
261271 void DecodeMCUs ( byte [ ] src , SimpleBitmap bmp ) {
262- int mcus_x = ( bmp . Width + 7 ) / 8 ;
263- int mcus_y = ( bmp . Height + 7 ) / 8 ;
272+ int mcus_x = Utils . CeilDiv ( bmp . Width , lowestHor * BLOCK_SAMPLES ) ;
273+ int mcus_y = Utils . CeilDiv ( bmp . Height , lowestVer * BLOCK_SAMPLES ) ;
264274
265275 JpegComponent [ ] comps = this . comps ;
266276 int [ ] block = new int [ 64 ] ;
277+ float [ ] output = new float [ 64 ] ;
267278
268- for ( int y = 0 ; y < mcus_y ; y ++ )
269- for ( int x = 0 ; x < mcus_x ; x ++ )
279+ for ( int mcuY = 0 ; mcuY < mcus_y ; mcuY ++ )
280+ for ( int mcuX = 0 ; mcuX < mcus_x ; mcuX ++ )
270281 {
271282 for ( int i = 0 ; i < comps . Length ; i ++ )
272283 {
273- // DC value is relative to DC value from prior block
274- var table = dc_huff_tables [ comps [ i ] . DCHuffTable ] ;
275- int dc_code = ReadHuffman ( table , src ) ;
276- int dc_delta = ReadBiasedValue ( src , dc_code ) ;
277-
278- int dc_value = comps [ i ] . PredDCValue + dc_delta ;
279- comps [ i ] . PredDCValue = dc_value ;
280-
281- byte [ ] dequant = quant_tables [ comps [ i ] . QuantTable ] ;
282- for ( int j = 0 ; j < block . Length ; j ++ ) block [ j ] = 0 ;
283- block [ 0 ] = dc_value * dequant [ 0 ] ;
284+ JpegComponent comp = comps [ i ] ;
284285
285- // 63 AC values
286- table = ac_huff_tables [ comps [ i ] . ACHuffTable ] ;
287- int idx = 1 ;
288- do {
289- int code = ReadHuffman ( table , src ) ;
290- if ( code == 0 ) break ;
291-
292- int bits = code & 0x0F ;
293- int num_zeros = code >> 4 ;
294-
295- if ( bits == 0 ) {
296- if ( code == 0 ) break ; // 0 value - end of block
297- // TODO is this right?
298- if ( num_zeros != 15 ) Fail ( "too many zeroes" ) ;
299- idx += 16 ;
300- } else {
301- idx += num_zeros ;
302- int lin = zigzag_to_linear [ idx ] ;
303- block [ lin ] = ReadBiasedValue ( src , bits ) * dequant [ idx ] ;
304- idx ++ ;
305- }
306- } while ( idx < 64 ) ;
307-
308- float [ ] output = new float [ 64 ] ;
309- IDCT ( block , output ) ;
286+ for ( int blockY = 0 ; blockY < comp . BlocksPerMcuY ; blockY ++ )
287+ for ( int blockX = 0 ; blockX < comp . BlocksPerMcuX ; blockX ++ )
288+ {
289+ DecodeBlock ( comp , src , block , output ) ;
290+ IDCT ( block , output ) ;
291+ }
310292
311- for ( int YY = 0 ; YY < 8 ; YY ++ )
312- for ( int XX = 0 ; XX < 8 ; XX ++ )
293+ for ( int YY = 0 ; YY < BLOCK_SAMPLES ; YY ++ )
294+ for ( int XX = 0 ; XX < BLOCK_SAMPLES ; XX ++ )
313295 {
314- int globalX = x * 8 + XX ;
315- int globalY = y * 8 + YY ;
296+ int globalX = mcuX * BLOCK_SAMPLES + XX ;
297+ int globalY = mcuY * BLOCK_SAMPLES + YY ;
298+
316299 if ( globalX < bmp . Width && globalY < bmp . Height ) {
317- byte rgb = ( byte ) output [ YY * 8 + XX ] ;
300+ byte rgb = ( byte ) output [ YY * BLOCK_SAMPLES + XX ] ;
318301 Pixel p = new Pixel ( rgb , rgb , rgb , 255 ) ;
319302 bmp . pixels [ globalY * bmp . Width + globalX ] = p ;
320303 }
@@ -325,6 +308,46 @@ void DecodeMCUs(byte[] src, SimpleBitmap bmp) {
325308 // Fail("MCUs");
326309 }
327310
311+ void DecodeBlock ( JpegComponent comp , byte [ ] src , int [ ] block , float [ ] output ) {
312+ // DC value is relative to DC value from prior block
313+ var table = dc_huff_tables [ comp . DCHuffTable ] ;
314+ int dc_code = ReadHuffman ( table , src ) ;
315+ int dc_delta = ReadBiasedValue ( src , dc_code ) ;
316+
317+ int dc_value = comp . PredDCValue + dc_delta ;
318+ comp . PredDCValue = dc_value ;
319+
320+ byte [ ] dequant = quant_tables [ comp . QuantTable ] ;
321+ for ( int j = 0 ; j < block . Length ; j ++ ) block [ j ] = 0 ;
322+ block [ 0 ] = dc_value * dequant [ 0 ] ;
323+
324+ // 63 AC values
325+ table = ac_huff_tables [ comp . ACHuffTable ] ;
326+ int idx = 1 ;
327+
328+ do {
329+ int code = ReadHuffman ( table , src ) ;
330+ if ( code == 0 ) break ;
331+
332+ int bits = code & 0x0F ;
333+ int num_zeros = code >> 4 ;
334+
335+ if ( bits == 0 ) {
336+ if ( code == 0 ) break ; // 0 value - end of block
337+ // TODO is this right?
338+ if ( num_zeros != 15 ) Fail ( "too many zeroes" ) ;
339+ idx += 16 ;
340+ } else {
341+ idx += num_zeros ;
342+ int lin = zigzag_to_linear [ idx ] ;
343+ block [ lin ] = ReadBiasedValue ( src , bits ) * dequant [ idx ] ;
344+ idx ++ ;
345+ }
346+ } while ( idx < 64 ) ;
347+
348+ IDCT ( block , output ) ;
349+ }
350+
328351 void IDCT ( int [ ] block , float [ ] output ) {
329352 for ( int y = 0 ; y < 8 ; y ++ )
330353 for ( int x = 0 ; x < 8 ; x ++ )
@@ -346,6 +369,10 @@ void IDCT(int[] block, float[] output) {
346369 }
347370 }
348371
372+ void OutputImage ( SimpleBitmap bmp ) {
373+
374+ }
375+
349376 uint bit_buf ;
350377 int bit_cnt ;
351378 bool end ;
@@ -409,12 +436,16 @@ int ReadBiasedValue(byte[] src, int bits) {
409436 }
410437 }
411438
412- struct JpegComponent
439+ class JpegComponent
413440 {
414441 public byte ID ;
442+ public byte QuantTable ;
443+
415444 public byte SamplingHor ;
416445 public byte SamplingVer ;
417- public byte QuantTable ;
446+ public byte BlocksPerMcuX ;
447+ public byte BlocksPerMcuY ;
448+
418449 public byte ACHuffTable ;
419450 public byte DCHuffTable ;
420451 public int PredDCValue ;
0 commit comments