【问题标题】:In a TIFF create a Sub IFD with thumbnail (libtiff)在 TIFF 中创建带有缩略图的 Sub IFD (libtiff)
【发布时间】:2012-08-11 04:14:15
【问题描述】:

我知道 thumbnail.c 包含一些创建缩略图并将其放置在子 IDF 中的代码,但是该代码中发生了很多事情(生成缩略图、应用对比度曲线等),而我正在仅写一个缩略图就很难复制。 Google 也没有提供任何帮助。

我的问题是,在我打开一个输出文件并拥有一个 TIFF* 之后,我的缩略图数据(以及我的主图像数据)都准备好了,我该如何添加它们,以便缩略图在主图像 IFD 的子 IFD 中?

【问题讨论】:

    标签: c++ thumbnails tiff libtiff


    【解决方案1】:

    所以在研究了 libtiff 源代码一段时间后,我在 tif_dirwrite.c 中偶然发现了这个:

     /*
     * Copyright (c) 1988-1997 Sam Leffler
     * Copyright (c) 1991-1997 Silicon Graphics, Inc.
     *
     * Permission to use, copy, modify, distribute, and sell this software and
     * its documentation for any purpose is hereby granted without fee, provided
     * that (i) the above copyright notices and this permission notice appear in
     * all copies of the software and related documentation, and (ii) the names of
     * Sam Leffler and Silicon Graphics may not be used in any advertising or
     * publicity relating to the software without the specific, prior written
     * permission of Sam Leffler and Silicon Graphics.
     */
    
    ...
    if (!n)
        return(0);
    /*
     * Total hack: if this directory includes a SubIFD
     * tag then force the next <n> directories to be
     * written as ``sub directories'' of this one.  This
     * is used to write things like thumbnails and
     * image masks that one wants to keep out of the
     * normal directory linkage access mechanism.
     */
    tif->tif_flags|=TIFF_INSUBIFD;
    tif->tif_nsubifd=tif->tif_dir.td_nsubifd;
    if (tif->tif_dir.td_nsubifd==1)
        tif->tif_subifdoff=0;
    else
        tif->tif_subifdoff=m;
    return(1);
    ...
    

    (我包含了版权信息,因为我不确定在此处从库中发布代码时是否必须这样做)

    所以,回答我自己的问题(如何在主图像 IFD 的子 IFD 中编写缩略图):

    //...
    //For the sake of this demo we will assume that I have opened a 
    //TIFF (TIFF* created_TIFF) in write mode and have included the correct header
    //files
    
    //set all of your TIFF fields for the main image
    //...
    
    //Define the number of sub-IFDs you are going to write
    //(assuming here that we are only writing one thumbnail for the image):
    int number_of_sub_IFDs = 1;
    toff_t sub_IFDs_offsets[1] = { 0UL };
    
    //set the TIFFTAG_SUBIFD field:
    if(!TIFFSetField(created_TIFF, TIFFTAG_SUBIFD, number_of_sub_IFDs, 
        sub_IFDs_offsets))
    {
        //there was an error setting the field
    }
    
    //Write your main image raster data to the TIFF (using whatever means you need,
    //such as TIFFWriteRawStrip, TIFFWriteEncodedStrip, TIFFWriteEncodedTile, etc.)
    //...
    
    //Write your main IFD like so:
    TIFFWriteDirectory(created_TIFF);
    
    //Now here is the trick: like the comment in the libtiff source states, the 
    //next n directories written will be sub-IFDs of the main IFD (where n is 
    //number_of_sub_IFDs specified when you set the TIFFTAG_SUBIFD field)
    
    //Set up your sub-IFD
    if(!TIFFSetField(created_TIFF, TIFFTAG_SUBFILETYPE, FILETYPE_REDUCEDIMAGE))
    {
        //there was an error setting the field
    }
    
    //set the rest of the required tags here, as well as any extras you would like
    //(remember, these refer to the thumbnail, not the main image)
    //...
    
    //Write this sub-IFD:
    TIFFWriteDirectory(created_TIFF);
    
    //Assuming you are only writing one sub-IFD and are done with the file, you 
    //can close it now. If you specified more than one sub-IFD, you need repeat 
    //the above code (starting where we set TIFFTAG_SUBFILETYPE) for each of your
    //sub-IFDs
    TIFFClose(created_TIFF);
    

    我希望这对某人有所帮助,并且他们不必像我那样花费大量精力来弄清楚如何做到这一点。很遗憾,libtiff 的文档记录如此之少,尤其是考虑到它的使用范围如此广泛。

    【讨论】:

    • 这对我来说效果很好,为我节省了额外的时间。我想指出,您必须为每个子文件输入一个 SUBFILETYPE,否则 Adob​​e 至少不会识别它。
    【解决方案2】:

    我认为@KSletmoe 指出了一个关键点,即在您编写任何subIFD 之前,应在IFD0 中添加SubIFD 标记(330),但仍然存在问题。

    SubIFD 标签的定义是“偏移到子 IFD”。所以,如果你没有正确设置偏移量,tiff解析器就无法正确解析整个tiff。

    有两种方法可以处理这种情况。

    首先,预先计算每个IFD/SubIFD的大小,然后在设置时填写SubIFD标签,而不是设置0x0。

    或者您可以正常编写每个 IFD,然后返回 IFD0 并添加带有由 libtiff 计算的最终偏移量的 SubIFD 标记。如下:

    //Write down every thing you need in a tiff
    // ... IFD0
    TIFFWriteDirectory(tif);
    // ... IFD1
    TIFFWriteDirectory(tif);
    // ... IFD2
    TIFFWriteDirectory(tif);
    
    //set current Dir as IFD0 in the end
    TIFFSetDirectory(tif, 0);  
    
    //get next dir offset
    sub_offset[1] = TIFFGetNextDirOff(tif, 2);
    sub_offset[0] = TIFFGetNextDirOff(tif, 1);
    //only for clean next dir offset in IFD0
    no_use_offset = TIFFGetNextDirOff(tif, 0);                                                    
    
    TIFFSetField(tif, TIFFTAG_SUBIFD, 2, sub_offset);    
    

    您可能需要在 tif_dir.c 中添加流功能

    uint64 TIFFGetNextDirOff(TIFF* tif, uint16 dirn)                                                 
    {                                                                                                
        uint64 nextdir;                                                                              
        uint16 n;                                                                                    
        if (!(tif->tif_flags&TIFF_BIGTIFF))                                                          
            nextdir = tif->tif_header.classic.tiff_diroff;                                           
        else                                                                                         
            nextdir = tif->tif_header.big.tiff_diroff;                                               
        for (n = dirn; n > 0 && nextdir != 0; n--)                                                   
            if (!TIFFAdvanceDirectory(tif, &nextdir, NULL))                                          
                return (0);
    
        /*!!Watchout!! Here will reset the next dir offset to 0*/
        tif->tif_nextdiroff = 0;                                                                                                                                     
        return nextdir;                                                                              
    }
    

    感谢@KSletmoe。希望这可以帮助某人,并期待一些更优雅的方式来做到这一点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-15
      • 2013-10-22
      • 2011-02-18
      相关资源
      最近更新 更多