Getting error when trying to apply "ExtraSamples" tag to a TIFF file to be written
I have a program that takes an image and writes that out to a TIFF file. The image can be grey scale (8 bit), grey scale with alpha channel (16 bit), RGB (24 bit), or ARGB (32 bit). I don't have any problems writing out the images without an alpha channel, but for the images with alpha, when I try to set the extra samples tag, I get sent to the TIFF error handling routine set by TIFFSetErrorHandler. The message that's passed in is <filename>: Bad value 1 for "ExtraSamples"
in the _TIFFVSetField module. Some sample code below:
#include "tiff.h"
#include "tiffio.h"
#include "xtiffio.h"
//Other includes
class MyTIFFWriter
{
public:
MyTIFFWriter(void);
~MyTIFFWriter(void);
bool writeFile(MyImage* outputImage);
bool openFile(std::string filename);
void closeFile();
private:
TIFF* m_tif;
};
//...
bool MyTIFFWriter::writeFile(MyImage* outputImage)
{
// check that we have data and that the tiff is ready for writing
if (outputImage->getHeight() == 0 || outputImage->getWidth() == 0 || !m_tif)
return false;
TIFFSetField(m_tif, TIFFTAG_IMAGEWIDTH, outputImage->getWidth());
TIFFSetField(m_tif, TIFFTAG_IMAGELENGTH, outputImage->getHeight());
TIFFSetField(m_tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
TIFFSetField(m_tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
if (outputImage->getColourMode() == MyImage::ARGB)
{
TIFFSetFi开发者_JAVA百科eld(m_tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
TIFFSetField(m_tif, TIFFTAG_BITSPERSAMPLE, outputImage->getBitDepth() / 4);
TIFFSetField(m_tif, TIFFTAG_SAMPLESPERPIXEL, 4);
TIFFSetField(m_tif, TIFFTAG_EXTRASAMPLES, EXTRASAMPLE_ASSOCALPHA); //problem exists here
} else if (/*other mode*/)
//apply other mode settings
//...
return (TIFFWriteEncodedStrip(m_tif, 0, outputImage->getImgDataAsCharPtr(),
outputImage->getWidth() * outputImage->getHeight() *
(outputImage->getBitDepth() / 8)) != -1);
}
As far as I can see, the tag never gets written to the file. Luckily, GIMP still recognizes that the additional channel is alpha, but some other programs that need to read these TIFFs aren't so generous. Am I missing tags that must be set before TIFFTAG_EXTRASAMPLES? Am I missing other tags that need to be there? Any help would be appreciated.
I found the solution. The Extra_Samples field is not an uint16 but rather first a count (which is uint16) and then an array of that size (of type uint16). The call should thus look like this:
uint16 out[1];
out[0] = EXTRASAMPLE_ASSOCALPHA;
TIFFSetField( outImage, TIFFTAG_EXTRASAMPLES, 1, &out );
The reason for this is that more than one extra sample is allowed.
Hope this helps!
Cheers, Kaspar
Thank you Kaspar, Tomas, and everyone else for the invaluable instructions.
Here are the relevant bits for RGBA from this thread:
const uint16 extras[] = {EXTRASAMPLE_ASSOCALPHA};
TIFFSetField(tifptr, TIFFTAG_SAMPLESPERPIXEL, 4);
TIFFSetField(tifptr, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
TIFFSetField(tifptr, TIFFTAG_EXTRASAMPLES, EXTRASAMPLE_ASSOCALPHA, 1, extras);
where tifptr is a pointer to the TIFF type defined in tiffio.h
.
Here's a link to help disambiguate the TIFF Tags:
https://www.awaresystems.be/imaging/tiff/tifftags/extrasamples.html
Here's a link where to get the libtiff source code:
http://www.libtiff.org/
Thank you!
Note on va_list and friends:
When va_list (variadic argument list) and friends are used, and an incorrect number of arguments is supplied, you get useless segfault errors. The lesson for me here is if you're using a modern C library, and getting useless segfaults, you should at least consider it's because you are passing a length but no array to va macros.
精彩评论