David Scarlett David Scarlett - 1 month ago 25
C Question

How are TIFF string fields retrieved using LibTIFF's TIFFGetField?

I've been trying to read string TIFF fields (such as TIFFTAG_MODEL) using LibTiff's TIFFGetField function, but all I'm getting back from it are pointers to zeroed memory. The TIFFGetField man page isn't much help, merely stating that it expects a

char**
argument for string fields, which I think implicitly suggests it will allocate memory, write the string to that memory, and return a pointer to it. But then it doesn't discuss responsibilities for freeing that memory.

When I define a
char*
and initialise it to NULL, then pass the address of that variable to TIFFGetField, it does set it to a non-NULL address, but the memory pointed to by that address is all zeroes.

In case it's relevant, I'm using LibTiff 4.0.2 on MacOS.

Here's an MCVE with what I've tried so far. (The commented out code is where I was experimenting with passing in an already allocated buffer instead. That didn't work either.)

#include "tiffio.h"
#include <stdio.h>

const char* img_filename = "temp.tif";

void WriteTestTIFF()
{
TIFF* tiff = TIFFOpen(img_filename, "w");

const size_t width = 2;
const size_t height = 2;
unsigned char image[width * height] = { 0 };

TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH, width);
TIFFSetField(tiff, TIFFTAG_IMAGELENGTH, height);
TIFFSetField(tiff, TIFFTAG_ROWSPERSTRIP, height); // Single strip image
TIFFSetField(tiff, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8);
TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, 1);
TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
TIFFSetField(tiff, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
TIFFSetField(tiff, TIFFTAG_MINSAMPLEVALUE, 0);
TIFFSetField(tiff, TIFFTAG_MAXSAMPLEVALUE, 255);

TIFFSetField(tiff, TIFFTAG_SOFTWARE, "TestingTIFFStringFields");
TIFFSetField(tiff, TIFFTAG_MODEL, "FakeCamera");

TIFFWriteEncodedStrip(tiff, 0, image, height * width);
TIFFClose(tiff);
}

void ReadTestTIFF()
{
TIFF* tiff = TIFFOpen(img_filename, "r");
//char buffer[256] = "";
char* char_ptr = NULL;
uint32 width = 0;
uint32 height = 0;
printf("(void*)char_ptr=0x%016lX\n", (unsigned long)char_ptr);
//printf("buffer='%s'\n", buffer);
if ( /*TIFFGetField(tiff, TIFFTAG_MODEL, buffer) != 1
||*/ TIFFGetField(tiff, TIFFTAG_MODEL, &char_ptr) != 1
|| TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &width) != 1
|| TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &height) != 1)
{
puts("One or more TIFFGetField calls failed.");
}
printf("width=%u\n", width);
printf("height=%u\n", height);
TIFFClose(tiff);
printf("(void*)char_ptr=0x%016lX\n", (unsigned long)char_ptr);
for (int n=0; n<5; n++)
{
printf("char_ptr[%d]=0x%02X\n", n, (unsigned int)(char_ptr[n]));
}
//printf("buffer='%s'\n", buffer);
printf("char_ptr='%s'\n", char_ptr);
}

int main()
{
WriteTestTIFF();
ReadTestTIFF();
return 0;
}


Output:

(void*)char_ptr=0x0000000000000000
width=2
height=2
(void*)char_ptr=0x00007FA5B3400310
char_ptr[0]=0x00
char_ptr[1]=0x00
char_ptr[2]=0x00
char_ptr[3]=0x00
char_ptr[4]=0x00
char_ptr=''


And just to demonstrate that these fields are being written correctly, here's the resulting TIFF file:

0000000: 4949 2a00 0c00 0000 0000 0000 0e00 0001 II*.............
0000010: 0300 0100 0000 0200 0000 0101 0300 0100 ................
0000020: 0000 0200 0000 0201 0300 0100 0000 0800 ................
0000030: 0000 0301 0300 0100 0000 0100 0000 0601 ................
0000040: 0300 0100 0000 0100 0000 1001 0200 0b00 ................
0000050: 0000 d200 0000 1101 0400 0100 0000 0800 ................
0000060: 0000 1501 0300 0100 0000 0100 0000 1601 ................
0000070: 0300 0100 0000 0200 0000 1701 0400 0100 ................
0000080: 0000 0400 0000 1801 0300 0100 0000 0000 ................
0000090: 0000 1901 0300 0100 0000 ff00 0000 3101 ..............1.
00000a0: 0200 1800 0000 ba00 0000 5301 0300 0100 ..........S.....
00000b0: 0000 0100 0000 0000 0000 5465 7374 696e ..........Testin
00000c0: 6754 4946 4653 7472 696e 6746 6965 6c64 gTIFFStringField
00000d0: 7300 4661 6b65 4361 6d65 7261 000a s.FakeCamera..

Answer

Perhaps don't TIFFClose() before accessing char_ptr. It's probably giving you back an address into some data structure that is created/populated by TIFFOpen() and is destroyed by TIFFClose().