在这个问题的答案中:c ++解码pdfs中的CCITT编码图像
需要指出的是,libtiff可用于解码CCITT编码的图像.当然,我们必须预先添加一个TIFF标头,以使CCITT流成为有效的TIFF文件.
但是,PDF文件中的某些图像是内嵌图像,虽然给出了宽度,高度和位深度,但未给出它们的长度.读取PDF的程序应该解码CCITT流,读取(宽度*高度*深度)位的解码数据,以及读取数据后的任何位置,这是内联图像的结束.然后它应该继续下一页标记命令,依此类推.
这带来了一个问题.TIFF图像文件目录必须指定图像数据的每个条带中有多少字节,但在我们解码之前我们不知道编码数据的实际属于多少字节,但我们不能不使用libtiff解码图像...
有没有办法在这里使用libtiff或我们需要自定义CCITT过滤器代码?
严格来说(是否可以使用 libtiff...?),是的。它涉及一些黑客攻击,但不是太多。
\n\n事实:数据将由一个条带组成,因为没有任何偏移量信息,所以我们唯一的偏移量为零。我们只需要阅读该条即可。
\n\n事实:该数据是 W*H 1 位深像素矩阵的压缩。
\n\n步骤1:估计压缩流的最大可能长度。这大约是 W*H 的 15%,即当 W=1000 且 H=1000 时,您将获得 150000 字节。该值将始终大于实际值。如果我们通过找到正确的 EI 结束图像标签而获得更好的估计,那就更好了,但不是必需的。
\n\n第 2 步:构建“虚拟”TIF 文件。这将由 形式的标头组成49 49 2a 00 AA BB CC DD,其中 0xDDCCBBAA 是估计长度加 8;接下来是我们估计的数据流;随后是 TIFF 目录。
步骤3:TIFF目录将始终具有相同的结构;其中的一些值是偏移量,并且与 IFD 位置 0xDDCCBBAA 无关。引用 TIFF6 规范(请注意,字节顺序是相反的 - Motorola,而不是 Intel 字节序):
\n\n\n\n\nRun Code Online (Sandbox Code Playgroud)\nTIFF 6.0 Specification Final\xe2\x80\x94June 3, 1992 20\n\nPutting it all together (along with a couple of less-important fields that are discussed\nlater), a sample bilevel image file might contain the following fields\n\nA Sample Bilevel TIFF File\n\nOffset Description Value\n(hex) (numeric values are expressed in hexadecimal notation)\nHeader:\n0000 Byte Order 4D4D \n0002 42 002A\n0004 1st IFD offset 00000014\nIFD:\n0014 Number of Directory Entries 000C\n0016 NewSubfileType 00FE 0004 00000001 00000000\n0022 ImageWidth 0100 0004 00000001 000007D0\n002E ImageLength 0101 0004 00000001 00000BB8\n003A Compression 0103 0003 00000001 8005 0000\n0046 PhotometricInterpretation 0106 0003 00000001 0001 0000\n0052 StripOffsets 0111 0004 000000BC 000000B6(*1)\n005E RowsPerStrip 0116 0004 00000001 00000010\n006A StripByteCounts 0117 0003 000000BC 000003A6(*2)\n0076 XResolution 011A 0005 00000001 00000696(*3)\n0082 YResolution 011B 0005 00000001 0000069E(*4)\n008E Software 0131 0002 0000000E 000006A6(*5)\n009A DateTime 0132 0002 00000014 000006B6(*6)\n00A6 Next IFD offset 00000000\nValues longer than 4 bytes:\n(*1) StripOffsets Offset0 00000008\n(*2) StripByteCounts Count0\n(*3) XResolution 0000012C 00000001\n(*4) YResolution 0000012C 00000001\n(*5) Software \xe2\x80\x9cPageMaker 4.0\xe2\x80\x9d\n(*6) DateTime \xe2\x80\x9c1988:02:18 13:59:59\xe2\x80\x9d\n
在上面,0xDDCCBBAA 实际上是 0014,所有其他偏移量都遵循。
\n\n我使用 ImageMagick 生成的单条 TIFFG4 图像进行了一些测试,并将其tiffcp转换为 1 条 CCITT 格式。那里的标题略有不同(我没有看到规范所说应该存在的软件和日期时间标签)。否则它会检查。
我们现在有一张损坏的TIFF 图像,其中有一个超长的条带,并且它位于内存中。
\n\n使用TIFFClientOpen,我们可以像访问磁盘映像一样访问它。
尝试读取第一个条带现在将导致错误并且程序中止:
\n\nTIFFFillStrip: Read error on strip 0; got 143151 bytes, expected 762826.\nRun Code Online (Sandbox Code Playgroud)\n\n通过使用TIFFSetErrorHandlerandTIFFSetErrorHandlerExt我们设置自己来拦截这个错误,并解析它,从而恢复信息143151,而不是中止。
我们需要提供回调TIFFClientOpen,但它们都非常简单:
TIFFReadWriteProc readproc(h, *ptr, n) // copy n bytes from FakeBuffer+pos into ptr, update pos to pos + n, ignore h.\nTIFFReadWriteProc writeproc // Throw an error. We don\'t write\nTIFFSeekProc seekproc // update pos appropriately\nTIFFCloseProc closeproc // do nothing\nTIFFSizeProc sizeproc // return total buffer size\nTIFFMapFileProc mapproc // Set to NULL\nTIFFUnmapFileProc unmapproc // Set to NULL\nRun Code Online (Sandbox Code Playgroud)\n\n处理确实比较尴尬、比较绕,但是就可行性而言,\n是可以做到的。
\n\n我已经用 C 语言运行了测试,从我在网上找到的内联图像 BI/ID/EI PDF 中手动提取 CCITT 流,并按照上述方式读取它。
\n\n如果我有一种可靠的方法来识别正确的 EI - 我已经挖掘出了Tilman Hausherr 的一条消息,解释了如何识别 EI 后面的有效 PDF 运算符,以便做到这一点,这让我认为可能有\没有很多更好的方法 - 我总是可以估计正确的偏移量,并直接从 PDF 生成正确且可读的 TIFF 文件,甚至根本不涉及 libtiff。
\n