Mac OS X Reference Library Apple Developer
Search

QTGraphImp.c

//////////
//
//  File:       QTGraphImp.c
//
//  Contains:   Sample code for using QuickTime's graphics import routines.
//
//  Written by: Tim Monroe
//              Based loosely on the SimpleGIExample.c code written by Apple DTS;
//              exporting code based heavily on Dispatch 14 from the Ice Floe by Sam Bushell.
//
//  Copyright:  © 1998 by Apple Computer, Inc., all rights reserved.
//
//  Change History (most recent first):
//
//     <3>      03/21/00    rtm     reworked functions to avoid calling Standard File Package
//     <2>      06/02/98    rtm     added QTGraphImp_ExportGWorldToFile and _GetAvailableExportTypes,
//                                  from Dispatch 14 from the Ice Floe; added QTGraphImp_ExportImageFile
//     <1>      04/14/98    rtm     first file
//     
//  This sample code illustrates how to use QuickTime's graphics importer routines
//  to open and display image files. The graphics importer routines were introduced
//  in QuickTime version 2.5 as a new way to draw still images. The graphics import
//  routines (for example, GetGraphicsImporterForFile) use graphics import components
//  (of component type 'grip') to open and perform other operations on image files.
//  Essentially, you can use the graphics import routines to insulate your application
//  from the nitty gritty details of the image file format and compression used in the
//  image.
//
//  This code also shows how to export images as picture files, and how to determine which
//  formats an image can be exported in. The QT functions that support these operations
//  were introduced in QuickTime version 3.
//
//  In this sample code, we allow the user to open an image file; then we draw it into
//  a window on the screen. Your application, of course, will probably want to do more
//  interesting things with the image. We also allow the user to save an image using JPEG
//  compression.
//
//////////
 
//////////
//
// header files
//
//////////
 
#include "QTGraphImp.h"
 
 
//////////
//
// global variables
//
//////////
 
WindowPtr                       gImageWindow = NULL;    // the window we display the image in
GraphicsImportComponent         gImporter = NULL;
 
 
//////////
//
// QTGraphImp_OpenImageFileAndDisplay
// Open an image file, then display the image in a window.
//
//////////
 
void QTGraphImp_OpenImageFileAndDisplay (FSSpecPtr theFSSpecPtr)
{
    Rect                        myRect;
    OSErr                       myErr = noErr;
 
    if (theFSSpecPtr == NULL)
        goto bail;
    
    //////////
    //
    // get a graphics importer for the image file and determine the natural size of the image
    //
    //////////
 
    myErr = GetGraphicsImporterForFile(theFSSpecPtr, &gImporter);
    if (myErr != noErr)
        goto bail;
    
    myErr = GraphicsImportGetNaturalBounds(gImporter, &myRect);
    if (myErr != noErr)
        goto bail;
    
    //////////
    //
    // create a window to display the image in; then draw into that window
    //
    //////////
    
    MacOffsetRect(&myRect, 50, 50);
    gImageWindow = NewCWindow(NULL, &myRect, theFSSpecPtr->name, true, movableDBoxProc, (WindowPtr)-1L, true, 0);
    if (gImageWindow == NULL)
        goto bail;
    
    // set the current port and draw
    GraphicsImportSetGWorld(gImporter, GetWindowPort(gImageWindow), NULL);
    GraphicsImportDraw(gImporter);
    
bail:
    if (myErr != noErr)
        if (gImporter != NULL)
            CloseComponent(gImporter);
}
 
 
//////////
//
// QTGraphImp_SaveCompressedImageIntoDiskFile
// Compress the current picture into the specified file.
//
//////////
 
void QTGraphImp_SaveCompressedImageIntoDiskFile (FSSpecPtr theFSSpecPtr)
{
    Rect                        myRect;
    GWorldPtr                   myGWorld;
    OSErr                       myErr = noErr;
 
    if (theFSSpecPtr == NULL)
        goto bail;
 
    // get the natural size of the image
    myErr = GraphicsImportGetNaturalBounds(gImporter, &myRect);
    if (myErr != noErr)
        goto bail;
 
    // create an offscreen graphics world to draw the image into
    myErr = NewGWorld(&myGWorld, 0, &myRect, NULL, NULL, 0);
    if (myErr == noErr) {
        GraphicsImportSetGWorld(gImporter, (CGrafPtr)myGWorld, NULL);
        GraphicsImportDraw(gImporter);
        
        // save the compressed image
        QTGraphImp_SaveCompressedImage(myGWorld, theFSSpecPtr);
        if (myGWorld != NULL)
            DisposeGWorld(myGWorld);
    }
 
bail:
    ;
}
 
 
//////////
//
// QTGraphImp_SaveCompressedImage
// Save the current image as a compressed file.
//
//////////
 
