2005.05.18 15:38 "[Tiff] Another libtiff+libjpeg problem", by Thom DeCarlo

2005.05.25 10:12 "Re[2]: [Tiff] Another libtiff+libjpeg problem", by Jean-Yves Le Ridant

Sorry about that. I believe the problem is that the CVS-head of libjpeg is broken. All my work was with the MK1-branch. Try checking that out.

As I said to Bob, I prefered restart my job for 8/12 bits from libtiff 3.7.2 so tif_jpeg 1.30, and the "very original ten year old v6b from IJG" ( mainly cause I could'nt.... 'think' in a jpeglib with BITS_IN_JSAMPLE defined as cinfo.data_precision ).

I attach two diff files from tif_jpeg.c, of some job I'have done. The first is a simple fix of some troubles in the EncodeRaw DecodeRaw path.

The second add some support for 12/16 bits support. It's what I use in my own stuff to have Dual (8/12/16) support ( nb: at this point, raw interface is not supported in 12/16 bits)

With the v6b, you get support for 8 or 12/16 depending the build of jpeglib. 16 bit up/down-sampling is a simple 4 bits shift, and that clearly ( in my mind ) reflect what it is at this point: a convenient way to do some tests with 'blind' programs.

Jean-Yves

PS: Do not hesitate if you have questions, but if not in mailing list, allways at this 2 mails jeanyves.leridant@wanadoo.fr and jean-yves.leridant@culture.gouv.fr

--- 372\tif_jpeg.c      2005-03-09 10:49:44.000000000 +0100
+++ mys\tif_jpeg2.c     2005-05-25 11:13:18.781250000 +0200
@@ -136,6 +136,7 @@
        JSAMPARRAY      ds_buffer[MAX_COMPONENTS];
        int             scancount;      /* number of "scanlines" accumulated */
        int             samplesperclump;
+       JSAMPROW  line_work_buf;

        TIFFVGetMethod  vgetparent;     /* super-class method */
        TIFFVSetMethod  vsetparent;     /* super-class method */
@@ -144,11 +145,11 @@
                                        /* pseudo-tag fields */
        void*           jpegtables;     /* JPEGTables tag value, or NULL */
        uint32          jpegtables_length; /* number of bytes in same */
-       int             jpegquality;    /* Compression quality level */
-       int             jpegcolormode;  /* Auto RGB<=>YCbCr convert? */
-       int             jpegtablesmode; /* What to put in JPEGTables */
+       int                     jpegquality;    /* Compression quality level */
+       int                     jpegcolormode;  /* Auto RGB<=>YCbCr convert? */
+       int                     jpegtablesmode; /* What to put in JPEGTables */

-        int             ycbcrsampling_fetched;
+    int         ycbcrsampling_fetched;
        uint32          recvparams;     /* encoded Class 2 session params */
        char*           subaddress;     /* subaddress string */
        uint32          recvtime;       /* time spent receiving (secs) */
@@ -190,6 +191,16 @@
 };
 #define        N(a)    (sizeof (a) / sizeof (a[0]))

