Hi,

Does anyone here have any experience of using libtiff in c++? I have been trying to do some simple image processing using it and I don't seem to be able to write images. I can make files that have roughly the right size, but they're not correct as they don't open with any image viewers that I have. A test example of my code is shown below. The code is supposed to read in a colour image to an array (raster), convert it to monochrome by averaging the pixel values and storing them in an int array (image_mono), then convert the int array back into a char array (monoFile) and output this array as a tiff. Anyway, it compiles and runs, but the tiff is not readable :-( Any tips would be greatly appreciated.

#include <iostream>
using std::cout;
using std::endl;
using std::cerr;
#include <cmath>
#include <tiffio.h>


int main(int argc, char* argv[])
{
	uint32 width = 0;
	uint32 height = 0;
	float xres;
	float yres;
	uint16 resUnit;
	uint32 *raster = NULL;
	uint32 numberOfPixels = 0;
	unsigned pixel = 0;
	
// Open the input file, as given via the command line
	TIFF* tif = TIFFOpen(argv[1], "r");
    	if (!tif){
		cerr << "Unable to open image!" << endl;
		return 1;
	}

// Get the dimensions of the image
	TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
	TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
	TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres);
	TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres);
	TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &resUnit);
	
// Now use the libtiff malloc functions to allocate memory to store the image data
	numberOfPixels=width*height;
	if(numberOfPixels)
		raster = (uint32 *)_TIFFmalloc(numberOfPixels*sizeof(uint32));

// Now actually read the data from the image...
	if(!TIFFReadRGBAImage(tif,width,height,raster,0)){
	// Print an error and exit if it doesn't read properly
		cerr << "Error occured when reading image data!" << endl;
		return 1;
	}
	else	// Close the file if the info is read OK
		TIFFClose(tif);
	
// Now the pixel values are in memory, so get the pixel values into the form
// that I want; that is monochromatic, by averaging the R, G & B channels...
	int *image_mono  =  (int*)malloc(numberOfPixels*sizeof(int));

	for(pixel = 0; pixel < numberOfPixels; pixel++)
		image_mono[pixel] = (	(static_cast<int>(static_cast<char>(TIFFGetR(raster[pixel]))) & 0xFF) +
					(static_cast<int>(static_cast<char>(TIFFGetG(raster[pixel]))) & 0xFF) +
					(static_cast<int>(static_cast<char>(TIFFGetB(raster[pixel]))) & 0xFF))/3;

// The reason for the bitwise AND (&) in the above is that I found that
// if I just do static_cast<int>(static_cast<char>(TIFFGetX(raster[pixel]))) 
// then I get the result (in hex) FFFFFF00 + the actual pixel value.  By doing
// 0xFF & on it then I get the answer I am looking for.
	
	char *monoFile = (char *)malloc(numberOfPixels);
	
	for(pixel = 0; pixel < numberOfPixels; pixel++)
		monoFile[pixel] = (char)(image_mono[pixel] | 0xFFFFFF00);
// The bitwise OR (|) here undoes the AND that I used above.
	
// Open a new TIFF file for the output...
	if((tif = TIFFOpen("output.tif", "w")) == NULL){
		cerr << "Could not open output.tif for writing" << endl;
		return 1;
	}

// Set some tags in the output file.  To be honest, I don't know much about
// what I'm doing here, I've just tried a bunch of different things...	
	TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, 8*width);
	TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);
	TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
	TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
	TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, height);
	TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE);
	TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, 2);
	TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
	TIFFSetField(tif, TIFFTAG_XRESOLUTION, xres);
	TIFFSetField(tif, TIFFTAG_YRESOLUTION, yres);
	TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, resUnit);
  
// Write the information to the file
	TIFFWriteEncodedStrip(tif, 0, monoFile, width*height);

	return 0;
}

I'm all out of ideas about what to do to get this to work. The documentation for libtiff seems to be a lot more sparse than I expected. Alternatively, if there is some other tiff library that I should be using then certainly let me know that as well!

Cheers,
Ravenous

Recommended Answers

All 3 Replies

You could try reading a known mono TIF image to make sure you know what values are expected for the various header fields.

Also, being a mono image, shouldn't it be just 1 bit per pixel, and not 1 byte set to 0x00 or 0xFF (just a guess)?

You could try reading a known mono TIF image to make sure you know what values are expected for the various header fields.

Yep, I'll try this. I couldn't find any suitable images, but I guess I'll just create one with Gimp or something,

Also, being a mono image, shouldn't it be just 1 bit per pixel, and not 1 byte set to 0x00 or 0xFF (just a guess)?

Sorry, this is just me using the wrong word. You are, of course, correct. A mono image is just one bit. What I meant was *greyscale*. Sorry for the confusion!

I think I'm going to use Magic++ instead, it has a much more C++-centric API!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.