void QTGraphImp_SaveCompressedImage (GWorldPtr theWorld, FSSpec *theFile)
{
    ImageDescriptionHandle      myDesc;
    Handle                      myData;
    Rect                        myRect;
    PixMapHandle                myPixMap;   
    CTabHandle                  myCTab = NULL;
    ICMFlushProcRecord          myFlushProc;
    short                       myRefNum;
    short                       myDepth;
    OSErr                       myErr = noErr;
 
    if ((theWorld == NULL) || (theFile == NULL))
        goto bail;
        
    myDesc = (ImageDescriptionHandle)NewHandle(sizeof(ImageDescription));
    if (myDesc == NULL)
        goto bail;
 
#if TARGET_OS_MAC
    GetPortBounds(theWorld, &myRect);
#endif
#if TARGET_OS_WIN32
    myRect = theWorld->portRect;
#endif
 
    myPixMap = GetGWorldPixMap(theWorld);
    
    if (LockPixels(myPixMap)) {
    
        // if less than 16-bit, then get the color table of our GWorld
        myDepth = (**myPixMap).pixelSize;
        if (myDepth < 16)
            myCTab = (**myPixMap).pmTable;
        
        myData = NewHandle(kBufferSize);
        myErr = MemError();
        
        if ((myData != NULL) && (myErr == noErr)) {
            CodecType           myCodec = kJPEGCodecType;
            
            HLock(myData);
                                                        
            myErr = FSpCreate(theFile, kImageFileCreator, kQTFileTypeJPEG, 0);
            
            if (myErr == noErr)
                myErr = FSpOpenDF(theFile, fsRdWrPerm, &myRefNum);
                
            if (myErr == noErr)
                myErr = SetFPos(myRefNum, fsFromStart, 0);
                
            if (myErr == noErr) {
                ICMFlushProcRecordPtr       myFlushProcPtr = NULL;
                
#if USE_FLUSH_PROC
                myFlushProc.flushProc = NewICMFlushProc(QTGraphImp_DataUnloadProc);
                myFlushProc.flushRefCon = myRefNum;
                myFlushProcPtr = &myFlushProc;
#else
                myFlushProcPtr = NULL;
#endif
                // compress the image
                myErr = FCompressImage( myPixMap,
                                        &myRect,
                                        myDepth,
                                        codecNormalQuality,
                                        myCodec,
                                        anyCodec,
                                        myCTab,
                                        codecFlagWasCompressed,
                                        kBufferSize,
                                        myFlushProcPtr,
                                        NULL,
                                        myDesc,
                                        *myData);
            
#if !USE_FLUSH_PROC
                if (myErr == noErr)
                    myErr = FSWrite(myRefNum, &(**myDesc).dataSize, *myData);
#endif
                
                if (myErr == noErr)
                    myErr = SetFPos(myRefNum, fsFromStart, (**myDesc).dataSize);
 
                if (myErr == noErr)
                    myErr = SetEOF(myRefNum, (**myDesc).dataSize);
                             
                if (myErr == noErr)     
                    myErr = FSClose(myRefNum);
                
                HUnlock(myData);
                DisposeHandle(myData);
                
#if USE_FLUSH_PROC
                DisposeRoutineDescriptor(myFlushProc.flushProc);
#endif
            }
        }
    }
    
    UnlockPixels(myPixMap);
 
bail:   
    if (myDesc != NULL)
        DisposeHandle((Handle)myDesc);
}           
 
 
//////////
//
// QTGraphImp_DataUnloadProc
// A data unloading procedure: write the compressed data to disk.
//
// The theRefCon parameter is assumed to be a file reference number of an open file.
//
//////////
 
PASCAL_RTN OSErr QTGraphImp_DataUnloadProc (Ptr theData, long theBytesNeeded, long theRefCon)
{
    OSErr       myErr = noErr;
    
    if (theData == NULL) {
        // if data is NULL, set a new position in the file from the current mark, offset by bytesNeeded
        myErr = SetFPos(theRefCon, fsFromMark, theBytesNeeded);
    } else {
        // otherwise, write the specified data to disk
        myErr = FSWrite(theRefCon, &theBytesNeeded, theData);
    }
    
    return(myErr);
}
 
 
//////////
//
// QTGraphImp_ExportGWorldToFile
// Save the image in a graphics world to the specified file.
//
// Use this function when you've got an image that you want to export to a file
// but that image wasn't read in from a file (in which case you could just use
// the GetGraphicsImporterForFile function to open an appropriate graphics importer).
//
// Based on the function ExportGWorldToFile in Dispatch 14 from the Ice Floe.
//
//////////
 
