Several ways to open an PDF document

Before the old project encountered a problem: iOS9 PDF Chinese will be garbled, and try a variety of methods are not good, but finally found a way to use this method to solve MuPDF
summed up in the process of solving the problem:

Several ways to open an PDF document

1. load with UIWebView

The code is very simple UIWebView / / *webView = [[UIWebView alloc] initWithFrame:self.view.bounds]; [self.view addSubview:webView]; NSString *path = [[NSBundle mainBundle] pathForResource:@ "test" ofType:@ "PDF"]; NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:path]]; [webView loadRequest:request];

2. use QLPreviewController to open

/ / initialize a QLPreviewController *previewController = QLPreviewController [[QLPreviewController alloc] init]; previewController.dataSource = self; [self.navigationController pushViewController:pageController animated:YES]; / / to two method to achieve the QLPreviewControllerDataSource display shows the number of documents / / - (NSInteger) numberOfPreviewItemsInPreviewController: (QLPreviewController * controller); / / URL - file path (ID < QLPreviewItem> previewController: (QLPreviewController) * previewItemAtIndex: (controller) NSInteger) index;

3. draw with CGContextDrawPDFPage

Draw the PDF content in the UIView – (void) drawRect: (CGRect) rect method, as follows:

UIKit Y / * Quartz2D (0, 0) |----------x | | | | | | | | (0, 0) |---------x y * - (void) drawRect: (CGRect) rect Drawing code CGContextRef {/ / context = UIGraphicsGetCurrentContext (CGContextTranslateCTM); / / adjust coordinates (context, 0, self.bounds.size.height); / / the first vertical down height the height of CGContextScaleCTM (context, 1, -1.0); / / and vertical flip / draw the PDF content CGPDFPageRef pageRef = CGPDFDocumentGetPage (pdfDocument, page); CGContextSaveGState (context); CGAffineTransform pdfTransform = CGPDFPageGetDrawingTransform (pageRef, kCGPDFCropBox, Self.bounds, 0, true); CGContextConcatCTM (context, pdfTransform); CGContextDrawPDFPage (context, pageRef); CGContextRestoreGState (context);}

What needs to be explained is that..:

  • The origin of the 2D Quartz coordinate system is in the lower left corner of the interface, and the origin of the UIKit coordinate system is in the upper left corner, so you need to flip the canvas to get the right view;
  • Page and pdfDocument are needed in the method, and CGContextDrawPDFPage is drawn by page numbers;

Add UIPageViewController to display, flip the effect of leverage (see the specific effects of the last Demo).

By the way, use UIPageViewController

  • UIPageViewControllerde feels like a book, each page is an UIViewController page, the contents of drawing in UIViewController’s view, flip effect comes, as long as you draw a good picture to show good;
  • When you initialize a UIPageViewControllerde object, you need to load the first page to avoid a blank page at the beginning;
  • Write a page in the following method and the call logic on the next page;
Loading a page / / call - (void) setViewControllers: (nullable NSArray< UIViewController *> *) viewControllers direction: (UIPageViewControllerNavigationDirection) direction animated: (BOOL) animated (completion: (void ^ __nullable) (BOOL finished) completion); / / on a page view controller (UIViewController *) pageViewController: (* UIPageViewController) pageViewController viewControllerBeforeViewController: (UIViewController * viewController) / / next page view controller (UIViewController) pageViewController: (UIPageViewController * pageViewController) viewControllerAfterViewController: (UIViewController * viewController)
  • The contents of the UIPageViewControllerde show no scaling function, so you need to add it yourself. I embed a layer of UIScrollView in the UIViewController view, set its scaling factor minimumZoomScale, maximumZoomScale, and then implement the following proxy method to implement scaling.
- (nullable, UIView *) viewForZoomingInScrollView: (UIScrollView *) scrollView

Of course, this can be done in other ways, such as: UIPinchGestureRecognizer

The use of the 4.MuPDF class library

MuPDF official website:

4.1 generate dependency packs

  1. Source code download: git, clone, –recursive, git://;
  2. When the download is complete, enter the mupdf/platform/ios directory;
  3. Open MuPDF project;
  4. Modify the project Build Configuration for Release;
  5. Select the iPhone simulator to run the project, which will generate the.A package of the i386 or x86_64 structure (depending on the type of simulator you choose);
  6. Connect your iPhone, modify your own bundle identifier certificate and provisioning profile, run the program in the real environment, it will generate armv7 arm64 framework.A package;
  7. Similarly, modifying the project’s Build Configuration is Debug and can generate Debug corresponding.A packages;
  8. When you go to mupdf/build/, you’ll find folders under each schema that contain all the packages generated after the build:
  9. Now you can use the lipo command to merge dependency packages under some architecture, which will generate a larger package;

