将自定义标记添加到TIFF文件

我对libtiff很新,但我已经成功地保存并打开了tiff文件而没有太多麻烦。

现在,我雄心勃勃,并试图在我的文件中添加自定义标签。 我已经阅读了文档( 参见此处 )并编写了一些无错误编译的测试代码,但在第一次调用具有自定义字段的TIFFSetField时,在运行时失败时出现访问冲突(使用标准字段调用TIFFSetField很好)。

我的测试代码如下:不到100行,唯一的外部依赖(除了libtiff)是我从.pgm文件打开测试图像的代码。 谁能指出我做错了什么? 顺便说一下,我正在使用libtiff 4.0.3。

#include "stdafx.h" #include "PGM.h" // Just for reading in the test image #include "tiffio.h" // There are a number of TIFF-related definitions we need to make in order to support the custom tags // that we want to include in our files. The form of these definitions and subroutines comes straight // out of the libtiff documentation, and the values of the custom tags themselves come from the // range (65000-75535) defined in the TIFF specification as "reusable" and suitable for private use // within organisations. See http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf #define N(a) (sizeof(a) / sizeof (a[0])) #define TIFFTAG_INCIDENTPOWER 65000 #define TIFFTAG_REFLECTEDPOWER 65001 #define TIFFTAG_T1 65002 #define TIFFTAG_T2 65003 #define TIFFTAG_HUMIDITY 65004 #define TIFFTAG_EXPOSURE 65005 static const TIFFFieldInfo xtiffFieldInfo[] = { { TIFFTAG_INCIDENTPOWER, -1, -1, TIFF_LONG, FIELD_CUSTOM, 0, 1, const_cast("LaserIncidentPower") }, { TIFFTAG_REFLECTEDPOWER, -1, -1, TIFF_LONG, FIELD_CUSTOM, 0, 1, const_cast("LaserReflectedPower") }, { TIFFTAG_T1, -1, -1, TIFF_FLOAT, FIELD_CUSTOM, 0, 1, const_cast("Temperature_1") }, { TIFFTAG_T2, -1, -1, TIFF_FLOAT, FIELD_CUSTOM, 0, 1, const_cast("Temperature_2") }, { TIFFTAG_HUMIDITY, -1, -1, TIFF_FLOAT, FIELD_CUSTOM, 0, 1, const_cast("Humidity") }, { TIFFTAG_EXPOSURE, -1, -1, TIFF_FLOAT, FIELD_CUSTOM, 0, 1, const_cast("ExposureTime(ms)") } }; // The casts are necessary because the // string literals are inherently const, // but the definition of TIFFFieldInfo // requires a non-const string pointer. // The Intel and Microsoft compilers // tolerate this, but gcc doesn't. static void registerCustomTIFFTags(TIFF *tif) { /* Install the extended Tag field info */ TIFFMergeFieldInfo(tif, xtiffFieldInfo, N(xtiffFieldInfo)); } void saveAsTiff(int nx, int ny, unsigned short *image, const char* filename, int Power1, int Power2, float T1, float T2, float Humidity, float Exposure) { // Create the TIFF directory object: TIFF* tif = TIFFOpen(filename, "w"); // Set the tags: first the standard ones... TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, nx); TIFFSetField(tif, TIFFTAG_IMAGELENGTH, ny); TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16); TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE); TIFFSetField(tif, TIFFTAG_ZIPQUALITY, 6); // Takes maximum advantage of Intel ZLIB enhancements TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); TIFFSetField(tif, TIFFTAG_ORIENTATION, static_cast(ORIENTATION_TOPLEFT)); TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1); TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, ny); // Saving the whole image in a single block makes heavy // demands on memory but should enable optimum compression TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); // ... and now our own custom ones; if we comment out this next block then everything // works as it should and we successfully save the image: registerCustomTIFFTags(tif); TIFFSetField(tif, TIFFTAG_INCIDENTPOWER, Power1); // Access violation here TIFFSetField(tif, TIFFTAG_REFLECTEDPOWER, Power2); TIFFSetField(tif, TIFFTAG_T1, T1); TIFFSetField(tif, TIFFTAG_T2, T2); TIFFSetField(tif, TIFFTAG_HUMIDITY, Humidity); TIFFSetField(tif, TIFFTAG_EXPOSURE, Exposure); TIFFWriteEncodedStrip(tif, 0, static_cast(image), nx * ny * 2); // The '* 2' is present because each pixel // has 16 bits, hence two bytes // Write the directory to a file, and close it: TIFFWriteDirectory(tif); TIFFClose(tif); } int _tmain(int argc, _TCHAR* argv[]) { // Variables to hold the image int nx, ny; unsigned short *image = nullptr; // Information we'd like to put into our custom tags: int Power1 = 1000000; int Power2 = 8; float T1 = 23.5f; float T2 = -18.7f; float Humidity = 0.98f; float Exposure = 0.001f; // Read the test image in from a PGM file: readFromPGM(&nx, &ny, &image, "TestImage.pgm"); // Save the image as a TIF file: saveAsTiff(nx, ny, image, "TestImage.tif", Power1, Power2, T1, T2, Humidity, Exposure); return 0; } 

