Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
QTStdCompr.c
////////// |
// |
// File: QTStdCompr.c |
// |
// Contains: Sample code for using QuickTime's standard image compression dialog routines. |
// |
// Written by: Tim Monroe |
// Based on existing code by Apple Developer Technical Support, which was itself |
// based on the code in Chapter 3 of Inside Macintosh: QuickTime Components. |
// |
// Copyright: © 1998 by Apple Computer, Inc., all rights reserved. |
// |
// Change History (most recent first): |
// |
// <4> 02/03/99 rtm reworked prompt and filename handling to remove "\p" sequences |
// <3> 04/23/98 rtm added extended procedures support; everything seems to work |
// fine on both Mac and Windows |
// <2> 04/22/98 rtm revised to personal coding style and made cross-platform |
// <1> 12/04/94 khs first file |
// |
// This sample code illustrates how to use QuickTime's standard image compression dialog routines |
// to get compression settings from the user and to compress an image using those settings. See |
// Chapter 3 of Inside Macintosh: QuickTime Components for complete information on the standard |
// image compression dialog routines. |
// |
// In this sample, we prompt the user to open an image file; then we display the standard image |
// compression dialog box and use the settings selected by the user to compress the image. The |
// Standard Image Compression Dialog Component currently supports three sources for the image: |
// |
// (1) a PICT handle |
// (2) a PICT file |
// (3) a pixel map |
// |
// The most general of these is the pixel map, so we'll use that throughout this sample. We can |
// create a pixel map by opening an image file and drawing it into an offscreen graphics world. |
// By using the graphics importer routines, we allow ourselves to handle ANY kind of image file for |
// which QuickTime supplies a graphics importer component. So, for free, we get support for PICT |
// files too. |
// |
// This sample also shows how to extend the basic user interface by installing a modal-dialog filter |
// function and a hook function to handle the optional custom button in the dialog box. If you don't |
// want this extended behavior, set gUseExtendedProcs to false. |
// |
// NOTES: |
// |
// *** (1) *** |
// Using the SCCompressImage function to compress a pixmap using some of the available compression |
// types (for instance, BMP) results in a block of compressed data that does not contain the required |
// headers. As a result, saving that data into a file results in an invalid image file. This is a |
// known limitation of QuickTime 3 and may be fixed in the future. Currently the only way to generate |
// these headers is to use a graphics importer to export the file as a BMP (or whatever) file. This |
// is NOT illustrated in this sample code. |
// |
// *** (2) *** |
// You can use the SCSetInfo function with the scSettingsStateType selector to retrieve a handle |
// containing the current compression settings; this might be useful if you were allowing the user |
// to compress a series of images and wanted to preserve the user's settings from one image to the |
// next (instead of reverting to the defaults for every image). Note, however, that the data in |
// that handle is byte-ordered according to the platform the code is running on. As a result, you |
// should not store that data in a file and expect that file to be valid on other platforms. To |
// get a handle of data in a platform-independent format, use the function SCGetSettingsAsAtomContainer |
// (introduced in QuickTime 3); to restore the settings in that handle, use the related function |
// SCSetSettingsAsAtomContainer. |
// |
////////// |
////////// |
// |
// header files |
// |
////////// |
#include "QTStdCompr.h" |
////////// |
// |
// global variables |
// |
////////// |
Boolean gUseExtendedProcs = true; // do we use extended procs with our dialog box? |
SCExtendedProcs gProcStruct; |
// our application's window-updating function |
extern void DoUpdateWindow (WindowRef theWindow, Rect *theRefreshArea); |
////////// |
// |
// QTStdCompr_PromptUserForImageFileAndCompress |
// Let the user select an image file and select its compression settings; then compress it. |
// |
////////// |
void QTStdCompr_PromptUserForImageFileAndCompress (void) |
{ |
SFTypeList myTypeList; |
StandardFileReply myReply; |
Rect myRect; |
GraphicsImportComponent myImporter = NULL; |
ComponentInstance myComponent = NULL; |
GWorldPtr myImageWorld = NULL; // the graphics world we draw the image in |
PixMapHandle myPixMap = NULL; |
ImageDescriptionHandle myDesc = NULL; |
Handle myHandle = NULL; |
OSErr myErr = noErr; |
////////// |
// |
// have the user select an image file |
// |
////////// |
// kQTFileTypeQuickTimeImage means any image file readable by GetGraphicsImporterForFile |
myTypeList[0] = kQTFileTypeQuickTimeImage; |
StandardGetFilePreview(NULL, 1, myTypeList, &myReply); |
if (!myReply.sfGood) |
goto bail; |
////////// |
// |
// get a graphics importer for the image file and determine the natural size of the image |
// |
////////// |
myErr = GetGraphicsImporterForFile(&myReply.sfFile, &myImporter); |
if (myErr != noErr) |
goto bail; |
myErr = GraphicsImportGetNaturalBounds(myImporter, &myRect); |
if (myErr != noErr) |
goto bail; |
////////// |
// |
// create an offscreen graphics world and draw the image into it |
// |
////////// |
myErr = NewGWorld(&myImageWorld, 0, &myRect, NULL, NULL, 0L); |
if (myErr != noErr) |
goto bail; |
// get the pixmap of the GWorld; we'll lock the pixmap, just to be safe |
myPixMap = GetGWorldPixMap(myImageWorld); |
if (!LockPixels(myPixMap)) |
goto bail; |
// set the current port and draw the image |
GraphicsImportSetGWorld(myImporter, (CGrafPtr)myImageWorld, NULL); |
GraphicsImportDraw(myImporter); |
////////// |
// |
// display the standard image compression dialog box |
// |
////////// |
// open the standard compression dialog component |
myComponent = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType); |
if (myComponent == NULL) |
goto bail; |
// set the picture to be displayed in the dialog box; passing NULL for the rect |
// means use the entire image; passing 0 for the flags means to use the default |
// system method of displaying the test image, which is currently a combination |
// of cropping and scaling; personally, I prefer scaling (your milage may vary) |
SCSetTestImagePixMap(myComponent, myPixMap, NULL, scPreferScaling); |
// install the custom procs, if requested |
// we can install two kinds of custom procedures for use in connection with |
// the standard dialog box: (1) a modal-dialog filter function, and (2) a hook |
// function to handle the custom button in the dialog box |
if (gUseExtendedProcs) |
QTStdCompr_InstallExtendedProcs(myComponent, (long)myPixMap); |
// request image compression settings from the user; in other words, put up the dialog box |
myErr = SCRequestImageSettings(myComponent); |
if (myErr == scUserCancelled) |
goto bail; |
////////// |
// |
// compress the image |
// |
////////// |
myErr = SCCompressImage(myComponent, myPixMap, NULL, &myDesc, &myHandle); |
if (myErr != noErr) |
goto bail; |
////////// |
// |
// save the compressed image in a new file |
// |
////////// |
QTStdCompr_PromptUserForDiskFileAndSaveCompressed(myHandle, myDesc); |
bail: |
if (gUseExtendedProcs) |
QTStdCompr_RemoveExtendedProcs(); |
if (myPixMap != NULL) |
if (GetPixelsState(myPixMap) & pixelsLocked) |
UnlockPixels(myPixMap); |
if (myImporter != NULL) |
CloseComponent(myImporter); |
if (myComponent != NULL) |
CloseComponent(myComponent); |
if (myDesc != NULL) |
DisposeHandle((Handle)myDesc); |
if (myHandle != NULL) |
DisposeHandle(myHandle); |
if (myImageWorld != NULL) |
DisposeGWorld(myImageWorld); |
} |
////////// |
// |
// QTStdCompr_PromptUserForDiskFileAndSaveCompressed |
// Let the user select a disk file, then write the compressed image into that file. |
// |
////////// |
void QTStdCompr_PromptUserForDiskFileAndSaveCompressed (Handle theHandle, ImageDescriptionHandle theDesc) |
{ |
StandardFileReply myReply; |
short myRefNum = -1; |
StringPtr myMoviePrompt = QTUtils_ConvertCToPascalString(kSaveMoviePrompt); |
StringPtr myMovieFileName = QTUtils_ConvertCToPascalString(kSaveMovieFileName); |
OSErr myErr = noErr; |
// do a little sanity-checking.... |
if ((theHandle == NULL) || (theDesc == NULL)) |
goto bail; |
if ((**theDesc).dataSize > GetHandleSize(theHandle)) |
goto bail; |
// prompt the user for a file to put the compressed image into; in theory, the name |
// should have a file extension appropriate to the type of compressed data selected by the user; |
// this is left as an exercise for the reader |
StandardPutFile(myMoviePrompt, myMovieFileName, &myReply); |
if (!myReply.sfGood) |
goto bail; |
HLock(theHandle); |
// create and open the file |
myErr = FSpCreate(&myReply.sfFile, kImageFileCreator, (**theDesc).cType, 0); |
if (myErr == noErr) |
myErr = FSpOpenDF(&myReply.sfFile, fsRdWrPerm, &myRefNum); |
if (myErr == noErr) |
myErr = SetFPos(myRefNum, fsFromStart, 0); |
// now write the data in theHandle into the file |
if (myErr == noErr) |
myErr = FSWrite(myRefNum, &(**theDesc).dataSize, *theHandle); |
if (myErr == noErr) |
myErr = SetFPos(myRefNum, fsFromStart, (**theDesc).dataSize); |
if (myErr == noErr) |
myErr = SetEOF(myRefNum, (**theDesc).dataSize); |
if (myRefNum != -1) |
myErr = FSClose(myRefNum); |
bail: |
free(myMoviePrompt); |
free(myMovieFileName); |
HUnlock(theHandle); |
} |
////////// |
// |
// QTStdCompr_InstallExtendedProcs |
// Install the modal-dialog filter function and the hook function. |
// |
////////// |
void QTStdCompr_InstallExtendedProcs (ComponentInstance theComponent, long theRefCon) |
{ |
StringPtr myButtonTitle = QTUtils_ConvertCToPascalString(kButtonTitle); |
// the modal-dialog filter function can be used to handle any events that |
// the standard image compression dialog handler doesn't know about, such |
// as any update events for windows owned by the application |
gProcStruct.filterProc = NewSCModalFilterProc(QTStdCompr_FilterProc); |
// the hook function can be used to handle clicks on the custom button |
gProcStruct.hookProc = NewSCModalHookProc(QTStdCompr_ButtonProc); |
// in this example, we pass the pixel map handle as a refcon |
gProcStruct.refcon = theRefCon; |
// copy the string for our custom button into the extended procs structure |
BlockMove(myButtonTitle, gProcStruct.customName, 9); |
// set the current extended procs |
SCSetInfo(theComponent, scExtendedProcsType, &gProcStruct); |
free(myButtonTitle); |
} |
////////// |
// |
// QTStdCompr_RemoveExtendedProcs |
// Remove the modal-dialog filter function and the hook function. |
// |
////////// |
void QTStdCompr_RemoveExtendedProcs (void) |
{ |
// clear out the extended procedures |
SCSetInfo((ComponentInstance)gProcStruct.refcon, scExtendedProcsType, NULL); |
// dispose of routine descriptors |
DisposeRoutineDescriptor(gProcStruct.filterProc); |
DisposeRoutineDescriptor(gProcStruct.hookProc); |
} |
////////// |
// |
// QTStdCompr_FilterProc |
// Filter events for a standard modal dialog box. |
// |
////////// |
PASCAL_RTN Boolean QTStdCompr_FilterProc (DialogPtr theDialog, EventRecord *theEvent, short *theItemHit, long theRefCon) |
{ |
#pragma unused(theDialog, theItemHit, theRefCon) |
Boolean myEventHandled = false; |
WindowRef myWindow = NULL; |
switch (theEvent->what) { |
case updateEvt: |
// update the specified window, if it's behind the modal dialog |
myWindow = (WindowRef)theEvent->message; |
if ((myWindow != NULL) && (myWindow != theDialog)) { |
DoUpdateWindow(myWindow, &(**(myWindow->visRgn)).rgnBBox); |
myEventHandled = false; // so sayeth IM |
} |
break; |
} |
return(myEventHandled); |
} |
////////// |
// |
// QTStdCompr_ButtonProc |
// Handle item selections in the standard image compression dialog box. |
// |
// The theParams parameter is the component instance of the standard image compression |
// dialog component. Also, the theRefCon paramter is handle to our pixel map. |
// |
////////// |
PASCAL_RTN short QTStdCompr_ButtonProc (DialogPtr theDialog, short theItemHit, void *theParams, long theRefCon) |
{ |
#pragma unused(theDialog) |
// in this sample code, we'll have the settings revert to their default values |
// when the user clicks on the custom button |
if (theItemHit == scCustomItem) |
SCDefaultPixMapSettings(theParams, (PixMapHandle)theRefCon, false); |
// always return the item passed in |
return(theItemHit); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14