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

< Previous PageNext Page > Hide TOC

Reading and Writing Picture Data

This section provides examples of how you can read and write picture data for the purpose of converting it to PDF or another Quartz-compatible format. Some general strategies include the following:

Avoiding PICT Wrappers for Bitmap Images

A popular strategy used by QuickDraw developers is to create a PICT wrapper around a bitmap image. With a bitmap image inside a PICT container, the picture acts as a transport mechanism for the image. If the bitmap is a JPEG or other image data, it’s best to create a CGImage from that data. For example, you can draw the bitmap to a bitmap graphics context and then create a CGImage by calling the function CGBitmapContextCreateImage (available starting in Mac OS X v10.4). If the bitmap is JPEG or PNG data, you can use CGImageCreateWithJPEGDataProvider or CGImageCreateWithPNGDataProvider to create a CGImage.

PICT uses a vector-based format. If you use the CopyBits function to create a PICT representation of a bitmap image by opening a QuickDraw picture, and copying an image onto itself (by specifying the same pixel map as source and destination), then you replace the vector-based format with at bit-based one. In general, the wrapper strategy in QuickDraw is not a good one. As you move your code to Quartz, you’ll want to convert PICTs to PDF documents. There is no need to create PICT wrappers to do so.

PDF is the format used to copy-and-paste between applications in Mac OS X. It’s also the metafile format for Quartz because PDF is resolution independent. Although you can use a PDF wrapper for a bitmap image (just as PICT has been used) if you wrap a PDF with a bitmap image, the bitmap is limited by resolution at which it was created.

To convert existing PICT images to PDF documents, you can use the QuickDraw QDPict API. This API is declared in the interface file QDPictToCGContext.h in the Application Services framework. Note that if a QuickDraw picture contains drawing operations such as CopyBits that use transfer modes that don’t have an analogue in PDF, the PDF representation may not look exactly the same.

The QDPict API includes these data types and functions:

Creating a QDPict Picture From Data in Memory

To create a QDPict picture from picture data in memory, you call QDPictCreateWithProvider and supply the data using a Quartz data provider. When you create the provider, you pass it a pointer to the picture data—for example, by dereferencing a locked PicHandle.

When using the functions QDPictCreateWithURL and QDPictCreateWithProvider, the picture data must begin at either the first byte or the 513th byte. The picture bounds must not be an empty rectangle.

Listing 4-1 shows how to implement this method using two custom functions—a creation function, and a release function associated with the data provider. A detailed explanation of each numbered line of code follows the listing.

Listing 4-1  Routines that create a QDPict picture from PICT data

QDPictRef MyCreateQDPictWithData (void *data, size_t size)
{
    QDPictRef picture = NULL;
 
    CGDataProviderRef provider =
    CGDataProviderCreateWithData (NULL, data, size, MyReleaseProc);// 1
 
    if (provider != NULL)
    {
        picture = QDPictCreateWithProvider (provider);// 2
        CFRelease (provider);
    }
 
    return picture;
}
 
void MyReleaseProc (void *info, const void *data, size_t size)// 3
{
    if (info != NULL) {
        /* release private information here */
    };
 
    if (data != NULL) {
        /* release picture data here */
    };
}

Here’s what the code does:

  1. Creates a Quartz data provider for your picture data. The parameters are private information (not used here), the address of the picture data, the size of the picture data in bytes, and your custom release function.

  2. Creates and returns a QDPict picture unless the picture data is not valid.

  3. Handles the release of any private resources when the QDPict picture is released. This is a good place to deallocate the picture data, if you’re finished using it.

Creating a QDPict Picture From a PICT File

To create a QDPict picture from picture data in a PICT file, you call QDPictCreateWithURL and specify the file location with a Core Foundation URL. Listing 4-2 shows how to implement this method using an opaque FSRef file specification.

Listing 4-2  A routine that creates a QDPict picture using data in a PICT file

QDPictRef MyCreateQDPictWithFSRef (const FSRef *file)
{
    QDPictRef picture = NULL;
 
    CFURLRef url = CFURLCreateFromFSRef (NULL, file);
    if (url != NULL)
    {
        picture = QDPictCreateWithURL (url);
        CFRelease(url);
    }
 
    return picture;
}

Converting QDPict Pictures Into PDF Documents

