About Graphics Importer and Exporter Components

This chapter describes what graphic importer and exporter components do and shows how to use them from within an application. A code sample is included.

Graphics Importers

Graphics importer components provide a standard method for applications to open and display still images contained within graphics documents. Graphics importer components allow you to work with any type of supported image data, regardless of the file format or compression used in the file.

You can use the graphics importer component functions to obtain a graphics importer component instance that can read graphics data from a particular file or area of memory. For example, GetGraphicsImporterForFile will attempt to locate and open a graphics importer component that can be used to draw the specified file. The component can then be used to find some characteristics of the image such as its dimensions by using GraphicsImportGetNaturalBounds and can be drawn by simply calling GraphicsImportDraw.

Alpha Channels

Some QuickTime supported file formats, such as TIFF, PNG, and Photoshop, support alpha channels; some, such as JPEG and TGA, do not. However, even if a file format supports alpha channels, not every file will contain one.

You can use graphics importers to find out whether a file has an alpha channel by calling GraphicsImportGetImageDescription and looking at the depth field in the image description. By convention, a depth of 24 means RGB without alpha, whereas 32 means ARGB.

QuickTime will not synthesize an opaque alpha channel for an image that does not have one; if the depth is 24, the first byte of each pixel will probably be 0. Developers working with alpha channels should only depend on these values if the depth is 32.

All depths of PNG files can have transparency. For example, a 4-bit indexed-color PNG file can have an opaqueness value associated with each color index. QuickTime translates these files to 32-bit ARGB in order to preserve the transparency information.

Multiple Images

Graphics importers also support image formats containing multiple images in a single file. For example, TIFF files can support multiple images, Photoshop files can contain multiple layers, and FlashPix files can contain multiple resolutions. You can use GraphicsImportGetImageCount to find out how many images are in a file, and GraphicsImportSetImageIndex to select a particular image.

Graphics Exporters

Graphics exporter components provide a standard interface for exporting graphics to image files in a variety of formats. QuickTime selects a graphic exporter component based on the desired output format, such as GIF or PNG.

The image input for an export operation can come from a QuickDraw picture, a GWorld or PixMap, a QuickTime graphics importer component instance, or a segment of compressed data described by a QuickTime image description. In the last case, the compressed data may be accessed via a pointer, handle, file or other data reference. The ouput image for an export operation can be stored in a handle, file, or other data reference. Different file formats support a wide range of configurable features, such as depth, resolution, and compression quality.

To use a graphics exporter, you must first open a graphics exporter component instance, specify the source of the input image, its destination, set whatever parameters you want, and then actually do the export.

For example, if you want to write a GWorld out to a PNG image file you would would use OpenADefaultComponent to open an instance of the kQTFileTypePNG graphics exporter component, GraphicsExportSetInputGWorld to associate the input GWorld with the export operation, GraphicsExportSetOutputFile to associate the output FSSpec with the export operation and GraphicsExportDoExport to perform the export.

Once you’re finished with component instances you can simply close them using CloseComponent.

Using QuickTime to Export a Picture as an Image File

Graphics importer components provide a simple, flexible and extensible way for you to draw pictures that are stored in a wide variety of image file formats. They also turn out to be the easiest way to export pictures to several file formats.

Typically, you create a graphics importer instance with the GetGraphicsImporterForFile call or one of its relatives. Afterwards, you can call GraphicsImportExportImageFile to export that image to a new file:

GetGraphicsImporterForFile(
                &theExistingFile,
                &gi);
 
GraphicsImportExportImageFile(
                gi,
                kQTFileTypeJPEG,      // or one of several other file types
                0,                    // ie, the default creator for this type
                &theNewFile,
                theScriptCode);

The file type determines the data format for the exported file. For example, if you pass kQTFileTypeJPEG, a JPEG file will be created.

If the picture you want to export isn’t already in a file, it doesn’t make sense to call GetGraphicsImporterForFile. Instead, you can create an instance of the “picture file” graphics importer yourself and give it a handle that contains a “source picture file.”

