Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS Objective-C - Render JBIG2 image format

JBIG2 images have been supported in PDFs since PDF specification 1.4. Therefore all PDF reader applications can read JBIG2 images. I can confirm that a PDF containing JBIG2 images is correctly rendered on iPhone & iPad.

What I want to do is to render (or convert to PNG) a JBIG2 image from Objective-C without it having to be inside a PDF. JBIG2 images are stored inside PDF files just as a normal image object, in their own JBIG2 raw format (no conversion of any kind) so it is obvious that somewhere in iOS there is a JBIG2 decoder library, else these could not be decoded.

So how can I render a JBIG2 image on iOS without that image being inside a PDF wrapper? It's exactly the same data that exists inside that PDF image object, so it would use exactly the same decoder.

It would be a massive waste of resources to add a tiny little PDF wrapper around the JBIG2 image just to be able to render it out. This JBIG2 decoder must exist somewhere already in iOS, so how to use it?

UPDATE

If the JBIG2 decoder is not available natively in iOS then that would mean PDF readers are using their own... in this case it should be possible to rip the decoder out of an open-source PDF reader.

Here is an example PDF containing JBIG2s and raw JIBG2s: http://www.filedropper.com/jbig2samples

like image 345
Alasdair Avatar asked Jan 06 '14 09:01

Alasdair


1 Answers

First of all you're right that the native iOS (and Mac OS) frameworks do support JBIG2 images embedded in PDF data streams—actually it's part of Core Graphics.

The public API to read images in iOS is ImageIO. It extends Core Graphics by adding generic image file reading and writing functions. It creates CGImage objects that can be used in CGContexts to decompress and render. Sadly it is not able to read jbig2 image files.

On the other hand a PDF containing JBIG2 images can be rendered. That seems to be possible by Core Graphics adding custom filters to CGImage which are used only when rendering PDFs:

> 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

Displaying a PDF in Preview while running Instruments reveals the library where JBIG2 support is implemented:

Instruments analyzing Preview.app

Here's the actual library:

> 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)
...

This library seems to include some xpdf-3 code but is mostly Apple's private implementation. There are no headers for this library, so it's to be considered private, especially on iOS.

That leaves us with only one option of how to use iOS native JBIG2 decompression: You have to wrap JBIG2 files into a minimal PDF. I don't think that the runtime overhead is relevant.

Addition to illustrate comment: Code to create an image from a PDF. This assumes that the PDF consists of one page that contains the JBIG2 image borderless in 72 dpi.

// 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];
like image 71
Nikolai Ruhe Avatar answered Oct 02 '22 09:10

Nikolai Ruhe