在一位名叫Paul Heckbert的绅士的TIFF用户邮件列表的指导下,以下是最终为我工作的代码。 它有两个关键:

(1)正确定义TIFFFieldInfo字段,其方式与文档中给出的示例不同。 (2)使用“扩展器”模式封装对TIFFMergeFieldInfo的调用,但打开文件之前执行此操作。 如果我在打开文件之前离开了呼叫,那么在读取带有自定义标签的文件时,会在打开文件时立即发出一些“警告,未知字段”消息。

这是代码:

 #include "stdafx.h" #include "PGM.h" #include "tiffio.h" // There are a number of TIFF-related definitions we need to make in order to support the custom tags // that we want to include in our files. The form of these definitions and subroutines comes straight // out of the libtiff documentation, and the values of the custom tags themselves come from the // range (65000-75535) defined in the TIFF specification as "reusable" and suitable for private use // within organisations. See http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf #define N(a) (sizeof(a) / sizeof (a[0])) #define TIFFTAG_INCIDENTPOWER 65000 #define TIFFTAG_REFLECTEDPOWER 65001 #define TIFFTAG_T1 65002 #define TIFFTAG_T2 65003 #define TIFFTAG_HUMIDITY 65004 #define TIFFTAG_EXPOSURE 65005 static const TIFFFieldInfo xtiffFieldInfo[] = { { TIFFTAG_INCIDENTPOWER, 1, 1, TIFF_LONG, FIELD_CUSTOM, 0, 0, const_cast("LaserIncidentPower") }, { TIFFTAG_REFLECTEDPOWER, 1, 1, TIFF_LONG, FIELD_CUSTOM, 0, 0, const_cast("LaserReflectedPower") }, { TIFFTAG_T1, 1, 1, TIFF_FLOAT, FIELD_CUSTOM, 0, 0, const_cast("Temperature_1") }, { TIFFTAG_T2, 1, 1, TIFF_FLOAT, FIELD_CUSTOM, 0, 0, const_cast("Temperature_2") }, { TIFFTAG_HUMIDITY, 1, 1, TIFF_FLOAT, FIELD_CUSTOM, 0, 0, const_cast("Humidity") }, { TIFFTAG_EXPOSURE, 1, 1, TIFF_FLOAT, FIELD_CUSTOM, 0, 0, const_cast("ExposureTime(ms)") } }; // The casts are necessary because the // string literals are inherently const, // but the definition of TIFFFieldInfo // requires a non-const string pointer. // The Intel and Microsoft compilers // tolerate this, but gcc doesn't. static TIFFExtendProc parent_extender = NULL; // In case we want a chain of extensions static void registerCustomTIFFTags(TIFF *tif) { /* Install the extended Tag field info */ int error = TIFFMergeFieldInfo(tif, xtiffFieldInfo, N(xtiffFieldInfo)); if (parent_extender) (*parent_extender)(tif); } static void augment_libtiff_with_custom_tags() { static bool first_time = true; if (!first_time) return; first_time = false; parent_extender = TIFFSetTagExtender(registerCustomTIFFTags); } void saveAsTiff(int nx, int ny, unsigned short *image, const char* filename, int Power1, int Power2, float T1, float T2, float Humidity, float Exposure) { // Create the TIFF directory object: augment_libtiff_with_custom_tags(); TIFF* tif = TIFFOpen(filename, "w"); // Set the tags: first the standard ones... TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, nx); TIFFSetField(tif, TIFFTAG_IMAGELENGTH, ny); TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16); TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE); TIFFSetField(tif, TIFFTAG_ZIPQUALITY, 6); // Takes maximum advantage of Intel ZLIB enhancements TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); TIFFSetField(tif, TIFFTAG_ORIENTATION, static_cast(ORIENTATION_TOPLEFT)); TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1); TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, ny); // Saving the whole image in a single block makes heavy // demands on memory but should enable optimum compression TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); // ... and now our own custom ones: TIFFSetField(tif, TIFFTAG_INCIDENTPOWER, Power1); TIFFSetField(tif, TIFFTAG_REFLECTEDPOWER, Power2); TIFFSetField(tif, TIFFTAG_T1, T1); TIFFSetField(tif, TIFFTAG_T2, T2); TIFFSetField(tif, TIFFTAG_HUMIDITY, Humidity); TIFFSetField(tif, TIFFTAG_EXPOSURE, Exposure); TIFFWriteEncodedStrip(tif, 0, static_cast(image), nx * ny * 2); // The '* 2' is present because each pixel // has 16 bits, hence two bytes // Write the directory to a file, and close it: TIFFWriteDirectory(tif); TIFFClose(tif); } void readFromTiff(int *nx, int *ny, unsigned short **image, const char* filename, int *Power1, int *Power2, float *T1, float *T2, float *Humidity, float *Exposure) { // Create the TIFF directory object: augment_libtiff_with_custom_tags(); TIFF* tif = TIFFOpen(filename, "r"); if (NULL == tif) { *nx = -1; *ny = -1; return; } // Read in the image size and metadata: TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, nx); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, ny); TIFFGetField(tif, TIFFTAG_INCIDENTPOWER, Power1); TIFFGetField(tif, TIFFTAG_REFLECTEDPOWER, Power2); TIFFGetField(tif, TIFFTAG_T1, T1); TIFFGetField(tif, TIFFTAG_T2, T2); TIFFGetField(tif, TIFFTAG_HUMIDITY, Humidity); TIFFGetField(tif, TIFFTAG_EXPOSURE, Exposure); // Dimension the buffer, and read in the image data itself: *image = new unsigned short[(*nx) * (*ny)]; TIFFReadEncodedStrip(tif, static_cast(0), static_cast(*image), static_cast(-1)); TIFFClose(tif); } int _tmain(int argc, _TCHAR* argv[]) { // Variables to hold the image int nx, ny; unsigned short *image = nullptr; // Information we'd like to put into our custom tags: int Power1 = 1000000; int Power2 = 8; float T1 = 23.5f; float T2 = -18.7f; float Humidity = 0.98f; float Exposure = 0.001f; // Read the test image in from a PGM file: readFromPGM(&nx, &ny, &image, "TestImage.pgm"); // Save the image as a TIF file: saveAsTiff(nx, ny, image, "TestImage.tif", Power1, Power2, T1, T2, Humidity, Exposure); // Prepare to read back in: first clear the various fields Power1 = 0; Power2 = 0; T1 = 0.0f; T2 = 0.0f; Humidity = 0.0f; Exposure = 0.0f; nx = 0; ny = 0; delete [] image; readFromTiff(&nx, &ny, &image, "TestImage.tif", &Power1, &Power2, &T1, &T2, &Humidity, &Exposure); printf("Image size = %d, %d\r\n", ny, ny); printf("Power1 = %d\r\n", Power1); printf("Power2 = %d\r\n", Power2); printf("T1 = %6.3f\r\n", T1); printf("T2 = %6.3f\r\n", T2); printf("Humidity = %6.3f\r\n", Humidity); printf("Exposure = %6.3f\r\n", Exposure); return 0; }