iOS Objective-C - Render JBIG2 image format
Asked Answered
A

1

5

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

Andromache answered 6/1, 2014 at 9:39 Comment(10)
did you check github.com/Borisvl/JBIG2-Image-DecoderPolyphone
Isn't that written in Java?Andromache
Yes, but you can embed java in to objective - c hints.macworld.com/article.php?story=20040321163154226Polyphone
Interesting. Isn't it less efficient to use a Java class, or would there be no noticeable difference? (Speed and efficiency is an issue here.)Andromache
You well know that there is no native lib for JBIG2 in objective-c or in c, there is little leg due to byte code but not noticeable. But i haven't tried yetPolyphone
Why do you assume the decoder is in iOS not in the PDF reader?Caesarean
I don't - it does appear to exist in the PDF readers rather than iOS, as you suggest. But that would imply that a JBIG2 decoder could then be extracted from an open-source iOS PDF reader. Either way there is a JBIG2 decoder floating around somewhere but I can't seem to get my hands on it.Andromache
Can you provide both an example PDF file containing a JBIG2 image and a pure JBIG2 image file?Infrasonic
Here is an example PDF containing JBIG2s and raw JIBG2s: filedropper.com/jbig2samplesAndromache
You can not run Java on iOS. The code snippet was for OSX. iOS does not have a JVM, nor does it allow any to be installed. Forget Java.Compo
I
9

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];
Infrasonic answered 13/1, 2014 at 23:5 Comment(9)
Thank you for your answer. The problem with using a PDF wrapper is that I want to control the margins (the JBIG2 are marginless and different margins are added depending on screen size, and orientation of the device.) I could get the app to generate its own PDF wrapper based on screen size and user preferences but then will I not lose control over scrolling animation/direction, etc.? How much control do I have with the display of a PDF file?Andromache
@Andromache You can easyly convert the PDF-wrapped JBIG2 into a CGImage by rendering into a properly sized CGBitmapContext. The (borderless) CGImage can then be displayed in a UIImageView or saved as PNG if it is needed again.Infrasonic
That's good. One more thing: does iOS include functionality for searching the PDF if it includes text in the content object of each page? (I could implement this separately but if iOS includes this already then I could add this to the PDF wrapper.)Andromache
@Andromache I don't think that Core Graphics' PDF engine supports text search, if that's what you mean. I'm not sure about that, though.Infrasonic
Thanks! +500 points for you. One last question: since I am only using the PDF wrapper to extract the JBIG2 images I will add many images into a single PDF and then will want to grab individual pages (prefetch) from this as the user scrolls through the document. My main concern is the speed and dpi of rendering (which is why I did not want to do a PDF wrapper) because I actually don't care about the mediabox & cropbox sizes in the PDF; I just want the image. In this case is there a more efficient way of rendering the page without rendering the page based on the PDF variables of mediabox, etc?Andromache
Or should I just set the cropbox & mediabox variables to pixels/72 so that it always renders the image out at 72dpi?Andromache
@Andromache (Thanks!) That's what I had in mind: creating a minimal PDF with only a single page and a mediaBox of [0 0 pixelWidth pixelHeight]. Then you render this single page PDF to an image (and throw away the PDF). Do this for all images and create a custom image viewer that shows the converted images. So PDF is only an intermediate step during conversion.Infrasonic
Sure. But it then makes more sense for me to transfer the entire document as a PDF (with all images included) to the device rather than continually wrap each individual image. Is there any disadvantage in extracting an image from a 200 page PDF instead of a 1 page PDF? It should not be difficult since PDF use objects which are all indexed. (Also I could extract several at a time for preloading.)Andromache
@Andromache No, of course you can put them all in one PDF. I was not aware that you control the creation of the JBIG2 files. So, what it boils down to is a PDF viewer that prerenders pages into images for faster display and better UX.Infrasonic

© 2022 - 2024 — McMap. All rights reserved.