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
August 2006

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

2006.08.29 20:44 "TiffReadEncodedStrip", by Richard Nolde
2006.08.29 23:56 "Re: TiffReadEncodedStrip", by Joris Van Damme
2006.08.30 22:01 "Re: TiffReadEncodedStrip", by Richard Nolde
2006.08.31 00:36 "Re: TiffReadEncodedStrip", by Joris Van Damme

2006.08.30 22:01 "Re: TiffReadEncodedStrip", by Richard Nolde

Joris wrote: 
>  Richard,

Richard Nolde wrote:
   
 From what I have read in the current man pages and programs in the
tools directory, I assume that I can simple compute the start of each
row as an offset from the beginning of the buffer. For 1 bit per
sample data with one sample per pixel, something like ImageWidth / 8
bytes would be returned into the read buffer for each row in the
image and the offset would be (row * IMAGEWIDTH) / (8 /bps)  *
samples per pixel for contiguous planes.  This seems to imply that
the last byte of a scanline is padded out to fill that byte.  Is this
correct?
     The last statement is correct, but the formulae before that is not.
Scanlines are padded out with fillbits up to a byte boundary.

The correct expression to use goes something like this. A scanline
length is (imagewidth*bitsperpixel+7)/8. Think about it, if imagewidth
is 1 and bitsperpixel is 1, that'll round things up to 1 byte per row.
If imagewidth is 8 and bitsperpixel is 1... still 1 byte per row.

So if you need an offset for (column,row), the byteoffset would be

row*((imagewidth*bitsperpixel+7)/8)+(column*bitsperpixel/8)

and if bitsperpixel is not a multiple of 8, you'll need a bit offset
too...

