【问题标题】:Adding custom tags to a TIFF file将自定义标签添加到 TIFF 文件
【发布时间】:2014-06-05 11:48:05
【问题描述】:

我对 libtiff 还很陌生,但我设法获得了 tiff 文件 保存和打开没有太多麻烦。

现在,我雄心勃勃,尝试将自定义标签添加到我的文件中。我有 阅读文档(see here)并编写了一些测试代码,无需编译 错误,但在运行时失败,在第一次调用时出现访问冲突 具有自定义字段的 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<char*>("LaserIncidentPower") },
    { TIFFTAG_REFLECTEDPOWER, -1, -1, TIFF_LONG,  FIELD_CUSTOM, 0, 1, const_cast<char*>("LaserReflectedPower") },
    { TIFFTAG_T1,             -1, -1, TIFF_FLOAT, FIELD_CUSTOM, 0, 1, const_cast<char*>("Temperature_1") },
    { TIFFTAG_T2,             -1, -1, TIFF_FLOAT, FIELD_CUSTOM, 0, 1, const_cast<char*>("Temperature_2") },
    { TIFFTAG_HUMIDITY,       -1, -1, TIFF_FLOAT, FIELD_CUSTOM, 0, 1, const_cast<char*>("Humidity") },
    { TIFFTAG_EXPOSURE,       -1, -1, TIFF_FLOAT, FIELD_CUSTOM, 0, 1, const_cast<char*>("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<int>(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<void *>(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;
}

【问题讨论】:

    标签: c++ c tiff libtiff


    【解决方案1】:

    在 TIFF 用户邮件列表上一位名叫 Paul Heckbert 的好心人的指导下,下面是最终对我有用的代码。它有两个关键:

    (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<char*>("LaserIncidentPower") },
            { TIFFTAG_REFLECTEDPOWER, 1, 1, TIFF_LONG,  FIELD_CUSTOM, 0, 0, const_cast<char*>("LaserReflectedPower") },
            { TIFFTAG_T1,             1, 1, TIFF_FLOAT, FIELD_CUSTOM, 0, 0, const_cast<char*>("Temperature_1") },
            { TIFFTAG_T2,             1, 1, TIFF_FLOAT, FIELD_CUSTOM, 0, 0, const_cast<char*>("Temperature_2") },
            { TIFFTAG_HUMIDITY,       1, 1, TIFF_FLOAT, FIELD_CUSTOM, 0, 0, const_cast<char*>("Humidity") },
            { TIFFTAG_EXPOSURE,       1, 1, TIFF_FLOAT, FIELD_CUSTOM, 0, 0, const_cast<char*>("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<int>(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<void *>(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<tstrip_t>(0), static_cast<void *>(*image), static_cast<tsize_t>(-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;
    }
    

    【讨论】:

    • TIFFMergeFieldInfo()TIFFFieldInfo 不是已经过时了吗?
    • 这确实是自定义标签的弃用接口。 Release 3.6.0 引入了一种处理自定义标签的新方法。我仍在尝试找出如何使用它,没有文档。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-31
    • 2011-01-28
    • 2012-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-27
    相关资源
    最近更新 更多