Listing 4-3 shows how to write a function that converts a QDPict picture into a PDF document stored in a file. A detailed explanation of each numbered line of code follows the listing. (Source code to create the URL and the optional PDF auxiliary information dictionary is not included here.)

Listing 4-3  Code that converts a picture into a single-page PDF document

void MyConvertQDPict (QDPictRef picture, CFURLRef url,
                        CFDictionaryRef dict)
{
    CGContextRef context = NULL;
    CGRect bounds = QDPictGetBounds (picture);
    bounds.origin.x = 0;
    bounds.origin.y = 0;
 
    context = CGPDFContextCreateWithURL (url, &bounds, dict);// 1
    if (context != NULL)
    {
        CGContextBeginPage (context, &bounds);// 2
        (void) QDPictDrawToCGContext (context, bounds, picture);// 3
        CGContextEndPage (context);// 4
        CGContextRelease (context);// 5
    }
}

Here’s what the code does:

  1. Creates a PDF graphics context that directs the PDF content stream to a URL. If the URL is a file, the filename should end with the .pdf extension. The second parameter uses the picture bounds to specify the media box. The third parameter is an optional PDF auxiliary information dictionary, which contains the title and creator of the PDF document.

  2. Begins a new page. In a PDF context, all drawing outside of an explicit page boundary is ignored. Here the page size (or media box) is the picture bounds, but you could specify any page size.

  3. Draws the picture. The drawing rectangle is identical to the picture bounds, so there is no change of scale.

  4. Ends the current PDF page.

  5. Releases the PDF context, which finalizes the PDF content stream and finishes creating the file.

Note:  Quartz provides an opaque type called CGPDFDocumentRef for working with existing PDF documents. When you need to examine, draw, or print a PDF page, you create an object of this type. CGPDFDocumentRef isn’t needed here because the objective is to create a PDF document, not to use it.

Scaling QDPict Pictures

When drawing a picture in a Quartz context, you have two ways to change the horizontal or vertical scale of the picture:

Listing 4-4 shows how to implement both types of scaling. A detailed explanation of each numbered line of code follows the listing.

Listing 4-4  A routine that uses two ways to scale a QDPict picture

void MyScaleQDPict (QDPictRef picture, CFURLRef url)
{
    float scaleXY = 2.0;
    CGRect bounds = QDPictGetBounds (picture);// 1
    float w = (bounds.size.width) * scaleXY;
    float h = (bounds.size.height) * scaleXY;
    CGRect scaledBounds = CGRectMake (0, 0, w, h);
    bounds.origin.x = 0;
    bounds.origin.y = 0;
 
    CGContextRef context = CGPDFContextCreateWithURL (url, NULL, NULL);// 2
    if (context != NULL)
    {
        /* page 1: scale without affecting patterns */
        CGContextBeginPage (context, &scaledBounds);
        (void) QDPictDrawToCGContext (context, scaledBounds, picture);// 3
        CGContextEndPage (context);
 
        /* page 2: scale everything */
        CGContextBeginPage (context, &scaledBounds);
        CGContextScaleCTM (context, scaleXY, scaleXY);// 4
        (void) QDPictDrawToCGContext (context, bounds, picture);// 5
        CGContextEndPage (context);
 
        CGContextRelease (context);
    }
}

Here’s what the code does:

  1. Creates a Quartz rectangle that represents the origin and size of the picture in user space. The resolution is 72 units per inch and the origin is (0,0).

  2. Creates a PDF context that renders into a file. The choice of PDF is arbitrary—you can draw QDPict pictures in any type of Quartz graphics context.

  3. Draws the picture into a scaled drawing rectangle. Patterns are not scaled along with the other graphic elements in the picture.

  4. Applies the scaling transform to the current transformation matrix (CTM) in the graphics context. This scaling affects all subsequent drawing.

  5. Draws the picture into a drawing rectangle with the same dimensions. This time the picture is scaled by the CTM, including patterns.


Figure 4-1  Original picture

Original picture


Figure 4-2  Scaling with a larger drawing rectangle (patterns not affected)

Scaling with a larger drawing rectangle (patterns not affected)


Figure 4-3  Scaling with a matrix transform (patterns affected)

Scaling with a matrix transform (patterns affected)



< 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