+tsize_t TIFFInterleavedRowSize( JPEGState *sp, int width )
+// for 8,12,16 bps, and h_sampling at least 2, no need of howmanies
+{
+
+       uint16 hv_sampling = sp->h_sampling * sp->v_sampling;
+       tsize_t bpl = (width + sp->h_sampling-1)/sp->h_sampling * (hv_sampling + 2);
+       bpl *= sp->tif->tif_dir.td_bitspersample;
+       return ((tsize_t) TIFFhowmany8(bpl));
+}
+
 /*
  * libjpeg interface layer.
  *
@@ -296,10 +307,33 @@
 static int
 TIFFjpeg_write_scanlines(JPEGState* sp, JSAMPARRAY scanlines, int num_lines)
 {
+       int bps=sp->tif->tif_dir.td_bitspersample;
+       assert(num_lines == 1);
+       if (bps==12){
+               int value_pairs = (sp->bytesperline+2)/3;
+               unsigned char *in_ptr = (unsigned char *) scanlines[0];
+               int iPair, result;
+
+               for( iPair = 0; iPair < value_pairs; iPair++, in_ptr += 3 ){
+              JSAMPLE *out_ptr = sp->line_work_buf + iPair * 2;
+                               out_ptr[0]= ( (in_ptr[0]<<4) & 0xff0 ) | ( (in_ptr[1] >> 4) & 0xf );
+                               out_ptr[1]= ( in_ptr[2]&0xff )  | ( (in_ptr[1]<<8) & 0xf00 )  ;
+               }
+               result= CALLJPEG(sp, -1, (int) jpeg_write_scanlines(&sp->cinfo.c, &sp->line_work_buf, (JDIMENSION) num_lines));
+               return result;
+       }
+       if ( bps == 16){
+               int count = sp->bytesperline/2;
+               uint16 *row = (uint16 *) scanlines[0];
+               while ( count-- ) { *row >>= 4 ; row++; }
+       }
        return CALLJPEG(sp, -1, (int) jpeg_write_scanlines(&sp->cinfo.c,
            scanlines, (JDIMENSION) num_lines));
 }

+
+
+
 static int
 TIFFjpeg_write_raw_data(JPEGState* sp, JSAMPIMAGE data, int num_lines)
 {
@@ -334,8 +368,36 @@
 static int
 TIFFjpeg_read_scanlines(JPEGState* sp, JSAMPARRAY scanlines, int max_lines)
 {
-       return CALLJPEG(sp, -1, (int) jpeg_read_scanlines(&sp->cinfo.d,
-           scanlines, (JDIMENSION) max_lines));
+       int bps = sp->tif->tif_dir.td_bitspersample;
+       assert(max_lines==1);
+       if(bps != 12) {
+               int result= CALLJPEG(sp, -1, (int) jpeg_read_scanlines(&sp->cinfo.d, scanlines, (JDIMENSION) max_lines));
+               if (!result || bps==8)
+                       return result;
+               {       /* process a 16 bits line */
+                       int count= sp->bytesperline/2;
+                       uint16 * row = (uint16 *) scanlines[0];
+                       while ( count-- ) { *row <<= 4 ; row++; }
+                       return 1;
+               }
+       }
+       {       /* process 12 bits line */
+               int result;
+               result= CALLJPEG(sp, -1, (int) jpeg_read_scanlines(&sp->cinfo.d, &sp->line_work_buf, (JDIMENSION) max_lines));
+               if (result) {
+                       unsigned char *out_ptr = (unsigned char *) scanlines[0];
+                       JSAMPLE *in_ptr = sp->line_work_buf;
+                       int out_count;
+                        for( out_count=sp->bytesperline ; out_count> 0 ; out_count--, out_ptr += 3, in_ptr += 2 )
+             {
+                 out_ptr[0] = (in_ptr[0] & 0xff0) >> 4;
+                 out_ptr[1] = ((in_ptr[0] & 0xf) << 4) | ((in_ptr[1] & 0xf00) >> 8);
+                                out_count-=2;
+                                if (out_count) out_ptr[2] = ((in_ptr[1] & 0xff) >> 0);
+             }
+               }
+               return result;
+       }
 }

 static int
@@ -615,6 +677,15 @@
        return (1);
 }

+static int alloc_linework12_buffer(JPEGState* sp )
+{
+       int countpairs= (sp->bytesperline+2)/3;
+       JSAMPARRAY buf= TIFFjpeg_alloc_sarray(sp, JPOOL_IMAGE, countpairs * 2, 1);
+       if(buf==NULL) return 0;
+       sp->line_work_buf=buf[0];
+       return 1;
+}
+

 /*
  * JPEG Decoding.
@@ -723,7 +794,7 @@
                TIFFError(module, "Improper JPEG component count");
                return (0);
        }
-       if (sp->cinfo.d.data_precision != td->td_bitspersample) {
+       if ( (sp->cinfo.d.data_precision != td->td_bitspersample) && ! (td->td_bitspersample==16 && BITS_IN_JSAMPLE==12 ) ) {
                TIFFError(module, "Improper JPEG data precision");
                return (0);
        }
@@ -792,6 +863,10 @@
        }
        if (downsampled_output) {
                /* Need to use raw-data interface to libjpeg */
+               if(sp->cinfo.d.data_precision == 12){
+                       TIFFError(module, "Raw mode not supported only for 8 bits mode");
+                       return 0;
+               }
                sp->cinfo.d.raw_data_out = TRUE;
                tif->tif_decoderow = JPEGDecodeRaw;
                tif->tif_decodestrip = JPEGDecodeRaw;
