在TIFF中创建一个带有缩略图(libtiff)的子IFD
In a TIFF create a Sub IFD with thumbnail (libtiff)
我知道 thumbnail.c 包含一些创建缩略图并将其放置在子 IDF 中的代码,但该代码中发生了很多事情(生成缩略图、应用对比度曲线等),我很难仅编写缩略图进行复制。谷歌也没有任何帮助。
我的问题是,在我打开输出文件并拥有 TIFF* 后,我的缩略图数据(以及我的主图像数据)都准备好了,如何以缩略图位于主图像 IFD 的子 IFD 中的方式添加它们?
因此,在深入研究了 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的记录如此之少,这真的是一种耻辱,特别是考虑到它的使用范围有多广。
我认为@KSletmoe已经指出了一个关键点,即在编写任何子IFD之前应该在IFD0中添加SubIFD标签(330),但仍然存在问题。
SubIFD 标签的定义是"偏移到子 IFD"。因此,如果您没有正确设置偏移量,tiff 解析器将无法正确解析整个 tiff。
有两种方法可以处理这种情况。
首先,预先计算每个 IFD/SubIFD 的大小,然后在设置时填写 SubIFD 标签,而不是设置0x0。
或者您可以正常编写每个 IFD,然后返回 IFD0 并添加 SubIFD 标签,其中包含由 libtiff 计算的最终偏移量。像下面这样:
//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。希望这可以帮助某人,并期待一些优雅的方式来做到这一点。
- QT将图像从缩略图拖放到网格布局(QVTKOpenGLWidget)?
- 无法链接 libtiff
- UINT8/16 /32/etc 和 INT8/16/32/etc 在 libtiff 中不起作用?
- 在 Qt 中显示多个图像缩略图
- CMake / 错误时链接 libfreeimage / libtiff.
- Mac OS c++ Link OpenCV and libtiff
- libtiff读写C 中的RGBA图像
- 从JPEG文件中读取Exif缩略图
- libtiff x64 visual studio 2017:链接器问题
- Xcode 上的 CImg 和 libtiff 的链接器错误
- 如何使用 LibTIFF 在多页面上编写磁贴
- 无法在窗口中添加缩略图按钮
- C++LibTiff:对_TIFFerrorHandler的未定义引用
- 滚动条缩略图跟踪长度 基于图像的水平适合调整窗口大小时出现问题
- libtiff with VS2012
- 使用 libtiff 在 C++ 中写入映像时出现问题,在 TIFFScanlineSize 中出现整数溢出
- 使用 libtiff 的 TIFFReadRawTile 无需解压缩/压缩即可获得 jpeg 磁贴
- 如何与 libtiff 链接
- 无法在 QT Creator/MSVC 中与 libtiff 链接
- 在TIFF中创建一个带有缩略图(libtiff)的子IFD