2014.12.27 23:06 "[Tiff] [PATCH] tiff2ps: fix grayscale with unassociated alpha (and other extrasamples != 0)", by Yuriy M. Kaminskiy

2014.12.27 22:30 "[Tiff] [PATCH] tiff2pdf fixes for grayscale (min-is-white/black) and alpha", by Yuriy M. Kaminskiy

Samples to test:

https://bugs.debian.org/cgi-bin/bugreport.cgi?msg=21;filename=test1s3.tiff;att=1;bug=611141

(from https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=611141)
and

https://bugs.debian.org/cgi-bin/bugreport.cgi?msg=5;filename=doc673.tif.126;att=5;bug=552382

(from https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=552382)

(both bugs are about tiff2ps [patch will be posted separately], but also exposes

bug in tiff2pdf).

From: Yuriy M. Kaminskiy <yumkam@gmail.com>

Subject: Disable compression passthrough when sample conversion requested

It is not possible to use passthrough compression when

conversion from separate to contig or drop alpha is requested.

Index: tiff-3.9.4/tools/tiff2pdf.c
===================================================================

--- tiff-3.9.4.orig/tools/tiff2pdf.c    2014-12-27 19:36:10.552594211 +0300

+++ tiff-3.9.4/tools/tiff2pdf.c 2014-12-27 23:40:32.708095195 +0300
@@ -1700,7 +1700,7 @@ void t2p_read_tiff_data(T2P* t2p, TIFF*
        t2p_compose_pdf_page(t2p);

       t2p->pdf_transcode = T2P_TRANSCODE_ENCODE;

-       if(t2p->pdf_nopassthrough==0){
+       if(t2p->pdf_nopassthrough==0 && t2p->pdf_sample == T2P_SAMPLE_NOTHING){

#ifdef CCITT_SUPPORT
               if(t2p->tiff_compression==COMPRESSION_CCITTFAX4
                       ){

Yuriy M. Kaminskiy <yumkam@gmail.com>

Subject: tiff2pdf: fix combination of SEPARATE to CONTIG conversion with other sample format conversions (dropping alpha/etc)

Index: tiff-3.9.4/tools/tiff2pdf.c
===================================================================

--- tiff-3.9.4.orig/tools/tiff2pdf.c    2014-12-27 19:36:10.552594211 +0300

+++ tiff-3.9.4/tools/tiff2pdf.c 2014-12-27 23:40:32.708095195 +0300
@@ -1649,7 +1649,7 @@ void t2p_read_tiff_data(T2P* t2p, TIFF*
                        case PLANARCONFIG_CONTIG:
                                break;
                        case PLANARCONFIG_SEPARATE:
- t2p->pdf_sample=T2P_SAMPLE_PLANAR_SEPARATE_TO_CONTIG;
+ t2p->pdf_sample |= T2P_SAMPLE_PLANAR_SEPARATE_TO_CONTIG;
                                if(t2p->tiff_bitspersample!=8){
                                        TIFFError(
                                                TIFF2PDF_MODULE,
@@ -2898,7 +2962,7 @@ tsize_t t2p_readwrite_pdf_image_tile(T2P

       } else {

-               if(t2p->pdf_sample == T2P_SAMPLE_PLANAR_SEPARATE_TO_CONTIG){
+               if(t2p->pdf_sample & T2P_SAMPLE_PLANAR_SEPARATE_TO_CONTIG){

                       septilesize=TIFFTileSize(input);
                       septilecount=TIFFNumberOfTiles(input);
                       tilesize=septilesize*t2p->tiff_samplesperpixel;

Yuriy M. Kaminskiy <yumkam@gmail.com>

Subject: tiff2pdf: fix/add support for grayscale-alpha formats

Index: tiff-3.9.4/tools/tiff2pdf.c
===================================================================

--- tiff-3.9.4.orig/tools/tiff2pdf.c    2014-12-27 19:36:10.552594211 +0300

+++ tiff-3.9.4/tools/tiff2pdf.c 2014-12-27 23:40:32.708095195 +0300
@@ -94,6 +94,8 @@ typedef enum{
        T2P_SAMPLE_ABGR_TO_RGB=0x0001, /* The unencoded samples are the result of ReadRGBAImage */
        T2P_SAMPLE_RGBA_TO_RGB=0x0002, /* The unencoded samples are contiguous RGBA */
        T2P_SAMPLE_RGBAA_TO_RGB=0x0004, /* The unencoded samples are RGBA with premultiplied alpha */

+       T2P_SAMPLE_GRAYA_TO_GRAY=0x0200, /* The unencoded samples are contiguous Min-is-* */
+       T2P_SAMPLE_GRAYAA_TO_GRAY=0x0400, /* The unencoded samples are Min-is-* with premultiplied alpha */

        T2P_SAMPLE_YCBCR_TO_RGB=0x0008,
        T2P_SAMPLE_YCBCR_TO_LAB=0x0010,
        T2P_SAMPLE_REALIZE_PALETTE=0x0020, /* The unencoded samples are indexes into the color map */
@@ -274,6 +277,8 @@ tsize_t t2p_sample_realize_palette(T2P*,
 tsize_t t2p_sample_abgr_to_rgb(tdata_t, uint32);
 tsize_t t2p_sample_rgba_to_rgb(tdata_t, uint32);
 tsize_t t2p_sample_rgbaa_to_rgb(tdata_t, uint32);
+tsize_t t2p_sample_graya_to_gray(tdata_t, uint32);
+tsize_t t2p_sample_grayaa_to_gray(tdata_t, uint32);
 tsize_t t2p_sample_lab_signed_to_unsigned(tdata_t, uint32);
 tsize_t t2p_write_pdf_header(T2P*, TIFF*);
 tsize_t t2p_write_pdf_obj_start(uint32, TIFF*);
@@ -1415,6 +1425,32 @@ void t2p_read_tiff_data(T2P* t2p, TIFF*
                                        t2p->pdf_switchdecode ^= 1;
                                }
                        }

+                       if(t2p->tiff_samplesperpixel == 1){
+                               break;
+                       }
+                       if(t2p->tiff_samplesperpixel > 1) {
+                               if(t2p->tiff_samplesperpixel == 2) {
+                                       if(TIFFGetField(input,
+                                                       TIFFTAG_EXTRASAMPLES,
+                                                       &xuint16, &xuint16p)
+                                          && xuint16 == 1) {
+                                               if(xuint16p[0] == EXTRASAMPLE_ASSOCALPHA){
+                                                       t2p->pdf_sample=T2P_SAMPLE_GRAYAA_TO_GRAY;
+                                                       break;
+                                               }
+                                               if(xuint16p[0] == EXTRASAMPLE_UNASSALPHA){
+                                                       t2p->pdf_sample=T2P_SAMPLE_GRAYA_TO_GRAY;
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+                       TIFFError(
+                               TIFF2PDF_MODULE,
+                               "No support for grayscale image %s with %u samples per pixel",
+                               TIFFFileName(input),
+                               t2p->tiff_samplesperpixel);
+                       t2p->t2p_error = T2P_ERR_ERROR;
                        break;
                case PHOTOMETRIC_RGB: 
                        t2p->pdf_colorspace=T2P_CS_RGB;
@@ -2536,6 +2588,18 @@ tsize_t t2p_readwrite_pdf_image(T2P* t2p
                                t2p->tiff_width*t2p->tiff_length);
                }

+               if(t2p->pdf_sample & T2P_SAMPLE_GRAYA_TO_GRAY){
+                       t2p->tiff_datasize=t2p_sample_graya_to_gray(
+                               (tdata_t)buffer,
+                               t2p->tiff_width*t2p->tiff_length);
+               }
+
+               if(t2p->pdf_sample & T2P_SAMPLE_GRAYAA_TO_GRAY){
+                       t2p->tiff_datasize=t2p_sample_grayaa_to_gray(
+                               (tdata_t)buffer,
+                               t2p->tiff_width*t2p->tiff_length);
+               }
+
                if(t2p->pdf_sample & T2P_SAMPLE_YCBCR_TO_RGB){
                        samplebuffer=(unsigned char*)_TIFFrealloc(
                                (tdata_t)buffer, 
@@ -2992,6 +3056,20 @@ tsize_t t2p_readwrite_pdf_image_tile(T2P
                                *t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength);
                }

+               if(t2p->pdf_sample & T2P_SAMPLE_GRAYA_TO_GRAY){
+                       t2p->tiff_datasize=t2p_sample_graya_to_gray(
+                               (tdata_t)buffer,
+                               t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth
+                               *t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength);
+               }
+
+               if(t2p->pdf_sample & T2P_SAMPLE_GRAYAA_TO_GRAY){
+                       t2p->tiff_datasize=t2p_sample_grayaa_to_gray(
+                               (tdata_t)buffer,
+                               t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth
+                               *t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength);
+               }
+
                if(t2p->pdf_sample & T2P_SAMPLE_YCBCR_TO_RGB){
                        TIFFError(TIFF2PDF_MODULE, 
                                "No support for YCbCr to RGB in tile for %s", 
@@ -3649,6 +3727,41 @@ t2p_sample_rgba_to_rgb(tdata_t data, uin

}

 /*
+ * This functions converts in place a buffer of GRAYA interleaved data
+ * into GRAY interleaved data, discarding A.
+ */
+
+tsize_t
+t2p_sample_grayaa_to_gray(tdata_t data, uint32 samplecount)
+{
+       uint32 i;
+
+       for(i = 0; i < samplecount; i++)
+               ((uint8 *)data)[i] = ((uint8*)data)[i*2];
+
+       return i;
+}
+
+/*
+ * This functions converts in place a buffer of GRAYA interleaved data
+ * into GRAY interleaved data, adding 255-A to each component sample.
+ */
+
+tsize_t
+t2p_sample_graya_to_gray(tdata_t data, uint32 samplecount)
+{
+       uint32 i = 0;
+       uint8 alpha = 0;
+
+       for (i = 0; i < samplecount; i++) {
+               alpha= 255 - (((uint8 *)data)[i*2+1] & 0xff);
+               ((uint8 *)data)[i] = (((uint8 *)data)[i*2] & 0xff) + alpha;
+       }
+
+       return i;
+}
+
+/*

       This function converts the a and b samples of Lab data from signed
       to unsigned.
*/

Yuriy M. Kaminskiy <yumkam@gmail.com>

Subject: tiff2pdf: fix number of decoded components

/Decode array was incorrect for case when alpha was cropped.

Index: tiff-3.9.4/tools/tiff2pdf.c
===================================================================

--- tiff-3.9.4.orig/tools/tiff2pdf.c    2014-12-27 19:36:10.552594211 +0300

+++ tiff-3.9.4/tools/tiff2pdf.c 2014-12-27 23:40:32.708095195 +0300

@@ -5078,10 +5191,15 @@ tsize_t t2p_write_pdf_xobject_palettecs_ tsize_t t2p_write_pdf_xobject_decode(T2P* t2p, TIFF* output){

        tsize_t written=0;
-       int i=0;
+       int i=t2p->tiff_samplesperpixel;

+       if ((t2p->pdf_sample & (T2P_SAMPLE_GRAYA_TO_GRAY |
+                               T2P_SAMPLE_GRAYAA_TO_GRAY |
+                               T2P_SAMPLE_RGBA_TO_RGB |
+                               T2P_SAMPLE_RGBAA_TO_RGB)))

+               i--;
        written += t2pWriteFile(output, (tdata_t) "/Decode [ ", 10);
-       for (i=0;i<t2p->tiff_samplesperpixel;i++){
+       while(i-- > 0){
                written += t2pWriteFile(output, (tdata_t) "1 0 ", 4);
        }
        written += t2pWriteFile(output, (tdata_t) "]\n", 2);

Yuriy M. Kaminskiy <yumkam@gmail.com>

Subject: tiff2pdf: short-circuit unassociated alpha cropping and PLANARCONFIG_SEPARATE decoding

In grayscale case, it is possible to completely avoid decoding and enables use of passthrough compression.

In RGB case, just integrate alpha dropping into separate->contig step

Index: tiff-3.9.4/tools/tiff2pdf.c
===================================================================

--- tiff-4.0.x-20141215.orig/tools/tiff2pdf.c   2014-12-27 19:36:10.552594211 +0300
+++ tiff-4.0.x-20141215/tools/tiff2pdf.c        2014-12-27 23:40:32.708095195 +0300

@@ -153,6 +155,7 @@ typedef struct {

        uint16 tiff_fillorder;
        uint16 tiff_bitspersample;
        uint16 tiff_samplesperpixel;
+       uint16 tiff_strips;
        uint16 tiff_planar;
        uint32 tiff_width;
        uint32 tiff_length;

@@ -1179,7 +1184,7 @@ void t2p_read_tiff_init(T2P* t2p, TIFF*
                         if( (xuint16== COMPRESSION_DEFLATE ||
                              xuint16== COMPRESSION_ADOBE_DEFLATE) &&
                             ((t2p->tiff_pages[i].page_tilecount != 0)

-                             || TIFFNumberOfStrips(input)==1) &&
+                             || t2p->tiff_strips==1) &&

                             (t2p->pdf_nopassthrough==0) ){
                                 if(t2p->pdf_minorversion<2){t2p->pdf_minorversion=2;}
                         }
@@ -1400,7 +1405,12 @@ void t2p_read_tiff_data(T2P* t2p, TIFF*
                 return;

        }

+       if (TIFFIsTiled(input))
+           t2p->tiff_strips = 1;
+       else
+           t2p->tiff_strips = TIFFNumberOfStrips(input);

+
        switch(t2p->tiff_photometric){
                case PHOTOMETRIC_MINISWHITE:
                case PHOTOMETRIC_MINISBLACK:
@@ -1649,7 +1685,23 @@ void t2p_read_tiff_data(T2P* t2p, TIFF*
                        case PLANARCONFIG_CONTIG:
                                break;
                        case PLANARCONFIG_SEPARATE:

+                               if (t2p->tiff_planar == PLANARCONFIG_SEPARATE
+                                   && (t2p->pdf_sample & (T2P_SAMPLE_RGBA_TO_RGB | T2P_SAMPLE_GRAYA_TO_GRAY))) {
+                                       /* just crop alpha strip/tile */
+                                       if (TIFFIsTiled(input))
+                                               t2p->tiff_pages[t2p->pdf_page].page_tilecount = (t2p->tiff_pages[t2p->pdf_page].page_tilecount/t2p->tiff_samplesperpixel) * (t2p->tiff_samplesperpixel - 1);
+                                       else
+                                               t2p->tiff_strips = (t2p->tiff_strips / t2p->tiff_samplesperpixel) * (t2p->tiff_samplesperpixel - 1);
+                                       t2p->tiff_samplesperpixel--;
+                                       if ((t2p->pdf_sample & T2P_SAMPLE_GRAYA_TO_GRAY)) {
+                                               /* skip conversion to GRAY */
+                                               t2p->tiff_planar = PLANARCONFIG_CONTIG;
+                                               t2p->pdf_sample &= ~T2P_SAMPLE_GRAYA_TO_GRAY;
+                                               break;
+                                       }
+                                       t2p->pdf_sample &= ~T2P_SAMPLE_RGBA_TO_RGB;
+                               }
                                t2p->pdf_sample |= T2P_SAMPLE_PLANAR_SEPARATE_TO_CONTIG;

                                if(t2p->tiff_bitspersample!=8){
                                        TIFFError(
                                                TIFF2PDF_MODULE,
@@ -1705,6 +1757,6 @@ void t2p_read_tiff_data(T2P* t2p, TIFF*
                if(t2p->tiff_compression==COMPRESSION_CCITTFAX4
                        ){

-                       if(TIFFIsTiled(input) || (TIFFNumberOfStrips(input)==1) ){
+                       if(/*TIFFIsTiled(input) || */(t2p->tiff_strips==1) ){

                                t2p->pdf_transcode = T2P_TRANSCODE_RAW;
                                t2p->pdf_compression=T2P_COMPRESS_G4;
                        }
@@ -1713,7 +1765,7 @@ void t2p_read_tiff_data(T2P* t2p, TIFF*
 #ifdef ZIP_SUPPORT
                if(t2p->tiff_compression== COMPRESSION_ADOBE_DEFLATE

                        || t2p->tiff_compression==COMPRESSION_DEFLATE){
-                       if(TIFFIsTiled(input) || (TIFFNumberOfStrips(input)==1) ){
+                       if(/*TIFFIsTiled(input) || */(t2p->tiff_strips==1) ){

                                t2p->pdf_transcode = T2P_TRANSCODE_RAW;
                                t2p->pdf_compression=T2P_COMPRESS_ZIP;
                        }
@@ -1884,7 +1936,7 @@ void t2p_read_tiff_size(T2P* t2p, TIFF*
                                t2p->t2p_error = T2P_ERR_ERROR;
                                return;
                        }
- stripcount=TIFFNumberOfStrips(input);
+ stripcount=t2p->tiff_strips;
                        for(i=0;i<stripcount;i++){
                                k = checkAdd64(k, sbc[i], t2p);
                        }
@@ -1939,7 +1991,7 @@ void t2p_read_tiff_size(T2P* t2p, TIFF*
                        } else {
                                k = 2; /* SOI for first strip */
                        }
- stripcount=TIFFNumberOfStrips(input);
+ stripcount=t2p->tiff_strips;
                        if(!TIFFGetField(input, TIFFTAG_STRIPBYTECOUNTS, &sbc)){
                                TIFFError(TIFF2PDF_MODULE,
                                        "Input file %s missing field: TIFFTAG_STRIPBYTECOUNTS",
@@ -2258,7 +2310,7 @@ tsize_t t2p_readwrite_pdf_image(T2P* t2p
                                        ri*=(rows+v_samp-1)/v_samp;
                                        buffer[bufferoffset++]= (ri>>8) & 0xff;

                                        buffer[bufferoffset++]= ri & 0xff;
-                                       stripcount=TIFFNumberOfStrips(input);
+                                       stripcount=t2p->tiff_strips;
                                        for(i=0;i<stripcount;i++){

                                                if(i != 0 ){
                                                        buffer[bufferoffset++]=0xff;
@@ -2294,7 +2346,7 @@ tsize_t t2p_readwrite_pdf_image(T2P* t2p
                                 memset(buffer, 0, t2p->tiff_datasize);
                                _TIFFmemcpy(buffer, t2p->pdf_ojpegdata, t2p->pdf_ojpegdatalength);

                                bufferoffset=t2p->pdf_ojpegdatalength;
-                               stripcount=TIFFNumberOfStrips(input);
+                               stripcount=t2p->tiff_strips;

                                for(i=0;i<stripcount;i++){
                                        if(i != 0){
                                                buffer[bufferoffset++]=0xff;
@@ -2341,7 +2393,7 @@ tsize_t t2p_readwrite_pdf_image(T2P* t2p
                                        bufferoffset += count - 2;
                                }
                        }
- stripcount=TIFFNumberOfStrips(input);
+ stripcount=t2p->tiff_strips;
                        TIFFGetField(input, TIFFTAG_STRIPBYTECOUNTS, &sbc);
                        for(i=0;i<stripcount;i++){
                                if(sbc[i]>max_striplength) max_striplength=sbc[i];
@@ -2398,7 +2450,7 @@ tsize_t t2p_readwrite_pdf_image(T2P* t2p
                }
                 memset(buffer, 0, t2p->tiff_datasize);
                stripsize=TIFFStripSize(input);
- stripcount=TIFFNumberOfStrips(input);
+ stripcount=t2p->tiff_strips;
                for(i=0;i<stripcount;i++){
                        read =
                                TIFFReadEncodedStrip(input,
@@ -2420,7 +2472,7 @@ tsize_t t2p_readwrite_pdf_image(T2P* t2p
                if(t2p->pdf_sample & T2P_SAMPLE_PLANAR_SEPARATE_TO_CONTIG){

                        sepstripsize=TIFFStripSize(input);
-                       sepstripcount=TIFFNumberOfStrips(input);
+                       sepstripcount=t2p->tiff_strips;

                        stripsize=sepstripsize*t2p->tiff_samplesperpixel;
                        stripcount=sepstripcount/t2p->tiff_samplesperpixel;
@@ -2485,7 +2537,7 @@ tsize_t t2p_readwrite_pdf_image(T2P* t2p
                }
                 memset(buffer, 0, t2p->tiff_datasize);
                stripsize=TIFFStripSize(input);
- stripcount=TIFFNumberOfStrips(input);
+ stripcount=t2p->tiff_strips;
                for(i=0;i<stripcount;i++){
                        read =
                                TIFFReadEncodedStrip(input,
@@ -2898,7 +2962,7 @@ tsize_t t2p_readwrite_pdf_image_tile(T2P

               if(t2p->pdf_sample & T2P_SAMPLE_PLANAR_SEPARATE_TO_CONTIG){
                       septilesize=TIFFTileSize(input);

-                       septilecount=TIFFNumberOfTiles(input);
+                       septilecount=t2p->tiff_pages[t2p->pdf_page].page_tilecount;
                        /* tilesize=septilesize*t2p->tiff_samplesperpixel; */

                        tilecount=septilecount/t2p->tiff_samplesperpixel;
                        buffer = (unsigned char*) _TIFFmalloc(t2p->tiff_datasize);
@@ -3342,7 +3420,7 @@ int t2p_process_ojpeg_tables(T2P* t2p, T
                        t2p->pdf_ojpegdatalength+=code_count;
                }
        }
- if(TIFFNumberOfStrips(input)>1){
+ if(t2p->tiff_strips>1){
                ojpegdata[t2p->pdf_ojpegdatalength++]=0xff;
                ojpegdata[t2p->pdf_ojpegdatalength++]=0xdd;
                ojpegdata[t2p->pdf_ojpegdatalength++]=0x00;

Yuriy M. Kaminskiy <yumkam@gmail.com>

Subject: tiff2pdf: move/simplify pdf_switchdecode toggle

Index: tiff-3.9.4/tools/tiff2pdf.c
===================================================================

--- tiff-3.9.4.orig/tools/tiff2pdf.c    2014-12-28 00:58:45.560598630 +0300

+++ tiff-3.9.4/tools/tiff2pdf.c 2014-12-28 01:01:33.744598722 +0300

@@ -1413,17 +1413,13 @@ void t2p_read_tiff_data(T2P* t2p, TIFF*

       switch(t2p->tiff_photometric){
               case PHOTOMETRIC_MINISWHITE:

+                       t2p->pdf_switchdecode ^= 1;
+                       /* fallthrough */

               case PHOTOMETRIC_MINISBLACK:
                       if (t2p->tiff_bitspersample==1){
                               t2p->pdf_colorspace=T2P_CS_BILEVEL;

- }
                        } else {
                                t2p->pdf_colorspace=T2P_CS_GRAY;

- }
                        }
                        if(t2p->tiff_samplesperpixel == 1){
                                break;