| AWARE [SYSTEMS] | Imaging expertise for the Delphi developer | |||||||
![]() |
TIFF and LibTiff Mailing List Archive | |||||||
LibTiff Mailing List
TIFF and LibTiff Mailing List Archive Contact
The TIFF Mailing List Homepage |
Thread2008.11.10 18:40 "Writing scanlines with PLANARCONFIG == SEPARATE", by Richard NoldeI've managed to get tiffcrop to support reading and writing TIFF files
with bit depths from 1 to 32 for RGB files but there appears to be a
limitation in the library that only it can only support PLANNARCONFIG ==
SEPARATE if the strips are organized with all the scanlines for a given
sample packed into one or more strips before any scanlines for the next
sample are written, eg:
Strip1
Scanline1 RRRRRRRRRRRR
Scanline2 RRRRRRRRRRRR
...
ScanlineN RRRRRRRRRRRR
Strip2
ScanlineN + 1 RRRRRRRRRRRR
ScanlineN + 2 RRRRRRRRRRRR
Strip3
Scanline1 GGGGGGGGGGG
Scanline2 GGGGGGGGGGG
...
ScanlineN GGGGGGGGGGG
Strip4
ScanlineN + 1 GGGGGGGGGG
ScanlineN + 2 GGGGGGGGGG
Strip5
Scanline1 BBBBBBBBBBBB
Scanline2 BBBBBBBBBBBB
....
ScanlineN BBBBBBBBBBBB
Strip6
Scanline N + 1 BBBBBBBBBB
Scanline N + 2 BBBBBBBBBB
I think this is due to the following code in tif_write.c, and/or other
places that setup the stripsperimage value and he stripbytecounts for
each strip.
tif_write.c
...
int
TIFFWriteScanline(TIFF* tif, tdata_t buf, uint32 row, tsample_t sample)
/*
* Calculate strip and check for crossings.
*/
if (td->td_planarconfig == PLANARCONFIG_SEPARATE) {
if (sample >= td->td_samplesperpixel) {
TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
"%d: Sample out of range, max %d",
sample, td->td_samplesperpixel);
return (-1);
}
strip = sample*td->td_stripsperimage + row/td->td_rowsperstrip;
} else
strip = row / td->td_rowsperstrip;
/*
* Check strip array to make sure there's space. We don't support
* dynamically growing files that have data organized in separate
* bitplanes because it's too painful. In that case we require that
* the imagelength be set properly before the first write (so that the
* strips array will be fully allocated above).
*/
if (strip >= td->td_nstrips && !TIFFGrowStrips(tif, 1, module))
return (-1);
if (strip != tif->tif_curstrip) {
/*
* Changing strips -- flush any data present.
*/
if (!TIFFFlushData(tif))
return (-1);
tif->tif_curstrip = strip;
/*
* Watch out for a growing image. The value of strips/image
* will initially be 1 (since it can't be deduced until the
* imagelength is known).
*/
if (strip >= td->td_stripsperimage && imagegrew)
td->td_stripsperimage =
TIFFhowmany(td->td_imagelength,td->td_rowsperstrip);
tif->tif_row =
(strip % td->td_stripsperimage) * td->td_rowsperstrip;
if ((tif->tif_flags & TIFF_CODERSETUP) == 0) {
if (!(*tif->tif_setupencode)(tif))
return (-1);
tif->tif_flags |= TIFF_CODERSETUP;
}
tif->tif_rawcc = 0;
tif->tif_rawcp = tif->tif_rawdata;
if( td->td_stripbytecount[strip] > 0 )
{
/* if we are writing over existing tiles, zero length */
td->td_stripbytecount[strip] = 0;
/* this forces TIFFAppendToStrip() to do a seek */
tif->tif_curoff = 0;
}
....
Since the data are compressed/stored on a per scanline basis, I wanted
to write the data for each sample of a given row of the image to
successive scan lines within one strip to speed up access when only a
part of the image is being used.
Strip 1
Scanline 1 RRRRRRRRR
Scanline 2 GGGGGGGG
Scanline 3 BBBBBBBBB
The current code in tif_write.c computes a strip value of 0, 3, 6 for
samples 0, 1, 2 in the initial row of my test image, but it zeroes the
stripbyte count every time it gets to the code at the end of the excerpt
above, which makes the resulting file invalid. Looking at the
StripOffsetts, there are nine values at 3 * ImageWidth apart even though
the debugger shows a value of three stripsperimage when inside this
function (at least for the first few rows of the image).
(gdb) p td->td_stripsperimage
$88 = 3
At the end of the three passes through TIFFWriteScanline for the first
row, the following strip byte counts were shown
(gdb) p *td->td_stripbytecount@9
$91 = {73, 0, 0, 73, 0, 0, 73, 0, 0}
but the fourth iteration of the function for sample 0 of row two reset
the strip byte count for the first strip to zero before writing out that
sample.
(gdb) p *td->td_stripbytecount@9
$91 = {0, 0, 0, 73, 0, 0, 73, 0, 0}
tiffdump
/tmp/tiger-rgb-strip-planar-08.tiff/tmp/tiger-rgb-strip-planar-08.tiff:
Magic: 0x4949 <little-endian> Version: 0x2a
Directory 0: offset 666 (0x29a) next 0 (0)
ImageWidth (256) SHORT (3) 1<73>
ImageLength (257) SHORT (3) 1<76>
BitsPerSample (258) SHORT (3) 3<8 8 8>
Compression (259) SHORT (3) 1<1>
Photometric (262) SHORT (3) 1<2>
DocumentName (269) ASCII (2) 30<tiger-rgb-strip-contig-0 ...>
ImageDescription (270) ASCII (2) 53< Image generated by GPL ...>
StripOffsets (273) LONG (4) 9<8 227 446 81 300 519 154 373 592>
Orientation (274) SHORT (3) 1<1>
SamplesPerPixel (277) SHORT (3) 1<3>
RowsPerStrip (278) SHORT (3) 1<37>
StripByteCounts (279) LONG (4) 9<0 0 0 0 0 0 0 0 0>
XResolution (282) RATIONAL (5) 1<72>
YResolution (283) RATIONAL (5) 1<72>
PlanarConfig (284) SHORT (3) 1<2>
ResolutionUnit (296) SHORT (3) 1<1>
PageNumber (297) SHORT (3) 2<1 0>
Software (305) ASCII (2) 65<GraphicsMagick 1.3 unrel ...>
SampleFormat (339) SHORT (3) 3<1 1 1>
Question 1: Is it valid to write scanlines (each scanline containing
only values of one sample plane) interleaved by sample within a single
strip of a TIFF image for PLANNARCONFIG SEPARATE?
Question 2 Is there anyway to do this within the current configuration
of libtiff?
Question 3 Can libtiff be modified to handle this option without
breaking existing applications?
Richard Nolde
tiffcrop author
|
|||||||