@@ -181,7 +181,7 @@ int ImagingLibTiffInit(ImagingCodecState state, int fp, uint32 offset) {
181181}
182182
183183
184- int ReadTile (TIFF * tiff , UINT32 col , UINT32 row , UINT32 * buffer ) {
184+ int ReadTile (TIFF * tiff , UINT32 col , UINT32 row , UINT8 plane , UINT32 * buffer ) {
185185 uint16 photometric = 0 ;
186186
187187 TIFFGetField (tiff , TIFFTAG_PHOTOMETRIC , & photometric );
@@ -228,7 +228,7 @@ int ReadTile(TIFF* tiff, UINT32 col, UINT32 row, UINT32* buffer) {
228228 return 0 ;
229229 }
230230
231- if (TIFFReadTile (tiff , (tdata_t )buffer , col , row , 0 , 0 ) == -1 ) {
231+ if (TIFFReadTile (tiff , (tdata_t )buffer , col , row , 0 , plane ) == -1 ) {
232232 TRACE (("Decode Error, Tile at %dx%d\n" , col , row ));
233233 return -1 ;
234234 }
@@ -238,7 +238,7 @@ int ReadTile(TIFF* tiff, UINT32 col, UINT32 row, UINT32* buffer) {
238238 return 0 ;
239239}
240240
241- int ReadStrip (TIFF * tiff , UINT32 row , UINT32 * buffer ) {
241+ int ReadStrip (TIFF * tiff , UINT32 row , UINT8 plane , UINT32 * buffer ) {
242242 uint16 photometric = 0 ; // init to not PHOTOMETRIC_YCBCR
243243 TIFFGetField (tiff , TIFFTAG_PHOTOMETRIC , & photometric );
244244
@@ -259,6 +259,8 @@ int ReadStrip(TIFF* tiff, UINT32 row, UINT32* buffer) {
259259 if (TIFFRGBAImageOK (tiff , emsg ) && TIFFRGBAImageBegin (& img , tiff , 0 , emsg )) {
260260 TRACE (("Initialized RGBAImage\n" ));
261261
262+ // Using TIFFRGBAImageGet instead of TIFFReadRGBAStrip
263+ // just to get strip in TOP_LEFT orientation
262264 img .req_orientation = ORIENTATION_TOPLEFT ;
263265 img .row_offset = row ;
264266 img .col_offset = 0 ;
@@ -281,7 +283,7 @@ int ReadStrip(TIFF* tiff, UINT32 row, UINT32* buffer) {
281283 return 0 ;
282284 }
283285
284- if (TIFFReadEncodedStrip (tiff , TIFFComputeStrip (tiff , row , 0 ), (tdata_t )buffer , -1 ) == -1 ) {
286+ if (TIFFReadEncodedStrip (tiff , TIFFComputeStrip (tiff , row , plane ), (tdata_t )buffer , -1 ) == -1 ) {
285287 TRACE (("Decode Error, strip %d\n" , TIFFComputeStrip (tiff , row , 0 )));
286288 return -1 ;
287289 }
@@ -294,6 +296,10 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_
294296 char * filename = "tempfile.tif" ;
295297 char * mode = "r" ;
296298 TIFF * tiff ;
299+ uint16 photometric = 0 ; // init to not PHOTOMETRIC_YCBCR
300+ UINT8 planarconfig ;
301+ UINT8 planes = 1 ;
302+ ImagingShuffler unpackers [4 ];
297303
298304 /* buffer is the encoded file, bytes is the length of the encoded file */
299305 /* it all ends up in state->buffer, which is a uint8* from Imaging.h */
@@ -350,8 +356,38 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_
350356 rv = TIFFSetSubDirectory (tiff , ifdoffset );
351357 if (!rv ){
352358 TRACE (("error in TIFFSetSubDirectory" ));
359+ state -> errcode = IMAGING_CODEC_BROKEN ;
360+ TIFFClose (tiff );
361+ return -1 ;
362+ }
363+ }
364+
365+ TIFFGetField (tiff , TIFFTAG_PHOTOMETRIC , & photometric );
366+ TIFFGetFieldDefaulted (tiff , TIFFTAG_PLANARCONFIG , & planarconfig );
367+ // YCbCr data is read as RGB by libtiff and we don't need to worry about planar storage in that case
368+ // if number of bands is 1, there is no difference with contig case
369+ if (planarconfig == PLANARCONFIG_SEPARATE && im -> bands > 1 && photometric != PHOTOMETRIC_YCBCR ) {
370+ uint16 bps = 8 ;
371+
372+ TIFFGetFieldDefaulted (tiff , TIFFTAG_BITSPERSAMPLE , & bps );
373+ if (bps != 8 && bps != 16 ) {
374+ TRACE (("Invalid value for bits per sample: %d\n" , bps ));
375+ state -> errcode = IMAGING_CODEC_BROKEN ;
376+ TIFFClose (tiff );
353377 return -1 ;
354378 }
379+
380+ planes = im -> bands ;
381+
382+ // We'll pick appropriate set of unpackers depending on planar_configuration
383+ // It does not matter if data is RGB(A), CMYK or LUV really,
384+ // we just copy it plane by plane
385+ unpackers [0 ] = ImagingFindUnpacker ("RGBA" , bps == 16 ? "R;16N" : "R" , NULL );
386+ unpackers [1 ] = ImagingFindUnpacker ("RGBA" , bps == 16 ? "G;16N" : "G" , NULL );
387+ unpackers [2 ] = ImagingFindUnpacker ("RGBA" , bps == 16 ? "B;16N" : "B" , NULL );
388+ unpackers [3 ] = ImagingFindUnpacker ("RGBA" , bps == 16 ? "A;16N" : "A" , NULL );
389+ } else {
390+ unpackers [0 ] = state -> shuffle ;
355391 }
356392
357393 if (TIFFIsTiled (tiff )) {
@@ -370,19 +406,19 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_
370406 }
371407
372408 // We could use TIFFTileSize, but for YCbCr data it returns subsampled data size
373- row_byte_size = (tile_width * state -> bits + 7 ) / 8 ;
409+ row_byte_size = (tile_width * state -> bits / planes + 7 ) / 8 ;
374410
375411 /* overflow check for realloc */
376412 if (INT_MAX / row_byte_size < tile_length ) {
377413 state -> errcode = IMAGING_CODEC_MEMORY ;
378414 TIFFClose (tiff );
379415 return -1 ;
380416 }
381-
417+
382418 state -> bytes = row_byte_size * tile_length ;
383419
384420 if (TIFFTileSize (tiff ) > state -> bytes ) {
385- // If the strip size as expected by LibTiff isn't what we're expecting, abort.
421+ // If the tile size as expected by LibTiff isn't what we're expecting, abort.
386422 state -> errcode = IMAGING_CODEC_MEMORY ;
387423 TIFFClose (tiff );
388424 return -1 ;
@@ -402,29 +438,33 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_
402438 TRACE (("TIFFTileSize: %d\n" , state -> bytes ));
403439
404440 for (y = state -> yoff ; y < state -> ysize ; y += tile_length ) {
405- for (x = state -> xoff ; x < state -> xsize ; x += tile_width ) {
406- if (ReadTile (tiff , x , y , (UINT32 * ) state -> buffer ) == -1 ) {
407- TRACE (("Decode Error, Tile at %dx%d\n" , x , y ));
408- state -> errcode = IMAGING_CODEC_BROKEN ;
409- TIFFClose (tiff );
410- return -1 ;
411- }
412-
413- TRACE (("Read tile at %dx%d; \n\n" , x , y ));
414-
415- current_tile_width = min ((INT32 ) tile_width , state -> xsize - x );
416-
417- // iterate over each line in the tile and stuff data into image
418- for (tile_y = 0 ; tile_y < min ((INT32 ) tile_length , state -> ysize - y ); tile_y ++ ) {
419- TRACE (("Writing tile data at %dx%d using tile_width: %d; \n" , tile_y + y , x , current_tile_width ));
420-
421- // UINT8 * bbb = state->buffer + tile_y * row_byte_size;
422- // TRACE(("chars: %x%x%x%x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3]));
423-
424- state -> shuffle ((UINT8 * ) im -> image [tile_y + y ] + x * im -> pixelsize ,
425- state -> buffer + tile_y * row_byte_size ,
426- current_tile_width
427- );
441+ UINT8 plane ;
442+ for (plane = 0 ; plane < planes ; plane ++ ) {
443+ ImagingShuffler shuffler = unpackers [plane ];
444+ for (x = state -> xoff ; x < state -> xsize ; x += tile_width ) {
445+ if (ReadTile (tiff , x , y , plane , (UINT32 * ) state -> buffer ) == -1 ) {
446+ TRACE (("Decode Error, Tile at %dx%d\n" , x , y ));
447+ state -> errcode = IMAGING_CODEC_BROKEN ;
448+ TIFFClose (tiff );
449+ return -1 ;
450+ }
451+
452+ TRACE (("Read tile at %dx%d; \n\n" , x , y ));
453+
454+ current_tile_width = min ((INT32 ) tile_width , state -> xsize - x );
455+
456+ // iterate over each line in the tile and stuff data into image
457+ for (tile_y = 0 ; tile_y < min ((INT32 ) tile_length , state -> ysize - y ); tile_y ++ ) {
458+ TRACE (("Writing tile data at %dx%d using tile_width: %d; \n" , tile_y + y , x , current_tile_width ));
459+
460+ // UINT8 * bbb = state->buffer + tile_y * row_byte_size;
461+ // TRACE(("chars: %x%x%x%x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3]));
462+
463+ shuffler ((UINT8 * ) im -> image [tile_y + y ] + x * im -> pixelsize ,
464+ state -> buffer + tile_y * row_byte_size ,
465+ current_tile_width
466+ );
467+ }
428468 }
429469 }
430470 }
@@ -441,7 +481,7 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_
441481 TRACE (("RowsPerStrip: %u \n" , rows_per_strip ));
442482
443483 // We could use TIFFStripSize, but for YCbCr data it returns subsampled data size
444- row_byte_size = (state -> xsize * state -> bits + 7 ) / 8 ;
484+ row_byte_size = (state -> xsize * state -> bits / planes + 7 ) / 8 ;
445485
446486 /* overflow check for realloc */
447487 if (INT_MAX / row_byte_size < rows_per_strip ) {
@@ -476,26 +516,55 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_
476516 state -> buffer = new_data ;
477517
478518 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- }
519+ UINT8 plane ;
520+ for (plane = 0 ; plane < planes ; plane ++ ) {
521+ ImagingShuffler shuffler = unpackers [plane ];
522+ if (ReadStrip (tiff , state -> y , plane , (UINT32 * )state -> buffer ) == -1 ) {
523+ TRACE (("Decode Error, strip %d\n" , TIFFComputeStrip (tiff , state -> y , 0 )));
524+ state -> errcode = IMAGING_CODEC_BROKEN ;
525+ TIFFClose (tiff );
526+ return -1 ;
527+ }
485528
486- TRACE (("Decoded strip for row %d \n" , state -> y ));
529+ TRACE (("Decoded strip for row %d \n" , state -> y ));
487530
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 ++ ) {
531+ // iterate over each row in the strip and stuff data into image
532+ for (strip_row = 0 ; strip_row < min ((INT32 ) rows_per_strip , state -> ysize - state -> y ); strip_row ++ ) {
490533 TRACE (("Writing data into line %d ; \n" , state -> y + strip_row ));
491534
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]));
535+ // UINT8 * bbb = state->buffer + strip_row * (state->bytes / rows_per_strip);
536+ // TRACE(("chars: %x %x %x %x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3]));
537+
538+ shuffler ((UINT8 * ) im -> image [state -> y + state -> yoff + strip_row ] +
539+ state -> xoff * im -> pixelsize ,
540+ state -> buffer + strip_row * row_byte_size ,
541+ state -> xsize );
542+ }
543+ }
544+ }
545+ }
546+
547+
548+ // Check if raw mode was RGBa and it was stored on separate planes
549+ // so we have to convert it to RGBA
550+ if (planes > 3 && strcmp (im -> mode , "RGBA" ) == 0 ) {
551+ uint16 extrasamples ;
552+ uint16 * sampleinfo ;
553+ ImagingShuffler shuffle ;
554+ INT32 y ;
555+
556+ TIFFGetFieldDefaulted (tiff , TIFFTAG_EXTRASAMPLES , & extrasamples , & sampleinfo );
557+
558+ if (extrasamples >= 1 &&
559+ (sampleinfo [0 ] == EXTRASAMPLE_UNSPECIFIED || sampleinfo [0 ] == EXTRASAMPLE_ASSOCALPHA )
560+ ) {
561+ shuffle = ImagingFindUnpacker ("RGBA" , "RGBa" , NULL );
562+
563+ for (y = state -> yoff ; y < state -> ysize ; y ++ ) {
564+ UINT8 * ptr = (UINT8 * ) im -> image [y + state -> yoff ] +
565+ state -> xoff * im -> pixelsize ;
494566
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 );
567+ shuffle (ptr , ptr , state -> xsize );
499568 }
500569 }
501570 }
0 commit comments