Search code examples
objective-ccocoapdfquartz-2d

Saving a PDF document to disk using Quartz


I am trying to draw a pdf page onto a pdf context and then save it to disk. I cannot seem to figure out what is wrong. Can someone give me a few pointers. Thanks.

- (void)testQuartz:(NSData *)pdfDocumentData
{   
    //Create the pdf document reference
    CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData((CFDataRef)pdfDocumentData);
    CGPDFDocumentRef document = CGPDFDocumentCreateWithProvider(dataProvider);
    CGDataProviderRelease(dataProvider); //Release the data provider

    //Create the pdf context
    CGPDFPageRef page = CGPDFDocumentGetPage(document, 0);
    CGRect pageRect = CGPDFPageGetBoxRect(page, kCGPDFMediaBox);
    CFMutableDataRef mutableData = CFDataCreateMutable(NULL, 0);

    CGDataConsumerRef dataConsumer = CGDataConsumerCreateWithCFData(mutableData);
    CGContextRef pdfContext = CGPDFContextCreate(dataConsumer, &pageRect, NULL);

    if (CGPDFDocumentGetNumberOfPages(document) > 0)
    {       
        //Draw the page onto the new context
        page = CGPDFDocumentGetPage(document, 0);
        CGContextDrawPDFPage(pdfContext, page);
    }
    else
    {
        NSLog(@"Failed to create the document");
    }

    //Write to disk
    [(NSMutableData *)mutableData writeToFile:@"/Users/David/Desktop/test.pdf" atomically:YES];

    //Clean up
    CGDataConsumerRelease(dataConsumer);
    CFRelease(mutableData);
    CGPDFDocumentRelease(document);
}

Solution

  • So I found 3 things wrong with it.

    1. PDF pages start at 1 and not 0.
    2. Need to tell the pdf context when a page begins and ends.
    3. Release the pdf context prior to writing the data to disk. This is key for some reason.

    Here is the corrected code that works.

    - (void)testQuartz:(NSData *)pdfDocumentData
    {       
        //Create the pdf document reference
        CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData((CFDataRef)pdfDocumentData);
        CGPDFDocumentRef document = CGPDFDocumentCreateWithProvider(dataProvider);
    
        //Create the pdf context
        CGPDFPageRef page = CGPDFDocumentGetPage(document, 1); //Pages are numbered starting at 1
        CGRect pageRect = CGPDFPageGetBoxRect(page, kCGPDFMediaBox);
        CFMutableDataRef mutableData = CFDataCreateMutable(NULL, 0);
    
        //NSLog(@"w:%2.2f, h:%2.2f",pageRect.size.width, pageRect.size.height);
        CGDataConsumerRef dataConsumer = CGDataConsumerCreateWithCFData(mutableData);
        CGContextRef pdfContext = CGPDFContextCreate(dataConsumer, &pageRect, NULL);
    
    
        if (CGPDFDocumentGetNumberOfPages(document) > 0)
        {       
            //Draw the page onto the new context
            //page = CGPDFDocumentGetPage(document, 1); //Pages are numbered starting at 1
    
            CGPDFContextBeginPage(pdfContext, NULL);
            CGContextDrawPDFPage(pdfContext, page);
            CGPDFContextEndPage(pdfContext);
        }
        else
        {
            NSLog(@"Failed to create the document");
        }
    
        CGContextRelease(pdfContext); //Release before writing data to disk.
    
        //Write to disk
        [(NSData *)mutableData writeToFile:@"/Users/David/Desktop/test.pdf" atomically:YES];
    
        //Clean up
        CGDataProviderRelease(dataProvider); //Release the data provider
        CGDataConsumerRelease(dataConsumer);
        CGPDFDocumentRelease(document);
        CFRelease(mutableData);
    }