Apple Developer Connection
Member Login Log In | Not a Member? Contact ADC

< Previous PageNext Page > Hide TOC

Copying PDF Data From the Clipboard (Pasteboard)

To bring PDF data back into your application you retrieve the PDF data from the pasteboard, create a Quartz data provider that copies the PDF data into a Quartz buffer, and use the provider to create a CGPDFDocumentRef object. You can call CGContextDrawPDFDocument to draw the PDF version of your picture in any graphics context. The PasteboardContainsPDF routine in Listing 4-7 is taken from the CarbonSketch sample application.

The routine checks whether the pasteboard provided to it contains PDF data. If it does, the PDF data is returned as CFData in the pdfData parameter. A detailed explanation for each numbered line of code appears following the listing.

Listing 4-7  A routine that gets PDF data from the pasteboard (Clipboard)

static Boolean PasteboardContainsPDF (PasteboardRef inPasteboard,
                                 CFDataRef* pdfData)
{
    Boolean             gotPDF      = false;
    OSStatus            err         = noErr;
    ItemCount           itemCount;
    UInt32              itemIndex;
 
    err = PasteboardGetItemCount (inPasteboard, &itemCount);// 1
    require_noerr(err, PasteboardGetItemCount_FAILED);
 
    for (itemIndex = 1; itemIndex <= itemCount; ++itemIndex)// 2
    {
        PasteboardItemID    itemID;
        CFArrayRef          flavorTypeArray;
        CFIndex             flavorCount;
        CFIndex             flavorIndex;
 
        err = PasteboardGetItemIdentifier (inPasteboard, // 3
                            itemIndex, &itemID );
        require_noerr( err, PasteboardGetItemIdentifier_FAILED );
        err = PasteboardCopyItemFlavors (inPasteboard, itemID,// 4
                                 &flavorTypeArray );
        require_noerr( err, PasteboardCopyItemFlavors_FAILED );
        flavorCount = CFArrayGetCount( flavorTypeArray );// 5
        for (flavorIndex = 0; flavorIndex < flavorCount; ++flavorIndex)
        {
            CFStringRef             flavorType;
            CFComparisonResult      comparisonResult;
 
            flavorType = (CFStringRef)CFArrayGetValueAtIndex (// 6
                                         flavorTypeArray, flavorIndex );
            comparisonResult = CFStringCompare(flavorType,// 7
                                        kUTTypePDF, 0);
            if (comparisonResult == kCFCompareEqualTo)
            {
                if (pdfData != NULL)
                {
                    err = PasteboardCopyItemFlavorData( inPasteboard,// 8
                                 itemID, flavorType, pdfData );
                    require_noerr (err,
                            PasteboardCopyItemFlavorData_FAILED );
                }
                gotPDF = true;// 9
                break;
            }
 
PasteboardCopyItemFlavorData_FAILED:
PasteboardGetItemFlavorFlags_FAILED:
        }
        CFRelease(flavorTypeArray);// 10
PasteboardCopyItemFlavors_FAILED:
PasteboardGetItemIdentifier_FAILED:
        ;
    }
PasteboardGetItemCount_FAILED:
    return gotPDF;// 11
}

Here’s what that code does:

  1. Gets the number of items on the pasteboard.

  2. Iterates through each item on the pasteboard.

  3. Gets the unique identifier for this pasteboard item.

  4. Copies the flavor types for that item ID into an array. Note that the flavor type array is a CFArrayType that you need to release later.

  5. Gets a count of the flavor types in the array. You need to iterate through these to find the PDF flavor.

  6. Gets the flavor type stored in a specific location in the array.

  7. Checks for the PDF flavor type. Note that in Mac OS X v10.4 you should use the universal type kUTTypePDF, as shown here, instead of CFSTR('com.adobe.pdf').

  8. Copies the PDF data, if any is found.

  9. Sets the gotPDF flag to true.

  10. Releases the array.

  11. Returns true if successful.

After you get the PDF data from the pasteboard, you can draw it in your application, using a routine similar to the DrawPDFData routine shown in Listing 4-8. The routine takes a CFDataRef data type (which is what you get from the routine in Listing 4-7 when you copy data from the pasteboard), a graphics context, and a destination rectangle. A detailed explanation for each numbered line of code appears following the listing.

Listing 4-8  A routine that draws PDF data

static void MyPDFDataRelease (void *info, const void *data, size_t size)
{
    if(info != NULL)
        CFRelease((CFDataRef)info);
}
 
static void DrawPDFData (CGContextRef ctx, CFDataRef pdfData,
                            CGRect dstRect)
{
    CGDataProviderRef   provider;
    CGPDFDocumentRef    document;
    CGPDFPageRef        page;
    CGRect              pageSize;
 
    CFRetain (pdfData);
    provider = CGDataProviderCreateWithData (pdfData, // 1
                        CFDataGetBytePtr(pdfData),
                        CFDataGetLength(pdfData), MyPDFDataRelease);
    document = CGPDFDocumentCreateWithProvider (provider);// 2
    CFRelease(provider);// 3
    page = CGPDFDocumentGetPage (document, 1);// 4
    pageSize = CGPDFPageGetBoxRect (page, kCGPDFMediaBox);// 5
 
    CGContextSaveGState(ctx);// 6
    MySetupTransform(ctx, pageSize, dstRect); // 7
// Scale pdf page into dstRect, if the pdf is too big
    CGContextDrawPDFPage (ctx, page);// 8
    CGContextRestoreGState(ctx);// 9
 
    CFRelease(document);// 10
}

Here’s what the code does:

  1. Creates a data provider to read PDF data provided to your application from a CGDataRef data source. Note that you need to supply a release function for Quartz to call when it frees the data provider.

  2. Creates a CGPDFDocument object using data supplied by the data provider you just created.

  3. Releases the data provider. You should release a data provider immediately after using it to create the CGPDFDocument object.

  4. Gets the first page of the newly created document.

  5. Gets the media box rectangle for the PDF. You need this to determine how to scale the content later.

  6. Saves the graphics state so that you can later restore it.

  7. Calls an application-defined routine to set a transform, if necessary. This routine (which you would need to write) determines whether the PDF is too big to fit in the destination rectangle, and transforms the context appropriately.

  8. Draws the PDF document into the graphics context that is passed to the DrawPDFData routine.

  9. Restores the graphics state.

  10. Releases the PDF document object.



< Previous PageNext Page > Hide TOC


Last updated: 2006-09-05




Did this document help you?
Yes: Tell us what works for you.

It’s good, but: Report typos, inaccuracies, and so forth.

It wasn’t helpful: Tell us what would have helped.
Get information on Apple products.
Visit the Apple Store online or at retail locations.
1-800-MY-APPLE

Copyright © 2007 Apple Inc.
All rights reserved. | Terms of use | Privacy Notice