@@ -808,11 +883,14 @@
                return (0);
        /* Allocate downsampled-data buffers if needed */
        if (downsampled_output) {
+               sp->bytesperline= TIFFInterleavedRowSize(sp, segment_width);
                if (!alloc_downsampled_buffers(tif, sp->cinfo.d.comp_info,
                                               sp->cinfo.d.num_components))
                        return (0);
                sp->scancount = DCTSIZE;        /* mark buffer empty */
        }
+       if( tif->tif_dir.td_bitspersample == 12 && ! alloc_linework12_buffer(sp) )
+               return 0;
        return (1);
 }

@@ -859,15 +937,16 @@
 JPEGDecodeRaw(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s)
 {
        JPEGState *sp = JState(tif);
-       tsize_t nrows;
+       JDIMENSION clumps_per_line = sp->cinfo.d.comp_info[1].downsampled_width;
+       int samples_per_clump = sp->samplesperclump;
+       tsize_t nrows= cc / sp->bytesperline;

        /* data is expected to be read in multiples of a scanline */
-       if ( (nrows = sp->cinfo.d.image_height) ) {
-               /* Cb,Cr both have sampling factors 1, so this is correct */
-               JDIMENSION clumps_per_line = sp->cinfo.d.comp_info[1].downsampled_width;
-               int samples_per_clump = sp->samplesperclump;
-
-               do {
+
+       if (cc % sp->bytesperline)
+               TIFFWarning(tif->tif_name, "fractional scanline discarded");
+
+       while( nrows-- ) {
                        jpeg_component_info *compptr;
                        int ci, clumpoffset;

@@ -917,10 +996,9 @@
                            }
                        }
                        ++sp->scancount;
-                       ++tif->tif_row;
+                       tif->tif_row += sp->v_sampling;
                        buf += sp->bytesperline;
                        cc -= sp->bytesperline;
-               } while (--nrows > 0);
        }

         /* Close down the decompressor if done. */
@@ -1051,12 +1129,17 @@
         * depths for different components, or if libjpeg ever supports
         * run-time selection of depth.  Neither is imminent.
         */
-       if (td->td_bitspersample != BITS_IN_JSAMPLE) {
-               TIFFError(module, "BitsPerSample %d not allowed for JPEG",
-                         (int) td->td_bitspersample);
-               return (0);
+       if (td->td_bitspersample != BITS_IN_JSAMPLE ){
+               if ( ! (td->td_bitspersample==16 && BITS_IN_JSAMPLE==12 ) ) {
+                               TIFFError(module, "BitsPerSample %d not allowed for JPEG",
+                                               (int) td->td_bitspersample);
+                               return (0);
+               }
+               else
+                       sp->cinfo.c.data_precision = 12;
        }
-       sp->cinfo.c.data_precision = td->td_bitspersample;
+       else
+               sp->cinfo.c.data_precision = td->td_bitspersample;
        if (isTiled(tif)) {
                if ((td->td_tilelength % (sp->v_sampling * DCTSIZE)) != 0) {
                        TIFFError(module,
@@ -1189,12 +1272,19 @@
                unsuppress_quant_table(sp, 0);
                unsuppress_quant_table(sp, 1);
        }
+       //if( BITS_IN_JSAMPLE == 12) sp->jpegtablesmode &= ( JPEGTABLESMODE_HUFF ^ 0xFFFF );
+       sp->jpegtablesmode &= ( JPEGTABLESMODE_HUFF ^ 0xFFFF );
+       /* for 8 bits also ---> anticipating some "low-speed" complains in 12 bits mode ;-))) */
        if (sp->jpegtablesmode & JPEGTABLESMODE_HUFF)
                sp->cinfo.c.optimize_coding = FALSE;
-       else
+       else
                sp->cinfo.c.optimize_coding = TRUE;
        if (downsampled_input) {
                /* Need to use raw-data interface to libjpeg */
+               if(sp->cinfo.c.data_precision == 12){
+                       TIFFError(module, "Raw mode not supported only for 8 bits mode");
+                       return 0;
+               }
                sp->cinfo.c.raw_data_in = TRUE;
                tif->tif_encoderow = JPEGEncodeRaw;
                tif->tif_encodestrip = JPEGEncodeRaw;
@@ -1211,12 +1301,14 @@
                return (0);
        /* Allocate downsampled-data buffers if needed */
        if (downsampled_input) {
+               sp->bytesperline= TIFFInterleavedRowSize(sp, segment_width);
                if (!alloc_downsampled_buffers(tif, sp->cinfo.c.comp_info,
                                               sp->cinfo.c.num_components))
                        return (0);
        }
        sp->scancount = 0;
-
+       if( tif->tif_dir.td_bitspersample == 12 && ! alloc_linework12_buffer(sp) )
+               return 0;
        return (1);
 }

@@ -1320,8 +1412,7 @@
                                return (0);
                        sp->scancount = 0;
                }
-               if (nrows > 0)
-                       tif->tif_row++;
+               tif->tif_row += sp->v_sampling;
                buf += sp->bytesperline;
        }
        return (1);

--- 372\tif_jpeg.c      2005-03-09 10:49:44.000000000 +0100
+++ mys\tif_jpeg1.c     2005-05-20 14:39:48.500000000 +0200
@@ -190,6 +190,16 @@
 };
 #define        N(a)    (sizeof (a) / sizeof (a[0]))

