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:
- generation 2 libraries, each of one with its corresponding settings, changing #defines at compilation time, that able that one or other option could be chosen, also is necessary to change all the identification's calls and the filenames by adding _12 at the name (so now we have two split libraries),
- communicating both options at the tiff_jpeg.c file, basically by modifying the CALLJPEG y CALLVJPEG macros,
- adding the *.h files at both versions and
- reviewing the consistency with the supported compressions.
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
_________________________________________________________________________