Innovaptor Logo

Splitting PDF into Pages on iOS

For a recent project, we had to split a PDF document with any number of pages into single PDF files that contained exactly one page of the source file each. The splitting had to be done by the app itself, and the text in the resulting documents had to be select- and copyable.

The function I created to that purpose takes a NSURL pointing to the source file, the base name for the generated output-files and a directory (which is relative to the application’s Documents folder) where the output-files are being saved.

So without further ado, here’s what I came up with:

-(void)splitPDF:(NSURL *)sourcePDFUrl withOutputName:(NSString *)outputBaseName intoDirectory:(NSString *)directory
    // Reference to the Document
    CGPDFDocumentRef SourcePDFDocument = CGPDFDocumentCreateWithURL((__bridge CFURLRef)sourcePDFUrl);
    // Get the number of pages in the Document
    size_t numberOfPages = CGPDFDocumentGetNumberOfPages(SourcePDFDocument);

    // Check the directory and create if not existent
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *filePathAndDirectory = [documentsDirectory stringByAppendingPathComponent:directory];
    NSError *error;
    if (![[NSFileManager defaultManager] createDirectoryAtPath:filePathAndDirectory
        NSLog(@"Create directory error: %@", error);
    // PDFPageReferences start to count the page numbers from 1 rather than 0
    for(int currentPage = 1; currentPage <= numberOfPages; currentPage ++ )
        // Iterate over all PDF-Pages in the Source-Document
        // Reference to Page current Page
        CGPDFPageRef SourcePDFPage = CGPDFDocumentGetPage(SourcePDFDocument, currentPage);
        // CoreGraphics: MUST retain the Page-Refernce manually

        // Build Path for the Output-File based on the directory, outputBaseName and current Page
        NSString *relativeOutputFilePath = [NSString stringWithFormat:@"%@/%@%d.pdf", directory, outputBaseName, currentPage];
        NSString *pdfFileName = [documentsDirectory stringByAppendingPathComponent:relativeOutputFilePath];

        // Get the Size of the Page in the Source-PDF
        CGRect sourceRect = CGPDFPageGetBoxRect(SourcePDFPage, kCGPDFMediaBox);
        // Start PDF-Context for the File --> if not existent, the file will be created
        UIGraphicsBeginPDFContextToFile(pdfFileName, sourceRect, nil);
        // Start a ne PDF-Page --> MUST be done!!!
        // Get the current Context
        CGContextRef context = UIGraphicsGetCurrentContext();
        // Flip the context so that the PDF page is rendered right side up.
        CGContextTranslateCTM(context, 0.0, sourceRect.size.height);
        CGContextScaleCTM(context, 1.0, -1.0);
        // Draw the PDF Page into the new Page
        CGContextDrawPDFPage(context, SourcePDFPage);
        // Close the PDF-Context which also writes the PDF to disk
        // Manually release the Source PDFPage Referene
Markus Chmelar Portrait

Markus Chmelar, MSc

Markus is a technical mastermind and one of the founders of Innovaptor. He studied Computer Engineering at Vienna University of Technology and contributes a valuable diversification to Innovaptor's qualifications. Markus is eager to find innovative solutions to complex problems in order to provide products that are tailored directly to the customers' needs