AWARE [SYSTEMS] Imaging expertise for the Delphi developer
AWare Systems, Imaging expertise for the Delphi developer, Home TIFF and LibTiff Mailing List Archive

LibTiff Mailing List

TIFF and LibTiff Mailing List Archive
November 2008

Previous Thread
Next Thread

Previous by Thread
Next by Thread

Previous by Date
Next by Date

Contact

The TIFF Mailing List Homepage
This list is run by Frank Warmerdam
Archive maintained by AWare Systems



Valid HTML 4.01!



Thread

2008.11.10 18:40 "Writing scanlines with PLANARCONFIG == SEPARATE", by Richard Nolde
2008.11.11 16:54 "Re: Writing scanlines with PLANARCONFIG == SEPARATE", by Ed Grissom
2008.11.11 17:17 "Re: Writing scanlines with PLANARCONFIG == SEPARATE", by Richard Nolde
2008.11.11 17:28 "Error in initial post for PLANARCONFIG == SEPARATE", by Richard Nolde

2008.11.10 18:40 "Writing scanlines with PLANARCONFIG == SEPARATE", by Richard Nolde

I'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