@@ -238,54 +238,181 @@ int ReadTile(TIFF* tiff, UINT32 col, UINT32 row, UINT32* buffer) {
238238 return 0 ;
239239}
240240
241- int ReadStrip (TIFF * tiff , UINT32 row , UINT32 * buffer ) {
242- uint16 photometric = 0 ; // init to not PHOTOMETRIC_YCBCR
243- TIFFGetField (tiff , TIFFTAG_PHOTOMETRIC , & photometric );
244-
241+ int _decodeStripYCbCr (Imaging im , ImagingCodecState state , TIFF * tiff ) {
245242 // To avoid dealing with YCbCr subsampling, let libtiff handle it
246- if (photometric == PHOTOMETRIC_YCBCR ) {
247- TIFFRGBAImage img ;
248- char emsg [1024 ] = "" ;
249- UINT32 rows_per_strip , rows_to_read ;
250- int ok ;
243+ // Use a TIFFRGBAImage wrapping the tiff image, and let libtiff handle
244+ // all of the conversion. Metadata read from the TIFFRGBAImage could
245+ // be different from the metadata that the base tiff returns.
246+
247+ INT32 strip_row ;
248+ UINT8 * new_data ;
249+ UINT32 rows_per_strip , row_byte_size , rows_to_read ;
250+ int ret ;
251+ TIFFRGBAImage img ;
252+ char emsg [1024 ] = "" ;
253+ int ok ;
254+
255+ ret = TIFFGetFieldDefaulted (tiff , TIFFTAG_ROWSPERSTRIP , & rows_per_strip );
256+ if (ret != 1 ) {
257+ rows_per_strip = state -> ysize ;
258+ }
259+ TRACE (("RowsPerStrip: %u \n" , rows_per_strip ));
260+
261+ if (!(TIFFRGBAImageOK (tiff , emsg ) && TIFFRGBAImageBegin (& img , tiff , 0 , emsg ))) {
262+ TRACE (("Decode error, msg: %s" , emsg ));
263+ state -> errcode = IMAGING_CODEC_BROKEN ;
264+ TIFFClose (tiff );
265+ return -1 ;
266+ }
251267
268+ img .req_orientation = ORIENTATION_TOPLEFT ;
269+ img .col_offset = 0 ;
252270
253- TIFFGetFieldDefaulted (tiff , TIFFTAG_ROWSPERSTRIP , & rows_per_strip );
254- if ((row % rows_per_strip ) != 0 ) {
255- TRACE (("Row passed to ReadStrip() must be first in a strip." ));
256- return -1 ;
257- }
271+ if (state -> xsize != img .width || state -> ysize != img .height ) {
272+ TRACE (("Inconsistent Image Error: %d =? %d, %d =? %d" ,
273+ state -> xsize , img .width , state -> ysize , img .height ));
274+ state -> errcode = IMAGING_CODEC_BROKEN ;
275+ TIFFRGBAImageEnd (& img );
276+ TIFFClose (tiff );
277+ return -1 ;
278+ }
279+
280+ /* overflow check for row byte size */
281+ if (INT_MAX / 4 < img .width ) {
282+ state -> errcode = IMAGING_CODEC_MEMORY ;
283+ TIFFRGBAImageEnd (& img );
284+ TIFFClose (tiff );
285+ return -1 ;
286+ }
287+
288+ // TiffRGBAImages are 32bits/pixel.
289+ row_byte_size = img .width * 4 ;
290+
291+ /* overflow check for realloc */
292+ if (INT_MAX / row_byte_size < rows_per_strip ) {
293+ state -> errcode = IMAGING_CODEC_MEMORY ;
294+ TIFFRGBAImageEnd (& img );
295+ TIFFClose (tiff );
296+ return -1 ;
297+ }
258298
259- if (TIFFRGBAImageOK (tiff , emsg ) && TIFFRGBAImageBegin (& img , tiff , 0 , emsg )) {
260- TRACE (("Initialized RGBAImage\n" ));
299+ state -> bytes = rows_per_strip * row_byte_size ;
261300
262- img .req_orientation = ORIENTATION_TOPLEFT ;
263- img .row_offset = row ;
264- img .col_offset = 0 ;
301+ TRACE (("StripSize: %d \n" , state -> bytes ));
265302
266- rows_to_read = min (rows_per_strip , img .height - row );
303+ /* realloc to fit whole strip */
304+ /* malloc check above */
305+ new_data = realloc (state -> buffer , state -> bytes );
306+ if (!new_data ) {
307+ state -> errcode = IMAGING_CODEC_MEMORY ;
308+ TIFFRGBAImageEnd (& img );
309+ TIFFClose (tiff );
310+ return -1 ;
311+ }
312+
313+ state -> buffer = new_data ;
267314
268- TRACE (("rows to read: %d\n" , rows_to_read ));
269- ok = TIFFRGBAImageGet (& img , buffer , img .width , rows_to_read );
315+ for (; state -> y < state -> ysize ; state -> y += rows_per_strip ) {
316+ img .row_offset = state -> y ;
317+ rows_to_read = min (rows_per_strip , img .height - state -> y );
270318
319+ if (TIFFRGBAImageGet (& img , (UINT32 * )state -> buffer , img .width , rows_to_read ) == -1 ) {
320+ TRACE (("Decode Error, y: %d\n" , state -> y ));
321+ state -> errcode = IMAGING_CODEC_BROKEN ;
271322 TIFFRGBAImageEnd (& img );
272- } else {
273- ok = 0 ;
323+ TIFFClose ( tiff );
324+ return -1 ;
274325 }
275326
276- if (ok == 0 ) {
277- TRACE (("Decode Error, row %d; msg: %s\n" , row , emsg ));
278- return -1 ;
327+ TRACE (("Decoded strip for row %d \n" , state -> y ));
328+
329+ // iterate over each row in the strip and stuff data into image
330+ for (strip_row = 0 ; strip_row < min ((INT32 ) rows_per_strip , state -> ysize - state -> y ); strip_row ++ ) {
331+ TRACE (("Writing data into line %d ; \n" , state -> y + strip_row ));
332+
333+ // UINT8 * bbb = state->buffer + strip_row * (state->bytes / rows_per_strip);
334+ // TRACE(("chars: %x %x %x %x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3]));
335+
336+ state -> shuffle ((UINT8 * ) im -> image [state -> y + state -> yoff + strip_row ] +
337+ state -> xoff * im -> pixelsize ,
338+ state -> buffer + strip_row * row_byte_size ,
339+ state -> xsize );
279340 }
341+ }
342+ TIFFRGBAImageEnd (& img );
343+ return 0 ;
344+ }
280345
281- return 0 ;
346+ int _decodeStrip (Imaging im , ImagingCodecState state , TIFF * tiff ) {
347+ INT32 strip_row ;
348+ UINT8 * new_data ;
349+ UINT32 rows_per_strip , row_byte_size ;
350+ int ret ;
351+
352+ ret = TIFFGetField (tiff , TIFFTAG_ROWSPERSTRIP , & rows_per_strip );
353+ if (ret != 1 ) {
354+ rows_per_strip = state -> ysize ;
355+ }
356+ TRACE (("RowsPerStrip: %u \n" , rows_per_strip ));
357+
358+ // We could use TIFFStripSize, but for YCbCr data it returns subsampled data size
359+ row_byte_size = (state -> xsize * state -> bits + 7 ) / 8 ;
360+
361+ /* overflow check for realloc */
362+ if (INT_MAX / row_byte_size < rows_per_strip ) {
363+ state -> errcode = IMAGING_CODEC_MEMORY ;
364+ TIFFClose (tiff );
365+ return -1 ;
366+ }
367+
368+ state -> bytes = rows_per_strip * row_byte_size ;
369+
370+ TRACE (("StripSize: %d \n" , state -> bytes ));
371+
372+ if (TIFFStripSize (tiff ) > state -> bytes ) {
373+ // If the strip size as expected by LibTiff isn't what we're expecting, abort.
374+ // man: TIFFStripSize returns the equivalent size for a strip of data as it would be returned in a
375+ // call to TIFFReadEncodedStrip ...
376+
377+ state -> errcode = IMAGING_CODEC_MEMORY ;
378+ TIFFClose (tiff );
379+ return -1 ;
282380 }
283381
284- if (TIFFReadEncodedStrip (tiff , TIFFComputeStrip (tiff , row , 0 ), (tdata_t )buffer , -1 ) == -1 ) {
285- TRACE (("Decode Error, strip %d\n" , TIFFComputeStrip (tiff , row , 0 )));
382+ /* realloc to fit whole strip */
383+ /* malloc check above */
384+ new_data = realloc (state -> buffer , state -> bytes );
385+ if (!new_data ) {
386+ state -> errcode = IMAGING_CODEC_MEMORY ;
387+ TIFFClose (tiff );
286388 return -1 ;
287389 }
288390
391+ state -> buffer = new_data ;
392+
393+ for (; state -> y < state -> ysize ; state -> y += rows_per_strip ) {
394+ if (TIFFReadEncodedStrip (tiff , TIFFComputeStrip (tiff , state -> y , 0 ), (tdata_t )state -> buffer , -1 ) == -1 ) {
395+ TRACE (("Decode Error, strip %d\n" , TIFFComputeStrip (tiff , state -> y , 0 )));
396+ state -> errcode = IMAGING_CODEC_BROKEN ;
397+ TIFFClose (tiff );
398+ return -1 ;
399+ }
400+
401+ TRACE (("Decoded strip for row %d \n" , state -> y ));
402+
403+ // iterate over each row in the strip and stuff data into image
404+ for (strip_row = 0 ; strip_row < min ((INT32 ) rows_per_strip , state -> ysize - state -> y ); strip_row ++ ) {
405+ TRACE (("Writing data into line %d ; \n" , state -> y + strip_row ));
406+
407+ // UINT8 * bbb = state->buffer + strip_row * (state->bytes / rows_per_strip);
408+ // TRACE(("chars: %x %x %x %x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3]));
409+
410+ state -> shuffle ((UINT8 * ) im -> image [state -> y + state -> yoff + strip_row ] +
411+ state -> xoff * im -> pixelsize ,
412+ state -> buffer + strip_row * row_byte_size ,
413+ state -> xsize );
414+ }
415+ }
289416 return 0 ;
290417}
291418
@@ -294,6 +421,9 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_
294421 char * filename = "tempfile.tif" ;
295422 char * mode = "r" ;
296423 TIFF * tiff ;
424+ uint16 photometric = 0 ; // init to not PHOTOMETRIC_YCBCR
425+ int isYCbCr = 0 ;
426+ int ret ;
297427
298428 /* buffer is the encoded file, bytes is the length of the encoded file */
299429 /* it all ends up in state->buffer, which is a uint8* from Imaging.h */
@@ -354,6 +484,10 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_
354484 }
355485 }
356486
487+
488+ TIFFGetField (tiff , TIFFTAG_PHOTOMETRIC , & photometric );
489+ isYCbCr = photometric == PHOTOMETRIC_YCBCR ;
490+
357491 if (TIFFIsTiled (tiff )) {
358492 INT32 x , y , tile_y ;
359493 UINT32 tile_width , tile_length , current_tile_width , row_byte_size ;
@@ -429,75 +563,13 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_
429563 }
430564 }
431565 } else {
432- INT32 strip_row ;
433- UINT8 * new_data ;
434- UINT32 rows_per_strip , row_byte_size ;
435- int ret ;
436-
437- ret = TIFFGetField (tiff , TIFFTAG_ROWSPERSTRIP , & rows_per_strip );
438- if (ret != 1 ) {
439- rows_per_strip = state -> ysize ;
440- }
441- TRACE (("RowsPerStrip: %u \n" , rows_per_strip ));
442-
443- // We could use TIFFStripSize, but for YCbCr data it returns subsampled data size
444- row_byte_size = (state -> xsize * state -> bits + 7 ) / 8 ;
445-
446- /* overflow check for realloc */
447- if (INT_MAX / row_byte_size < rows_per_strip ) {
448- state -> errcode = IMAGING_CODEC_MEMORY ;
449- TIFFClose (tiff );
450- return -1 ;
451- }
452-
453- state -> bytes = rows_per_strip * row_byte_size ;
454-
455- TRACE (("StripSize: %d \n" , state -> bytes ));
456-
457- if (TIFFStripSize (tiff ) > state -> bytes ) {
458- // If the strip size as expected by LibTiff isn't what we're expecting, abort.
459- // man: TIFFStripSize returns the equivalent size for a strip of data as it would be returned in a
460- // call to TIFFReadEncodedStrip ...
461-
462- state -> errcode = IMAGING_CODEC_MEMORY ;
463- TIFFClose (tiff );
464- return -1 ;
465- }
466-
467- /* realloc to fit whole strip */
468- /* malloc check above */
469- new_data = realloc (state -> buffer , state -> bytes );
470- if (!new_data ) {
471- state -> errcode = IMAGING_CODEC_MEMORY ;
472- TIFFClose (tiff );
473- return -1 ;
566+ if (!isYCbCr ) {
567+ ret = _decodeStrip (im , state , tiff );
474568 }
475-
476- state -> buffer = new_data ;
477-
478- for (; state -> y < state -> ysize ; state -> y += rows_per_strip ) {
479- if (ReadStrip (tiff , state -> y , (UINT32 * )state -> buffer ) == -1 ) {
480- TRACE (("Decode Error, strip %d\n" , TIFFComputeStrip (tiff , state -> y , 0 )));
481- state -> errcode = IMAGING_CODEC_BROKEN ;
482- TIFFClose (tiff );
483- return -1 ;
484- }
485-
486- TRACE (("Decoded strip for row %d \n" , state -> y ));
487-
488- // iterate over each row in the strip and stuff data into image
489- for (strip_row = 0 ; strip_row < min ((INT32 ) rows_per_strip , state -> ysize - state -> y ); strip_row ++ ) {
490- TRACE (("Writing data into line %d ; \n" , state -> y + strip_row ));
491-
492- // UINT8 * bbb = state->buffer + strip_row * (state->bytes / rows_per_strip);
493- // TRACE(("chars: %x %x %x %x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3]));
494-
495- state -> shuffle ((UINT8 * ) im -> image [state -> y + state -> yoff + strip_row ] +
496- state -> xoff * im -> pixelsize ,
497- state -> buffer + strip_row * row_byte_size ,
498- state -> xsize );
499- }
569+ else {
570+ ret = _decodeStripYCbCr (im , state , tiff );
500571 }
572+ if (ret == -1 ) { return ret ; }
501573 }
502574
503575 TIFFClose (tiff );
0 commit comments