From: libtiff@apexinternetsoftware.com (Finlayson, Ross)
Date: Thu, 20 Nov 2003 21:34:40 -0800
Subject: [Tiff] Reading Tiff Image files
In-Reply-To: <Pine.GSO.4.33.0311202210240.9825-100000@grad>
Message-ID: <200311210522.hAL5Mo6l003927@whale2.fsr.net>

On Thursday, November 20, 2003, at 07:17 PM, sridhar duggireddy wrote:

> Hi,
>
>    I have a doubt. What does StripOffsets mean? Where is it used? When I
> searched in the net I found that it is the only field to find the image
> data.? In my program I'm doing like this to get the image data...Can you
> please tell me whether I'm doing correct or not?
>

You don't have to worry about the strip offsets.  The strip offsets, 
when you get them into a unit32* called uint32av with TIFFGetField(tif, 
TIFFTAG_STRIPOFFSETS, &uint32av), would contain the contents of the 
Strip Offsets field, then the Strip Byte Counts field contains the 
extent of each strips data from the corresponding offset, each array has 
as many elements as there are stripes in the image.

When you call TIFFReadEncodedStrip, the function uses the strip offset 
and strip byte count for that strip to get the raw, compressed data from 
the strip.  Then, it uncompresses the data into the buffer that you have 
passed to the TIFFReadEncodedStrip, as you illustrate in your sample 
program.

The TIFFReadEncodedStrip and TIFFReadRawStrip functions handle the strip 
offsets and byte counts for you.  If you had some reason to access them 
separately, you can with TIFFGetField, but you shouldn't set them with 
TIFFSetField, they are determined by TIFFWriteEncodedStrip.

> .................. Sample output from tiffdump()......
>
> sample.tif:
> Magic: 0x4949 <little-endian> Version: 0x2a
> Directory 0: offset 8 (0x8) next 0 (0)
> OldSubFileType (255) SHORT (3) 1<1>
> ImageWidth (256) SHORT (3) 1<4733>
> ImageLength (257) SHORT (3) 1<4733>
> BitsPerSample (258) SHORT (3) 1<8>
> Photometric (262) SHORT (3) 1<1>
> StripOffsets (273) LONG (4) 1<265>
> ImageDescription (270) ASCII (2) 155<[30..46140]  PGA-HCL-ast ...>
> GrayResponseUnit (290) SHORT (3) 1<2>
>
>   ............. Sample Code ...............
> #include "tiffio.h"
> #include <stdio.h>
> int main()
> {
>         TIFF* tif = TIFFOpen("sample.tif","r");
>         if(tif)
>         {
>                 uint32 imagelength;
>                 uint32 w,h;
>                 int t;
>                 tstrip_t strips;
>                 unsigned char *buf;
>                 FILE *fp;
>                 fp = fopen("out.txt","w");
>                 TIFFGetField(tif,TIFFTAG_IMAGELENGTH,&imagelength);
>                 TIFFGetField(tif,TIFFTAG_IMAGEWIDTH,&w);
>                 printf("WIDTH = %ld,HEIGHT = %ld\n",w,imagelength);
>                 strips = TIFFNumberOfStrips(tif);
>                 printf("Number of strips = %ld\n",strips);
> 		 printf("Strip Size = %ld\n",TIFFStripSize(tif));
>                 buf = (unsigned char 
> *)(_TIFFmalloc(TIFFStripSize(tif)));
>                 // Get the image data...
> 		for(strips=0;strips < TIFFNumberOfStrips(tif);strips++)
>                 {
>                         
> TIFFReadEncodedStrip(tif,strips,buf,(tsize_t)-1);
>                         for(int x = 0; x < TIFFStripSize(tif); x++)
>                                 fprintf(fp,"%d ",buf[x]);
>                         fprintf(fp,"\n");
>                 }
>                 _TIFFfree(buf);
>                 TIFFClose(tif);
>         }
> }
>
> Thanks,
> Sridhar!!
>
> _______________________________________________
> Tiff mailing list
> Tiff@remotesensing.org
> http://remotesensing.org/mailman/listinfo/tiff
>

Here's my suggestion, add another variable and instead of having the 
strips variable be both the count of strips and later the incrementor, 
have a separate incrementor and only call TIFFNumberOfStrips once, eg 
adding tstrip_t i=0; to the variable list and have the for loop be 
"for(i=0;i<strips;i++)", and changing the TIFFReadEncodedStrip function 
to use i instead of strips.

Here's another example of storing the result, when you call 
TIFFStripSize, that function returns the size of a buffer that can hold 
the contents of each strip.  Store that size in a variable and then 
reuse instead of calling TIFFStripSize, which calculates the strip size 
from the sample type and dimensions of the strip.

tsize_t strip_size=0;
strip_size=TIFFStripSize(tif);

Then replace the calls to TIFFStripSize(tif) with the variable 
strip_size.

You might want to check the return value of the TIFFReadEncodedStrip 
function.  It returns (tsize_t)-1 if there was an error.  Otherwise, it 
returns the amount read into the buffer.  This won't always be the same 
as strip_size, but it should be, except for the last strip.  This is 
where if there are, for example, 16 rows per strip, and, the image 
length is not a multiple of 16, the last strip will only have x/16'ths 
of the data read, for x between 1 and 15, x is image_length % 
rows_per_strip.

Instead of using the -1 argument to TIFFReadEncodedStrip for the amount 
to read, you could replace that with strip_size.  Because you already 
know the value, it might help the function from having to calculate it 
itself.  Also, in some weird case where it would otherwise read more 
than strip_size, it would stop.

Ross F.