((column*bitsperpixel)%8)


   I would deduce from this that your row and column numbers are zero
   referenced as in C arrays. It has been a while since I have had a chance
   to write in C so I'm a little bit groggy on the bit shifts and masking as
   it applies to libtiff.
 
 My usage, for reasons related to the code that defines the zones to be
 extracted, runs row from 1 to IMAGE_LENGTH and column from 1 to IMAGE_WIDTH
 so I have to subtract one in each case.  The snippet below is the code to
 extract the data bytes from the input image and write them to an output
 image.  My code now gets the right bytes, but I am confused by your comment
 on the bit offset.  Assuming an image of 1658 pixels wide with 1 bit per
 sample, 1 sample per pixel, there will be 207 "full bytes" and two extra
 bits.  Will these last bits be in the highorder bits or loworder bits, ie
 128 and 64 or 2 and 1 and does the fill order matter when the image has
 been extracted by ReadEncodedStrip?  I had assumed a continuous bit stream
 with the padding in the low order bits and planned on reading the trailing
 bits followed by zeros if it is the end of the line.  Of course, when
 cropping from within the line, the remaining bits need to be masked off and
 converted to fill bits too.
 
   for (i = 0; i < crop->zones; i++)
     {
     first_row = crop->zonelist[i].y1;
     last_row  = crop->zonelist[i].y2;
     first_col = crop->zonelist[i].x1;
     last_col  = crop->zonelist[i].x2;
 
     crop_width = last_col - first_col + 1;
     crop_length = last_row - first_row + 1;
     crop_size   = (crop_width * crop_length * spp) / (8 / bps);
 
     full_bytes = spp * (crop_width * bps) / 8;   /* number of COMPLETE
     bytes per row in crop area */
     padded_bytes = spp * (crop_width * bps + 7) / 8; /* total number of
     bytes per row in crop area */
     trailing_bits = (crop_width * bps) % 8;
 
     fprintf (stderr, "First row: %d, Last row; %d First column: %d, Last
     column: %d\n",
          first_row, last_row, first_col, last_col);
     fprintf (stderr, "\nZone: %d, Crop width: %u, Crop length: %u,
     Compressed size in bytes: %u\n", 
          i + 1, crop_width, crop_length, crop_size);
     fprintf (stderr, "Complete bytes in cropped row: %d,  %d trailing
     bits\n", 
                       full_bytes, trailing_bits);
 
     for (row = first_row; row <= last_row; row++)
       {
       /* Simple case first, all samples interleaved */
       if (planar == PLANARCONFIG_CONTIG)
         {
         /* Offset1 is the byte offset at which the first selected pixel of
         the region is found
            Shift1 is the bit offset within the byte at offeset1 */
         offset1 =  spp * ((row - 1) * ((img_width * bps + 7) / 8) +
         ((first_col - 1) * bps / 8));
         shift1  =  spp * (((first_col - 1) * bps) % 8);
 
     /* Offset2 is the byte offset at which the last selected pixel of the
     region is found
            Shift2 is the bit offset within the byte at offeset2 */
         offset2 = spp * ((row - 1) * ((img_width * bps + 7) / 8) +
         ((last_col - 1) * bps / 8));
         shift2  = spp * (((last_col - 1) * bps) % 8);
 
         fprintf (stderr, "\nRow: %5d, Start byte: %6u,  Shift: %d\n        
            End byte:   %6u,  Shift: %d\n", 
          row, offset1, shift1, offset2, shift2);
 
         bytebuff1 = bytebuff2 = 0;
         if (shift1 == 0) /* the region is byte and sample alligned */
           {
       /* fprintf (stderr, "Processing %d unshifted bytes plus final partial
       byte\n", full_bytes); */
       _TIFFmemcpy (crop_buff + dest_offset, read_buff + offset1,
       full_bytes);
           dest_offset += full_bytes;
 
           /* pick up the final bits */
           if (trailing_bits != 0)
             {
             for (k = 7; k >= 0; k--)
           sprintf (&bitbuffer[7 - k], "%s", ((unsigned
           char)read_buff[offset2] & (1 << k)) ? "1" : "0");
 
         fprintf (stderr, "Final byte contains value %2x, %s\n",
              (unsigned char)read_buff[offset2], bitbuffer);
 
         bytebuff2 = read_buff[offset2] & ((unsigned char)255 << (8 -
         shift2));
             crop_buff[dest_offset] = bytebuff2;
             dest_offset++;
             }
           }
         else   /* each destination byte will have to be built from two
         source bytes*/
           {
       fprintf (stderr, "Processing %d bit shifted bytes\n", full_bytes);
           for (j = 0; j <= full_bytes; j++) 
             {
         bytebuff1 = read_buff[offset1 + j] & ((unsigned char)255 >>
         (shift1));
         bytebuff2 = read_buff[offset1 + j + 1] & ((unsigned char)255 << (8
         - shift1));
             crop_buff[dest_offset + j] = bytebuff1 | bytebuff2;
             }
           dest_offset += full_bytes;
 
           /* process the final bits of the cropped row */
       /* calculate how many bits are left from shift1 and how many are
       needed from shift 2 
                pad the scanline as needed  */
           if (trailing_bits != 0)
             {
             for (k = 7; k >= 0; k--)
           sprintf (&bitbuffer[7 - k], "%s", ((unsigned
           char)read_buff[offset2] & (1 << k)) ? "1" : "0");
 
         fprintf (stderr, "Final byte contains value %2x, %s\n",
              (unsigned char)read_buff[offset2], bitbuffer);
         if (shift2 > shift1)
               {
           bytebuff1 = read_buff[source_offset + full_bytes] & ((unsigned
           char)255 << (8 - shift2));
               bytebuff2 = bytebuff1 & ((unsigned char)255 << shift1);
               crop_buff[dest_offset + j] = bytebuff2;
               }
             else
               {
            if (shift2 < shift1)
                 {
                 bytebuff2 = ((unsigned char)255 << (8 - shift2));
                 crop_buff[dest_offset + j] &= bytebuff2;
                 }
           /*   else
            fprintf (stderr, "Shift2 equals bit borrowed from final
            byte\n"); */
               }
         }
       }
     }
       else
         {
     /* PLANARCONFIG_SEPARATE */
     fprintf (stderr, "Planar config separate data not yet supported.\n");
         return (-1);
     }
       }
 
 Here is a log for the first two images in the input file.  Since I am not
 ready to write out the data, I can't tell if I have the bit shifting is
 correct.
 
 Image 1, width: 1658, Image length: 2591, Xres 300.00, Yres: 300.00
 Scale: 1.000000  Requested resunit 2, Image resunit 2
 
 Margins: Top: 0  Left: 0  Bottom: 0  Right: 0
 Crop region within margins: Requested Width:   1658  Length:   2591
 Crop region within margins: Adjusted Width:    1658  Length:   2591
 
 Zone 1, width: 1658, length:  323, x1:    1  x2: 1658  y1:    1  y2:  323
 Image width: 1658, Image length: 2591, Image size in pixels: 4295878
 Samples per Pixel: 1, Bits per Sample: 1, Planar config: 1
 Image is not byte swapped and fill order is MSB to LSB
 Number of strips: 1, Strip size: 538928, RowsPerStrip 2591, Scanline size:
 208
 Crop buffer: 535534 pixels, 67507 bytes
 First row: 1, Last row; 323 First column: 1, Last column: 1658
 
 Zone: 1, Crop width: 1658, Crop length: 323, Compressed size in bytes:
 66941
 Complete bytes in cropped row: 207,  2 trailing bits
 
 Row:     1, Start byte:      0,  Shift: 0
             End byte:      207,  Shift: 1
 Final byte contains value  0, 00000000
 
 Row:     2, Start byte:    208,  Shift: 0
             End byte:      415,  Shift: 1
 Final byte contains value  0, 00000000
 
 Row:     3, Start byte:    416,  Shift: 0
             End byte:      623,  Shift: 1
 Final byte contains value  0, 00000000
 ...
 
 Image 2, width: 3449, Image length: 2604, Xres 300.00, Yres: 300.00
 Scale: 1.000000  Requested resunit 2, Image resunit 2
 
 Margins: Top: 0  Left: 0  Bottom: 0  Right: 0
 Crop region within margins: Requested Width:   3449  Length:   2604
 Crop region within margins: Adjusted Width:    3449  Length:   2604
 
 Zone 1, width: 3449, length:  325, x1:    1  x2: 3449  y1:    1  y2:  325
 Image width: 3449, Image length: 2604, Image size in pixels: 8981196
 Samples per Pixel: 1, Bits per Sample: 1, Planar config: 1
 Image is not byte swapped and fill order is MSB to LSB
 Number of strips: 1, Strip size: 1124928, RowsPerStrip 2604, Scanline size:
 432
 Crop buffer: 2234952 pixels, 140400 bytes
 First row: 1, Last row; 325 First column: 1, Last column: 3449
 
 Zone: 1, Crop width: 3449, Crop length: 325, Compressed size in bytes:
 140115
 Complete bytes in cropped row: 431,  1 trailing bits
 
 Row:     1, Start byte:      0,  Shift: 0
             End byte:      431,  Shift: 0
 Final byte contains value  0, 00000000
 
 Row:     2, Start byte:    432,  Shift: 0
             End byte:      863,  Shift: 0
 Final byte contains value  0, 00000000
 
 Richard Nolde