OpenADefaultComponent(
                GraphicsImporterComponentType,
                kQTFileTypePicture,
                &gi);
 
GraphicsImportSetDataHandle(
                gi,
                thePictureFileHandle);
 
GraphicsImportExportImageFile(
                gi,
                kQTFileTypeJPEG,
                0,
                &theNewFile,
                theScriptCode);

Picture files are just like picture handles, except that they have an extra 512-byte header at the front. (Any data in this header is usually ignored, but it must be there for historical reasons.) The graphics importer for picture files expects and skips this 512-byte header, so you must insert it.

PicHandle thePicture = /* create a picture */;
Handle thePictureFileHandle;
 
thePictureFileHandle = NewHandleClear(512);
HandAndHand((Handle)thePicture,thePictureFileHandle);

The following function exports a picture to a file. The new file is described by its type, creator, specification and script code. If you don’t know what script code to use, it’s usually safe to use smSystemScript.

#include <OSUtils.h>
#include <ImageCompression.h>
#include <QuickTimeComponents.h>
 
OSErr ExportPicHandleToFile(
    PicHandle thePicture,
    OSType filetype,
    OSType filecreator,
    FSSpec *filespec,
    ScriptCode filescriptcode)
{
    Handle h;
    OSErr err;
    GraphicsImportComponent gi = 0;
 
    // Convert the picture handle into a PICT file (still in a handle)
    // by adding a 512-byte header to the start.
    h = NewHandleClear(512);
    err = MemError();
    if(err) goto bail;
    err = HandAndHand((Handle)thePicture,h);
 
    err = OpenADefaultComponent(
                GraphicsImporterComponentType,
                kQTFileTypePicture,
                &gi);
    if(err) goto bail;
 
    err = GraphicsImportSetDataHandle(gi, h);
    if(err) goto bail;
 
    err = GraphicsImportExportImageFile(
                gi,
                filetype,
                filecreator,
                filespec,
                filescriptcode);
    if(err) goto bail;
 
bail:
    if(gi) CloseComponent(gi);
    if(h) DisposeHandle(h);
    return err;
}

Your application can find out more information about available export formats by calling the GraphicsImportGetExportImageTypeList function. This function returns an atom container (which your application must dispose of) containing several kGraphicsExportGroup atoms. Each of these represents one export format, and has child atoms which indicate the file type (kGraphicsExportFileType), human-readable format name (kGraphicsExportDescription), file extension (kGraphicsExportExtension) and optionally MIME type (kGraphicsExportMIMEType).

The code fragment in Listing 1-1 shows how you can find out the available export file types. Error-handling code has been removed.

Listing 1-1  Finding the available export file types

QTAtomContainer theExportInfo = nil;
short theNumberOfExportTypes, i;
 
GraphicsImportGetExportImageTypeList(
                gi,
                &theExportInfo);
 
theNumberOfExportTypes = QTCountChildrenOfType(
                theExportInfo,
                kParentAtomIsContainer,
                kGraphicsExportGroup);        // 'expo'
 
for(i = 1; i <= theNumberOfExportTypes; i++) {
    QTAtom groupAtom, fileTypeAtom;
    OSType fileType;
 
    groupAtom = QTFindChildByIndex(
                    theExportInfo,
                    kParentAtomIsContainer,
                    kGraphicsExportGroup,
                    i,
                    nil);
 
    fileTypeAtom = QTFindChildByIndex(
                    theExportInfo,
                    groupAtom,
                    kGraphicsExportFileType,  // 'ftyp'
                    1,
                    nil);
 
    QTCopyAtomDataToPtr(
                    theExportInfo,
                    fileTypeAtom,
                    false,
                    sizeof(fileType),
                    &fileType,
                    nil);
 
    fileType = EndianU32_BtoN(fileType);      // data in QT atoms
                                              // is always big-endian
}
QTDisposeAtomContainer(theExportInfo);