+tsize_t TIFFInterleavedRowSize( JPEGState *sp, int width )
+// for 8,12,16 bps, and h_sampling at least 2, no need of howmanies
+{
+
+       uint16 hv_sampling = sp->h_sampling * sp->v_sampling;
+       tsize_t bpl = (width + sp->h_sampling-1)/sp->h_sampling * (hv_sampling + 2);
+       bpl *= sp->tif->tif_dir.td_bitspersample;
+       return ((tsize_t) TIFFhowmany8(bpl));
+}
+
 /*
  * libjpeg interface layer.
  *
@@ -808,6 +818,7 @@
                return (0);
        /* Allocate downsampled-data buffers if needed */
        if (downsampled_output) {
+               sp->bytesperline= TIFFInterleavedRowSize(sp, segment_width);
                if (!alloc_downsampled_buffers(tif, sp->cinfo.d.comp_info,
                                               sp->cinfo.d.num_components))
                        return (0);
@@ -859,15 +870,16 @@
 JPEGDecodeRaw(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s)
 {
        JPEGState *sp = JState(tif);
-       tsize_t nrows;
+       JDIMENSION clumps_per_line = sp->cinfo.d.comp_info[1].downsampled_width;
+       int samples_per_clump = sp->samplesperclump;
+       tsize_t nrows= cc / sp->bytesperline;

        /* data is expected to be read in multiples of a scanline */
-       if ( (nrows = sp->cinfo.d.image_height) ) {
-               /* Cb,Cr both have sampling factors 1, so this is correct */
-               JDIMENSION clumps_per_line = sp->cinfo.d.comp_info[1].downsampled_width;
-               int samples_per_clump = sp->samplesperclump;
-
-               do {
+
+       if (cc % sp->bytesperline)
+               TIFFWarning(tif->tif_name, "fractional scanline discarded");
+
+       while( nrows-- ) {
                        jpeg_component_info *compptr;
                        int ci, clumpoffset;

@@ -917,10 +929,9 @@
                            }
                        }
                        ++sp->scancount;
-                       ++tif->tif_row;
+                       tif->tif_row += sp->v_sampling;
                        buf += sp->bytesperline;
                        cc -= sp->bytesperline;
-               } while (--nrows > 0);
        }

         /* Close down the decompressor if done. */
@@ -1211,6 +1222,7 @@
                return (0);
        /* Allocate downsampled-data buffers if needed */
        if (downsampled_input) {
+               sp->bytesperline= TIFFInterleavedRowSize(sp, segment_width);
                if (!alloc_downsampled_buffers(tif, sp->cinfo.c.comp_info,
                                               sp->cinfo.c.num_components))
                        return (0);
@@ -1320,8 +1332,7 @@
                                return (0);
                        sp->scancount = 0;
                }
-               if (nrows > 0)
-                       tif->tif_row++;
+               tif->tif_row += sp->v_sampling;
                buf += sp->bytesperline;
        }
        return (1);