OSErr QTGraphImp_ExportGWorldToFile (GWorldPtr theWorld, FSSpec *theFile, OSType theType)
{
    PicHandle                   myPicture = NULL;
    PixMapHandle                myPixMap = NULL;
    GraphicsImportComponent     myImporter = NULL;
    Handle                      myHandle = NULL;
    CGrafPtr                    mySavedGW;
    GDHandle                    mySavedGD;
    Rect                        myRect;
    OSErr                       myErr = noErr;
 
    // save the current graphics world, and set the specified graphics world as current
    GetGWorld(&mySavedGW, &mySavedGD);
    SetGWorld(theWorld, NULL);
    
    mySrcPixMap = GetGWorldPixMap(theWorld);
 
#if TARGET_OS_MAC
    GetPortBounds(theWorld, &myRect);
#endif
#if TARGET_OS_WIN32
    myRect = theWorld->portRect;
#endif
 
    // capture the contents of the specified graphics world in a picture handle
    myPicture = OpenPicture(&((GrafPtr)theWorld)->portRect);
    CopyBits(   (BitMapPtr)*myPixMap,
                (BitMapPtr)*myPixMap,
                &myRect,
                &myRect,
                srcCopy,
                NULL);
                  
    ClosePicture();
 
    // convert the picture handle into a handle-based PICT file by adding a 512-byte header to the start;
    // 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 exist, for historical reasons
    myHandle = NewHandleClear(512);
    myErr = MemError();
    if (myErr != noErr)
        goto bail;
 
    myErr = HandAndHand((Handle)myPicture, myHandle);
    if (myErr != noErr)
        goto bail;
 
    // open an instance of the picture file graphics importer
    myErr = OpenADefaultComponent(GraphicsImporterComponentType, kQTFileTypePicture, &myImporter);
    if (myErr != noErr)
        goto bail;
 
    myErr = GraphicsImportSetDataHandle(myImporter, myHandle);
    if (myErr != noErr)
        goto bail;
 
    // export the image to a file
    myErr = GraphicsImportExportImageFile(myImporter, theType, kImageFileCreator, theFile, smSystemScript);
 
bail:
    // restore the original graphics world
    SetGWorld(mySavedGW, mySavedGD);
    
    if (myPicture != NULL)
        KillPicture(myPicture);
    
    if (myImporter != NULL)
        CloseComponent(myImporter);
    
    if (myHandle != NULL)
        DisposeHandle(myHandle);
    
    return(myErr);
}
 
 
//////////
//
// QTGraphImp_GetAvailableExportTypes
// Get a list of the available image export file types.
//
// Based on a function in Dispatch 14 from the Ice Floe.
//
//////////
 
OSErr QTGraphImp_GetAvailableExportTypes (GraphicsImportComponent theImporter)
{
    QTAtomContainer             myContainer = NULL;
    short                       myCount, myIndex;
    OSErr                       myErr = noErr;
 
    // get an atom container that contains one or more kGraphicsExportGroup atoms;
    // each export group atom represents a single export format and has child atoms that indicate
    // the file type (kGraphicsExportFileType), a human-readable name (kGraphicsExportDescription),
    // a file extension (kGraphicsExportExtension) and a MIME type (kGraphicsExportMIMEType)
    myErr = GraphicsImportGetExportImageTypeList(theImporter, &myContainer);
    if (myErr != noErr)
        goto bail;
 
    myCount = QTCountChildrenOfType(myContainer, kParentAtomIsContainer, kGraphicsExportGroup);
    for (myIndex = 1; myIndex <= myCount; myIndex++) {
        QTAtom                  myGroupAtom;
 
        myGroupAtom = QTFindChildByIndex(myContainer, kParentAtomIsContainer, kGraphicsExportGroup, myIndex, NULL);
        if (myGroupAtom != 0) {
            QTAtom              myTypeAtom;
            
            myTypeAtom = QTFindChildByIndex(myContainer, myGroupAtom, kGraphicsExportFileType, 1, NULL);
            if (myTypeAtom != 0) {
                OSType          myType;
                
                myErr = QTCopyAtomDataToPtr(myContainer, myTypeAtom, false, sizeof(myType), &myType, NULL);
                // the data in QT atoms is always big-endian, so convert the file type to native format
                myType = EndianU32_BtoN(myType);
                
                // at this point, you probably want to do something interesting with the file type, eh?
                // this is left as an exercise for the reader
                
            } else {
                myErr = cannotFindAtomErr;
            }
        }
    }
 
bail:
    if (myContainer != NULL)
        QTDisposeAtomContainer(myContainer);
    return(myErr);
}
 
 
//////////
//
// QTGraphImp_ExportImageFile
// Let the user select a disk file, then export the current picture into that file.
//
//////////
 
OSErr QTGraphImp_ExportImageFile (GraphicsImportComponent theImporter)
{
    OSType                  myType;
    FSSpec                  myFSSpec;
    OSErr                   myErr = noErr;
 
    myErr = GraphicsImportDoExportImageFileDialog(
                            theImporter, 
                            NULL,           // no default name for the file
                            NULL,           // use the default prompt in the dialog box
                            NULL,           // no modal dialog filter procedure
                            &myType,        // return the type of the selected file
                            &myFSSpec,      // return the name (etc.) of the selected file
                            NULL);          // don't return the script code
    return(myErr);
}



Last updated: 2003-01-14

Did this document help you? Yes It's good, but... Not helpful...