5

自 PDF 规范 1.4 起,PDF 就支持 JBIG2 图像。因此,所有 PDF 阅读器应用程序都可以阅读 JBIG2 图像。我可以确认包含 JBIG2 图像的 PDF 在 iPhone 和 iPad 上正确呈现。

我想做的是从Objective-C渲染(或转换为PNG)JBIG2图像,而不必将它放在PDF中。JBIG2 图像存储在 PDF 文件中,就像普通图像对象一样,以它们自己的 JBIG2 原始格式(没有任何类型的转换),所以很明显,在 iOS 的某个地方有一个 JBIG2 解码器库,否则这些无法解码。

那么如何在 iOS 上呈现 JBIG2 图像而不将该图像放在 PDF 包装器中呢?它与该 PDF 图像对象中存在的数据完全相同,因此它将使用完全相同的解码器。

在 JBIG2 图像周围添加一个很小的 ​​PDF 包装器只是为了能够将其渲染出来,这将是一种巨大的资源浪费。这个 JBIG2 解码器肯定已经存在于 iOS 的某个地方,那么如何使用呢?

更新

如果 JBIG2 解码器在 iOS 中本机不可用,那么这意味着 PDF 阅读器正在使用他们自己的......在这种情况下,应该可以将解码器从开源 PDF 阅读器中剥离出来。

这是一个包含 JBIG2s 和原始 JIBG2s 的示例 PDF:http ://www.filedropper.com/jbig2samples

4

1 回答 1

9

首先,您是对的,原生 iOS(和 Mac OS)框架确实支持嵌入在 PDF 数据流中的 JBIG2 图像——实际上它是 Core Graphics 的一部分。

在 iOS 中读取图像的公共 API 是ImageIO。它通过添加通用图像文件读取和写入功能来扩展 Core Graphics。它创建CGImage可以在CGContexts 中使用的对象来解压缩和渲染。遗憾的是它无法读取 jbig2 图像文件。

另一方面,可以渲染包含 JBIG2 图像的PDF。这似乎可以通过 Core Graphics 向 CGImage 添加自定义过滤器来实现,这些过滤器仅在渲染 PDF 时使用:

> cd /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.0.sdk/System/Library/Frameworks
> nm -arch armv7 ./CoreGraphics.framework/CoreGraphics | grep jbig2
000f4f6c t _jbig2_create_state
00081e68 t _jbig2_filter_finalize
00081e44 t _jbig2_filter_refill
00081e24 t _jbig2_filter_rewind
000f500c t _jbig2_read_bytes
000f4fc0 t _jbig2_release_state
000f5064 t _jbig2_rewind
0013b78c b _jbig2_vtable
00081d9c t _pdf_source_create_jbig2_filter
001247f0 s _pdf_source_create_jbig2_filter.callbacks

在运行 Instruments 时在 Preview 中显示 PDF 会显示实现 JBIG2 支持的库:

仪器分析 Preview.app

这是实际的库:

> nm -arch armv7 ./CoreGraphics.framework/Resources/libJBIG2.dylib | c++filt
...
00001f68 unsigned short JBIG2Bitmap::JBIG2Bitmap(unsigned int, JBIG2Bitmap*)
00007adc unsigned short JBIG2Stream::readGenericBitmap(int, int, int, int, int, int, JBIG2Bitmap*, int*, int*, int)
...

这个库似乎包含一些xpdf-3代码,但主要是 Apple 的私有实现。这个库没有头文件,所以它被认为是私有的,尤其是在 iOS 上。

这让我们只有一个选择如何使用 iOS 原生 JBIG2 解压缩:您必须将 JBIG2 文件包装成最小的 PDF。我不认为运行时开销是相关的。

附加说明注释:从 PDF 创建图像的代码。这假定 PDF 包含一页,其中包含 72 dpi 的无边界 JBIG2 图像。

// create PDF document
CGPDFDocumentRef document = CGPDFDocumentCreateWithURL((__bridge CFURLRef)[NSURL fileURLWithPath:path]);

// get the first page
CGPDFPageRef page = CGPDFDocumentGetPage(document, 1);

// create a bitmap context
CGSize size = CGPDFPageGetBoxRect(page, kCGPDFMediaBox).size;
UIGraphicsBeginImageContextWithOptions(size, YES, 1);

// flip the context
CGContextTranslateCTM(UIGraphicsGetCurrentContext(), 0, mediaBox.size.height);
CGContextScaleCTM(UIGraphicsGetCurrentContext(), 1, -1);

// draw the page into the bitmap context
CGContextDrawPDFPage(UIGraphicsGetCurrentContext(), page);
CGPDFDocumentRelease(document);

// get the image from the context
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

// save image as PNG file
[UIImagePNGRepresentation(image) writeToFile:somePath atomically:YES];
于 2014-01-13T23:05:02.943 回答