如果我有指向TIFF数据的指针,但没有大小的指示,有没有办法准确计算它?
我已经经历了几个不同的想法,所有这些想法大部分时间都在工作,但并非总是如此,因为有很多不同的方式来格式化TIFF,我认为必须有一种更简单的方法。现在,我最接近的是:
ULONG readImageHeader(char* image)
{
TIF_HDR *xTIFHdr;
TIF_IFD *xTIFIFD;
TIF_IFD_ENTRY *pxTIFIFDEntry;
UCHAR *pHdrPtr;
USHORT i;
ULONG length = 0;
ULONG imgLength = 0;
ULONG count = 0;
// check to see if it is a TIFF header
xTIFHdr = (TIF_HDR *)image;
// Little Endian
if (xTIFHdr->usTIFID == TIF_HEAD_LITTLE)
{
pHdrPtr = (UCHAR*)image;
pHdrPtr += xTIFHdr->ulFirstIFDOffset;
// read TIF IFD
xTIFIFD = (TIF_IFD *)pHdrPtr;
// Look at all the IFD entries and set internal image hdr
pHdrPtr += TIF_IFD_LEN;
pxTIFIFDEntry = (TIF_IFD_ENTRY *)pHdrPtr;
// iterate through each IFD entry
for (i=0; i<xTIFIFD->usNumIFDEntries; i++)
{
if(length <= (ULONG)pxTIFIFDEntry->ulTIFValueOffset)
{
length = (ULONG)pxTIFIFDEntry->ulTIFValueOffset;
// the TIF length is in units of the TIF type
switch(pxTIFIFDEntry->usTIFType)
{
case TIF_BYTE:
length += (ULONG)pxTIFIFDEntry->ulTIFLength * TIF_BYTE_SIZE;
break;
case TIF_ASCII:
length += (ULONG)pxTIFIFDEntry->ulTIFLength * TIF_ASCII_SIZE;
break;
case TIF_SHORT:
length += (ULONG)pxTIFIFDEntry->ulTIFLength * TIF_SHORT_SIZE;
break;
case TIF_LONG:
length += (ULONG)pxTIFIFDEntry->ulTIFLength * TIF_LONG_SIZE;
break;
case TIF_RATIONAL:
length += (ULONG)pxTIFIFDEntry->ulTIFLength * TIF_RATIONAL_SIZE;
break;
default:
length += (ULONG)pxTIFIFDEntry->ulTIFLength;
break;
}
}
switch (pxTIFIFDEntry->usTIFTag)
{
case TIF_STRIP_BYTE_COUNTS:
case TIF_STRIP_OFFSETS:
{
ULONG valueOffset = (ULONG)pxTIFIFDEntry->ulTIFValueOffset;
count = (ULONG)pxTIFIFDEntry->ulTIFLength;
// if the count > 1, then the valueOffset actually represents an offset
if(count > 1)
{
ULONG countsize = (count - 1) * sizeof(ULONG);
imgLength += *(ULONG*) ((UCHAR*)image + valueOffset + countsize);
}
else
{
// if count is 1, then the valueOffset is really just the value of that item
imgLength += valueOffset;
}
break;
}
default:
break;
}
pxTIFIFDEntry++;
}
// the length is the largest offset, plus the length of that item
// the imgLength is the offset of the image, plus the size of the image, which is stored as two separate tags
// return the largest of them
return(length > imgLength ? length : imgLength);
}
// Big Endian
else if(xTIFHdr->usTIFID == TIF_HEAD_BIG)
{
// I don't care about this
printf("Big Endian TIFF image\n");
}
printf("Invalid TIFF image\n");
return(0);
}
基本上我在这里做的是我在迭代TIFF标题,并计算两个运行总和:(最大偏移+数据长度)和(条带偏移+条带字节计数)。然后我只使用两个值中较大的一个。
除了有时ulTIFValueOffset根本不是偏移量,而是实际值以外,这种情况大多有效。在(某些)这些情况下,我得到的文件太大了。到目前为止,我所有失败的例子都是在抓取宽度或长度标签的时候,虽然我不能排除其他标签可能出现同样问题的可能性。
有吗
谢谢!
答案 0 :(得分:3)
面向实用主义的答案,除非你绝对必须,否则不要直接自己处理图像格式。使用图像库。对于TIFF,有各种免费( libre 和/或 gratis )图形文件库,包括libTIFF,ImageMagick / {{3} },GraphicMagick,DevIL和其他人。
FreeImage功能非常强大且灵活,但可以说是最复杂的图像格式,如TIFF 6.0规范中所述。此外,当前的实现还包含用于JPEG支持的TIFF技术说明#2,以及BigTIFF草案。
我经历了几个不同的想法,所有这些想法都是最有效的 时间,但并非总是如此,因为有很多不同的方式 格式化TIFF
这就是我推荐使用图像库的原因。
如果我有指向TIFF数据的指针,但没有指示大小, 有没有办法准确计算它?
如果您使用“TIFF数据”,那么您的意思是TIFF图像本身,不,不是我所知道的。如果不对其进行解析,则无法确定TIFF图像的文件大小(在磁盘上或内存中)。
根据标题计算文件大小的方法?
只需使用8字节图像文件标题,然后使用no。
通过解析Image File Directory
(IFD),您可以计算该值。
一种了解标题是值还是偏移量的方法?
您应该能够确定IFD(图像文件目录,TIFF规范中的术语)条目ValueOffset
何时是值或偏移量。值当且仅当符合4字节(ValueOffset字段的大小)时。 (参考:TIFF image format - 价值/抵消)
答案 1 :(得分:2)
我正在解释你的问题是“我所拥有的只是指向数据的盲目指针,据称是TIFF。Can I determine the size of the block of memory allocated to that pointer?”
至于仅根据TIFF数据来确定块大小,有时会得到答案,但在一般情况下没有,当然也不安全。
TIFF IFD结构被构建为一个概念链表,任何IFD中的最后4个字节指向下一个IFD的偏移量或为0.我有一组破坏的TIFF用于测试我的TIFF库,它表明有些人编写代码来编写TIFF的人甚至无法正确完成这项简单的任务。我经常看到IFD偏移或数据偏移指向某个地方的空间。如果您在不知道内存块限制的情况下编写内存中的IFD遍历代码,那么当您在堆中进行遍历时,如果出现分段错误,则幸运。
TIFF是一种欺骗性的文件格式。粗略的外观表明它很简单,但有很多棘手的特殊情况,代码消耗TIFF需要处理这些情况和生产者拙劣的特殊情况。
即使你写了一个完整的消费者来撇去所有的IFD和所有的偏移标签,并试图找出数据中哪个最远,但仍然无法保证数据不会被截断(我有几个文件这个条纹)也没有在最后一个IFD之后没有更多的垃圾数据(我有几个这样的文件)。
如果您决定编写代码来遍历文件(我不建议您这样做),您应该考虑使用抽象层将数据读入结构而不是盲目转换,因为TIFF数据偏移不必遵守任何特定的单词/长词对齐,这可能会让你感到悲伤。