2004.06.23 10:31 "[Tiff] Tiff JpegCompression 12-bit", by Albert Adell

Hi all,

During some weeks I have been trying to read and to write TIFF 8-bits and 12-bits (true 16) Tiled JpegCompressed Files by using LibTiff 3.6.1 and IJG JpegLib v6b. At least for the 12 bits images that I have, and some other that I found by Internet I reached a possible solution. I hope this can help to someone that could be at the same trouble.

- Read/Write 8-bits TIFF Files with JPEG compression is direct, thanks to the TIFF-JPEG tiff_jpeg.c interface.

- Generate TIFF 8-12 bits JPEG compression files by giving simultaneous support was not possible at the beginning, due to the fact that the JPEG library supports both, but NOT at once. It can be worked around by:

For example:

TiffLib::tiff_jpeg.c::JPEGSetupEncode(TIFF* tif)
        ...
        //#define CALLJPEG(sp, fail, op)        (SETJMP((sp)->exit_jmpbuf) ? (fail) : (op))
        //#define CALLVJPEG(sp, op)             CALLJPEG(sp, 0, ((op),1))

        #define CALLJPEGX(sp, fail, op)         (SETJMP((sp)->exit_jmpbuf) ? (fail) : (op))

        #define CALLJPEG8(sp, fail, op, params) CALLJPEGX(sp, fail, op##params)
        #define CALLJPEG12(sp, fail, op,params) CALLJPEGX(sp, fail, op##12##params)
        #define CALLJPEG(sp, fail, op, params) (sp->tif->tif_dir.td_bitspersample==12 ? CALLJPEG12(sp, fail, op, params) : CALLJPEG8(sp, fail, op, params))

        #define CALLVJPEG8(sp, op, params)      CALLJPEGX(sp, 0, ((op##params),1))
        #define CALLVJPEG12(sp, op, params)     CALLJPEGX(sp, 0, ((op##12##params),1))
        #define CALLVJPEG(sp, op, params) (sp->tif->tif_dir.td_bitspersample==12 ? CALLVJPEG12(sp, op, params) : CALLVJPEG8(sp, op, params))
        ...

TiffLib::tiff_jpeg.c::JPEGSetupEncode(TIFF* tif)
        ...
        //if (td->td_bitspersample != BITS_IN_JSAMPLE) {
        if (td->td_bitspersample != 8 && td->td_bitspersample != 12) {
        ..

- Apart from the previous point, the 12-bits compression is not correctly supported by LibTiff. There is a recognized bug at (http://bugzilla.remotesensing.org/show_bug.cgi?id=451). it can not read, neither write directly this file format. A possible solution:

Reading: could be done by modifying the TIFF library, where the computation of the number of tiles and strips (in bytes) of the is done. The problem was that the size returned in bytes was incorrectly computed, without taking on count that the data were packed in 16 bits, not in 12. For that the number in bytes was fewer that the real one.

TiffLib::tiff_tile.c::TIFFTileRowSize
        ..
        //rowsize = td->td_bitspersample * td->td_tilewidth;
        bitspersample = (td->td_bitspersample<=8 || td->td_bitspersample%8==0) ? td->td_bitspersample : (td->td_bitspersample/8 + 1)*8;
        rowsize = bitspersample * td->td_tilewidth;
        ..
TiffLib::tiff_tile.c::TIFFVTileSize
        ...
        //tsize_t rowsize = TIFFhowmany(w*td->td_bitspersample, 8);
        tsize_t bitspersample = (td->td_bitspersample<=8 || td->td_bitspersample%8==0) ? td->td_bitspersample : (td->td_bitspersample/8 + 1)*8;
        tsize_t rowsize = TIFFhowmany(w*bitspersample, 8);
        ...
TiffLib::tiff_strip.c::TIFFScanlineSize
        ...
        //scanline = td->td_bitspersample * td->td_imagewidth;
        bitspersample = (td->td_bitspersample<=8 || td->td_bitspersample%8==0) ? td->td_bitspersample : (td->td_bitspersample/8 + 1)*8;
        scanline = bitspersample * td->td_imagewidth;
        ...
TiffLib::tiff_strip.c::TIFFRasterScanlineSize
        ...
        //scanline = td->td_bitspersample * td->td_imagewidth;
        bitspersample = (td->td_bitspersample<=8 || td->td_bitspersample%8==0) ? td->td_bitspersample : (td->td_bitspersample/8 + 1)*8;
        scanline = bitspersample * td->td_imagewidth;
        ...
TiffLib::tiff_strip.c::TIFFVStripSize
        ...
        //scanline = TIFFhowmany(w*td->td_bitspersample, 8);
        bitspersample = (td->td_bitspersample<=8 || td->td_bitspersample%8==0) ? td->td_bitspersample : (td->td_bitspersample/8 + 1)*8;
        scanline = TIFFhowmany(w*bitspersample, 8);
        ...

Writing: The problem was when creating the Huffman tables at the IJG JpegLib library, causing a "Missing Huffman code table entry" error due to the fact that the file tiff_jpeg.c did not set up correctly the above mentioned library at the 12-bits case. This can be solved by modifying the JPEGPreEncode call

TiffLib::tiff_jpeg.c::JPEGPreEncode
        ...
        //if (sp->jpegtablesmode & JPEGTABLESMODE_HUFF)
        //      sp->cinfo.c.optimize_coding = FALSE;
        //else
        //      sp->cinfo.c.optimize_coding = TRUE;
        if ((sp->jpegtablesmode & JPEGTABLESMODE_HUFF) && sp->tif->tif_dir.td_bitspersample == 8)
                sp->cinfo.c.optimize_coding = FALSE;
        else
                sp->cinfo.c.optimize_coding = TRUE;
        ...

Greetings to you all. Saludos a todos.

Albert Adell

_________________________________________________________________________

Albert Adell Fernández              Desenvolupament Fotogrametria Digital
Institut Cartografic de Catalunya   Passeig Santa Madrona 45-51
E-08004 Barcelona                   www http://www.icc.es
_________________________________________________________________________