Merge.A packages using the lipo command:

Last login: Mon Feb on console promote:~ mac$29 20:43:50 CD /Users/mac/Desktop/lib promote:lib mac$lipo -create libmupdf_arm64.a libmupdf_x86_64.a -output libmupdf.a promote:lib mac$lipo -info libmupdf.a Architectures in the fat file: libmupdf.a are: x86_64 arm64 promote:lib mac$lipo -create libmupdfthird_arm64.a libmupdfthird_x86_64.a -output libmupdfthird.a promote:lib mac$lipo -info libmupdfthird.a Architectures in the fat file: libmupdfthird.a are: x86_64 arm64 promote:lib mac$
Packages after Several ways to open an PDF document,
, Lipo
  • I’ve only merged the packages of arm64 and debug in x86_64, and if merged, i386 would be too big.

4.2 start integration

  1. Add the required source files:
    mupdf/include/mupdf directory of all the header files; all obj-c class of mupdf/platform/ios/classes path
    mupdf/platform/ios common.h common.M path;
  2. Add a good dependency package before you add it to your project;
  3. Configure your project’s Library Search Path, add a path that relies on packages, and
    , for example: $(inherited) $(PROJECT_DIR) /External/MuPDF/lib/
  4. The #include file “mupdf/fitz.h” reference library, use the compiler of include, so the header file absolute path = search path + relative path, so you need to configure the Header Search Paths as the search path “$(SRCROOT) /OpenPFDemo/ThirdLib/include”;

Now you should be able to run your program (see the Demo for specific file directories).

4.3 tips:

  1. Due to the dependence after the merger of the package is relatively large, so in order to reduce the size of your App, you can configure the two path:
    add a dependency of mupdf/build/release-ios-armv7-arm64 path in the release folder;
    build/debug-ios-arm64 and debug-ios-x86_64 mupdf/ add merge path after the package in the debug folder;
  2. In your project configuration Library Search Path, configure the paths of Debug and Release, respectively;

So you in the simulator and real machine Debug environment is the use of dependent Debug corresponding to the package, use when packaging is dependent on the Release corresponding to the package, but does not contain other dependencies.

4.4 note

  • According to the integration steps of the question and answer above stackoverflow, there will be some discrepancy between the current version of the MuPDF version, so I modified it;
  • Since this library contains many platforms (see the platform folder), it is large enough to be used when the full download is complete;
  • When the download is complete, you run the iOS code and find the wrong (xcode7.0)
    I used because the pdf_write_document (CTX, IDoc, TMP, &amp, opts) methods can not be found.

Solution: the pdf_write_document (CTX, IDoc, TMP, &amp, opts) in MuDocumentController.m is changed to pdf_create_document (CTX);

4.6 use open PDF

  • First, initialize the parameters after the program starts:
Enum {ResourceCacheMaxSize = 128< < /**< 20; use at most 128M for resource cache * /}; queue = dispatch_queue_create (com.artifex.mupdf.queue, NULL); CTX = fz_new_context (NULL, NULL, ResourceCacheMaxSize); fz_register_document_handlers (CTX);
  • Then call the following method to open:
- (void) openMuPDF: (NSString * path) name: (NSString * name) {_filePath = malloc (strlen ([path UTF8String]); strcpy (+1) _filePath, [path UTF8String]); dispatch_sync (queue, ^{}); printf ("open document'%s'/n", _filePath); _filename [name = retain]; doc = [[MuDocRef alloc] initWithFilename:_filePath]; if (! DOC) {return}; if (fz_needs_password (CTX, doc-> DOC)) {[self askForPassword: @'%@'needs a password: "];} else {[self onPasswordOkay];}} - (void) askForPassword: (NSString*) prompt *passwordAlertView alloc] initWithTitle: {UIAlertView = [[UIAlertView @ Password Protected" Message: [NSString stringWithFormat: prompt, [_filename lastPathComponent]] delegate: self cancelButtonTitle: @ otherButtonTitles: @ "Cancel" "Done", nil] [passwordAlertView setAlertViewStyle:; UIAlertViewStyleSecureTextInput]; [passwordAlertView release]; show] passwordAlertView;} - (void) onPasswordOkay [[MuDocumentController alloc] initWithFilename:_filename {MuDocumentController *document = path:_filePath document:doc]; if (document) {[self setTitle: @ [[self navigationController] "Library"]; pushViewController:document animated:YES]; [document release];} [_filename rel Ease]; free (_filePath);}

Demo download link: OpenPDFDemo