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.
Common Files/ImageCompressionUtilities.c
////////// |
// |
// File: ImageCompressionUtilities.c |
// |
// Contains: Utilities for compressing images. |
// |
// Written by: Peter Hoddie, Sean Allen, Chris Flick |
// Revised by: Tim Monroe |
// |
// Copyright: © 1997-2000 by Apple Computer, Inc., all rights reserved. |
// |
// Change History (most recent first): |
// |
// <8> 11/17/00 rtm general clean-up to bring this file into conformance with style of other |
// sample code |
// <7> 03/28/00 rtm changed ((**myPixMap).rowBytes & 0x3fff) to QTGetPixMapHandleRowBytes(myPixMap) |
// <6> 03/17/00 rtm moved some things to ImageCompressionUtilities.h; made some changes for Carbon |
// <5> 02/25/00 rtm changed pascal keyword to PASCAL_RTN, for Windows compatibility |
// <4> 12/16/98 rtm removed orphaned prototype for compressTransparentRLEwithHitTesting |
// <3> 05/28/98 rtm added some typecasting to minimize MSDev compiler warnings |
// <2> 04/22/98 rtm made changes to ICUtils_RecompressPictureFileWithTransparency, as per Chris' fixes |
// <1> 03/27/98 rtm existing file |
// |
////////// |
#ifndef __IMAGECOMPRESSIONUTILITIES__ |
#include "ImageCompressionUtilities.h" |
#endif |
////////// |
// |
// ICUtils_CreateImageDescription |
// Create an image description. |
// |
////////// |
static ImageDescriptionHandle ICUtils_CreateImageDescription (CodecType theCodecType, PixMapHandle thePixmap) |
{ |
ImageDescriptionHandle myDesc = NULL; |
OSErr myErr = noErr; |
if (thePixmap == NULL) |
return(myDesc); |
myDesc = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription)); |
if (myDesc != NULL) { |
Rect myRect = (**thePixmap).bounds; |
(**myDesc).idSize = sizeof(ImageDescription); |
(**myDesc).cType = theCodecType; |
(**myDesc).spatialQuality = codecNormalQuality; |
(**myDesc).width = myRect.right - myRect.left; |
(**myDesc).height = myRect.bottom - myRect.top; |
(**myDesc).hRes = 72L << 16; |
(**myDesc).vRes = 72L << 16; |
(**myDesc).dataSize = (QTGetPixMapHandleRowBytes(thePixmap)) * (**myDesc).height; |
(**myDesc).depth = (**thePixmap).pixelSize; |
(**myDesc).clutID = -1; |
myErr = SetImageDescriptionCTable(myDesc, (**thePixmap).pmTable); |
if (myErr != noErr) { |
DisposeHandle((Handle)myDesc); |
myDesc = NULL; |
} |
} |
return(myDesc); |
} |
////////// |
// |
// ICUtils_NoDitherBitsProc |
// |
////////// |
PASCAL_RTN void ICUtils_NoDitherBitsProc (const BitMap *theSrcBits, const Rect *theSrcRect, const Rect *theDstRect, short theMode, RgnHandle theMaskRgn) |
{ |
theMode &= ~ditherCopy; |
StdBits(theSrcBits, theSrcRect, theDstRect, theMode, theMaskRgn); |
} |
////////// |
// |
// ICUtils_DrawPictureNoDither |
// Draw a QuickTime picture, but convert any use of ditherCopy graphics modes to graphics modes that don't use ditherCopy. |
// |
////////// |
static void ICUtils_DrawPictureNoDither (PicHandle thePicture, const Rect *theRect) |
{ |
CQDProcs myProcs; |
GrafPtr mySavedPort; |
CQDProcsPtr mySavedProcs; |
GetPort(&mySavedPort); |
mySavedProcs = GetPortGrafProcs(mySavedPort); |
SetStdCProcs(&myProcs); |
myProcs.bitsProc = NewQDBitsUPP(ICUtils_NoDitherBitsProc); |
SetPortGrafProcs((CGrafPtr)mySavedPort, &myProcs); |
DrawPicture(thePicture, theRect); |
SetPortGrafProcs((CGrafPtr)mySavedPort, mySavedProcs); |
DisposeQDBitsUPP(myProcs.bitsProc); |
} |
////////// |
// |
// ICUtils_PrepareFor16BitCompress |
// |
// Clean up the colors in a picture before being compressed with the Animation compressor in 16-bits at codecNormal quality. |
// |
// The QuickTime Animation compressor can operate in both a lossless and lossy manner. This routine is meant to help when |
// compressing in a lossy manner. Here, "clean up" means to force any colors that are sufficiently close to white to colors |
// that are not as close. Since the Animation compressor will perform thresholding of the image's colors when codecNormal |
// quality is specified, without this preprocessing, colors very close to white can be mapped to white in the compression. |
// If white was chosen as the key color, pixels that are close to white could possibly become transparent as well. |
// |
// While not used by other routines in this file, ICUtils_PrepareFor16BitCompress is provided as an example of how this might be done. |
// |
// Note that with codecLossless quality, there is no remapping of colors so this step is unnecessary. |
// |
////////// |
static OSErr ICUtils_PrepareFor16BitCompress (PicHandle *thePicture) |
{ |
PicHandle myPicture = NULL; |
Rect myRect; |
GWorldPtr myGWorld = NULL; |
CGrafPtr mySavedPort; |
GDHandle mySavedDevice; |
short myRowBytes; |
Ptr myBaseAddr; |
long w, h; |
PixMapHandle myPixMap; |
OSErr myErr = noErr; |
GetGWorld(&mySavedPort, &mySavedDevice); |
myRect = (***thePicture).picFrame; |
MacOffsetRect(&myRect, (short)-myRect.left, (short)-myRect.top); |
myErr = QTNewGWorld(&myGWorld, 32, &myRect, NULL, NULL, kICMTempThenAppMemory); |
if (myErr != noErr) |
goto bail; |
myPixMap = GetGWorldPixMap(myGWorld); |
LockPixels(myPixMap) |
; |
SetGWorld(myGWorld, NULL); |
EraseRect(&myRect); |
DrawPicture(*thePicture, &myRect); |
myBaseAddr = GetPixBaseAddr(myPixMap); |
myRowBytes = QTGetPixMapHandleRowBytes(myPixMap);; |
for (h =0 ; h < myRect.bottom; h++) { |
long *myPixelPtr = (long *)myBaseAddr; |
for (w = 0; w < myRect.right; w++, myPixelPtr++) { |
UInt8 r, g, b, a; |
long myPixel = *myPixelPtr; |
if ((myPixel & 0x0ffffff) == 0x00ffffff) // pure white |
continue; |
a = (myPixel >> 24) & 0x0ff; |
r = (myPixel >> 16) & 0x0ff; |
g = (myPixel >> 8) & 0x0ff; |
b = (myPixel >> 0) & 0x0ff; |
if ((r > kThreshold) && (g > kThreshold) && (b > kThreshold)) { |
r = g = b = kThreshold; |
*myPixelPtr = (a << 24) | (kThreshold << 16) | (kThreshold << 8) | (kThreshold << 0); |
} |
} |
myBaseAddr += myRowBytes; |
} |
myPicture = OpenPicture(&myRect); |
CopyBits((BitMapPtr)*GetGWorldPixMap(myGWorld), |
(BitMapPtr)*GetGWorldPixMap(myGWorld), |
&myRect, |
&myRect, |
ditherCopy, |
NULL); |
ClosePicture(); |
UnlockPixels(myPixMap); |
bail: |
if (myGWorld) |
DisposeGWorld(myGWorld); |
if (myErr == noErr) { |
if (myPicture) { |
KillPicture(*thePicture); |
*thePicture = myPicture; |
} |
} |
SetGWorld(mySavedPort, mySavedDevice); |
return(myErr); |
} |
/////////////////////////////////////////////////////////////////////////////////////////////////////////// |
// |
// Callback-based routines for compressing with hit-testing and transparency. |
// |
/////////////////////////////////////////////////////////////////////////////////////////////////////////// |
////////// |
// |
// ICUtils_RecompressWithTransparencyFromProc |
// |
// This routine recompresses some given image data with transparency, using the specified key color. |
// It uses a callback procedure (theDrawProc) to get the dimensions of the area of the drawable entity |
// and for actually drawing that entity. |
// |
// This routine is called by _RecompressCompressedImageWithTransparency, _RecompressPictureWithTransparency, |
// and _RecompressPictureFileWithTransparency; you can also call it directly. |
// |
// Here's a recap of the parameters: |
// |
// theDrawProc the callback procedure that gets area of image and draws it |
// theDrawProcRefCon a reference constant passed to theDrawProc |
// includeHitTesting TRUE if hit-testing data should be added to the compressed data |
// theKeyColor an RGBColor that is to be used as the key color; NULL if no tansparency |
// theHitTestRegion a RgnHandle specifying an area that is to be used as the hit test area; |
// if you pass this, you must also set includeHitTesting to TRUE; this is |
// optional, as the callback procedure can perform drawing of the hit test area |
// (which is often suitable when both the image and hit test area were painted |
// in a drawing program) |
// theImageDesc returned ImageDescriptionHandle for the compressed image data |
// theImageData returned Handle to the compressed image data |
// |
// |
////////// |
OSErr ICUtils_RecompressWithTransparencyFromProc ( |
CompressDrawProc theDrawProc, |
void *theDrawProcRefCon, |
Boolean includeHitTesting, |
RGBColor *theKeyColor, |
RgnHandle theHitTestRegion, |
ImageDescriptionHandle *theImageDesc, |
Handle *theImageData) |
{ |
Rect myRect; |
CGrafPtr mySavedPort; |
GDHandle mySavedDevice; |
GWorldPtr myGWImage = NULL; // always used |
GWorldPtr myGWPrev = NULL; // used if compressing with transparency (via key color) |
GWorldPtr myGWMap = NULL; // used if compressing with hittesting data |
ImageDescriptionHandle myDesc = NULL; // resulting image description |
ImageDescriptionHandle myGWMapDesc = NULL; |
ImageSequence mySeqID = 0; // compression sequence |
ImageSequenceDataSource myMapSource = 0L; |
Ptr myData = NULL; |
long myDataSize; |
UInt8 mySimilarity; |
Boolean includeTransparency = false; |
RGBColor mySaveBackColor; |
OSErr myErr = noErr; |
// get the current graphics port and device |
GetGWorld(&mySavedPort, &mySavedDevice); |
if ((theDrawProc == NULL) || (theImageDesc == NULL) || (theImageData == NULL)) { |
myErr = paramErr; |
goto bail; |
} |
////////// |
// |
// allocate and configure any storage we'll need for recompressing the image data |
// |
////////// |
// tell the callback procedure that it should initialize any storage it needs |
myErr = theDrawProc(kRecoProcInitMsg, NULL, NULL, 0, theDrawProcRefCon); |
if (myErr != noErr) |
goto bail; |
// determine the bounds to use for compression |
myErr = theDrawProc(kRecoProcGetBoundsMsg, &myRect, NULL, 0, theDrawProcRefCon); |
if (myErr != noErr) |
goto bail; |
myErr = QTNewGWorld(&myGWImage, kCompressDepth, &myRect, NULL, NULL, kICMTempThenAppMemory); |
if (myErr != noErr) |
goto bail; |
if (theKeyColor != NULL) |
includeTransparency = true; |
// if we are to include transparency, we need a previous buffer and an 8-bit GWorld for the mask data |
if (includeHitTesting) { |
myErr = QTNewGWorld(&myGWPrev, kCompressDepth, &myRect, NULL, NULL, kICMTempThenAppMemory); |
if (myErr != noErr) |
goto bail; |
myErr = QTNewGWorld(&myGWMap, 8, &myRect, NULL, NULL, kICMTempThenAppMemory); |
if (myErr != noErr) |
goto bail; |
} |
// lock our GWorld pixmaps |
LockPixels(GetGWorldPixMap(myGWImage)); |
if (myGWPrev != NULL) |
LockPixels(GetGWorldPixMap(myGWPrev)); |
if (myGWMap != NULL) |
LockPixels(GetGWorldPixMap(myGWMap)); |
////////// |
// |
// set up the GWorlds |
// |
////////// |
// erase the previous GWorld |
if (myGWPrev != NULL) { |
SetGWorld(myGWPrev, NULL); |
ClipRect(&myRect); |
GetBackColor(&mySaveBackColor); |
if (theKeyColor != NULL) |
RGBBackColor(theKeyColor); |
EraseRect(&myRect); |
RGBBackColor(&mySaveBackColor); |
} |
// draw the hit-test region in the hit-test GWorld |
if (myGWMap != NULL) { |
SetGWorld(myGWMap, NULL); |
// paint background white |
EraseRect(&myRect); |
myErr = theDrawProc(kRecoProcDrawMsg, &myRect, myGWMap, kRecoProcHitTestingImageType, theDrawProcRefCon); |
if (myErr != noErr) |
goto bail; |
// paint the hit-test region |
if (theHitTestRegion != NULL) { |
RGBColor myBlackRGB; |
myBlackRGB.red = myBlackRGB.green = myBlackRGB.blue = 0; |
RGBForeColor(&myBlackRGB); |
MacPaintRgn(theHitTestRegion); |
} |
myGWMapDesc = ICUtils_CreateImageDescription(kRawCodecType, GetGWorldPixMap(myGWMap)); |
myErr = MemError(); |
if (myErr) goto bail; |
} |
// erase the image GWorld |
SetGWorld(myGWImage, NULL); |
ClipRect(&myRect); |
EraseRect(&myRect); |
////////// |
// |
// set up the compression sequence |
// |
// we pass codecLosslessQuality so that the key color (if any) is matched exactly; this avoids colors within |
// some threshhold different from the key color being taken as equivalent to the key color; alternatively, |
// we could perform some threshold processing on the source image's pixels and pass codecNormalQuality |
// |
////////// |
myDesc = (ImageDescriptionHandle)NewHandle(sizeof(ImageDescription)); |
if (includeHitTesting) { |
// allocate a compression sequence and add source data for hit-test mask |
myErr = CompressSequenceBegin(&mySeqID, GetGWorldPixMap(myGWPrev), NULL, NULL, NULL, kCompressDepth, kAnimationCodecType, |
anyCodec, codecLosslessQuality, codecLosslessQuality, 2, NULL, 0, myDesc); |
// with hit-testing, we have to add a data source to hold the mask data |
myErr = CDSequenceNewDataSource(mySeqID, &myMapSource, kRecoProcHitTestingImageType, 1, (Handle)myGWMapDesc, NULL, NULL); |
if (myErr != noErr) |
goto bail; |
myErr = CDSequenceSetSourceData(myMapSource, GetPixBaseAddr(GetGWorldPixMap(myGWMap)), (**myGWMapDesc).dataSize); |
if (myErr != noErr) |
goto bail; |
// what's the maximum size the compressed data could be (including hit-test data)? |
myErr = GetCSequenceMaxCompressionSize(mySeqID, GetGWorldPixMap(myGWPrev), &myDataSize); |
} else { |
// we're not hit-testing, so we only need the image buffer |
myErr = CompressSequenceBegin(&mySeqID, GetGWorldPixMap(myGWImage), NULL, &myRect, NULL, kCompressDepth, kAnimationCodecType, |
0, codecLosslessQuality, codecLosslessQuality, 2, NULL, 0, myDesc); |
if (myErr != noErr) |
goto bail; |
// What's the maximum size the compressed data could be? |
myErr = GetCSequenceMaxCompressionSize(mySeqID, GetGWorldPixMap(myGWImage), &myDataSize); |
} |
if (myErr != noErr) |
goto bail; |
////////// |
// |
// compress the image data |
// |
////////// |
myData = NewPtr(myDataSize); |
myErr = MemError(); |
if (myErr != noErr) |
goto bail; |
if (includeHitTesting) { /* with or without transparency */ |
// with hit-testing, we use two buffers; actually we don't have to but do so to show how it can be done |
// (this code was based upon some older code that did) |
// compress the GWorld painted with the theKeyColor exclusively |
myErr = CompressSequenceFrame(mySeqID, GetGWorldPixMap(myGWPrev), NULL, 0, myData, &myDataSize, &mySimilarity, NULL); |
if (myErr != noErr) |
goto bail; |
myErr = SetCSequencePrev(mySeqID, GetGWorldPixMap(myGWPrev), NULL); |
if (myErr != noErr) |
goto bail; |
// draw the image into the GWorld over the area painted with theKeyColor, so that if the picture is already transparent, |
// the areas it doesn't paint will be in the key color |
SetGWorld(myGWImage, NULL); |
GetBackColor(&mySaveBackColor); |
if (theKeyColor != NULL) |
RGBBackColor(theKeyColor); |
EraseRect(&myRect); |
RGBBackColor(&mySaveBackColor); |
myErr = theDrawProc(kRecoProcDrawMsg, &myRect, myGWImage, kRecoProcOriginalImageType, theDrawProcRefCon); |
if (myErr != noErr) |
goto bail; |
// now compress the GWorld holding the image drawn on top of the theKeyColor |
myErr = CompressSequenceFrame(mySeqID, GetGWorldPixMap(myGWImage), NULL, 0, myData, &myDataSize, &mySimilarity, NULL); |
if (myErr != noErr) |
goto bail; |
// at this point, myData points to the image data for just the difference between the two (thus generating transparency); |
// also, hit-testing data is contained in the image data if so specified |
} else if (includeTransparency) { |
// for transparency without hit-testing, we get by with only using a single buffer |
// compress the GWorld painted with the theKeyColor exclusively |
myErr = CompressSequenceFrame(mySeqID, GetGWorldPixMap(myGWImage), NULL, codecFlagUpdatePrevious, myData, &myDataSize, &mySimilarity, NULL); |
if (myErr != noErr) |
goto bail; |
// draw the image into the GWorld over the area painted with theKeyColor, so that if the picture is already transparent, |
// the areas it doesn't paint will be in the key color |
SetGWorld(myGWImage, NULL); |
GetBackColor(&mySaveBackColor); |
if (theKeyColor != NULL) |
RGBBackColor(theKeyColor); |
EraseRect(&myRect); |
RGBBackColor(&mySaveBackColor); |
myErr = theDrawProc(kRecoProcDrawMsg, &myRect, myGWImage, kRecoProcOriginalImageType, theDrawProcRefCon); |
if (myErr != noErr) |
goto bail; |
// now compress the GWorld holding the image drawn on top of the theKeyColor |
myErr = CompressSequenceFrame(mySeqID, GetGWorldPixMap(myGWImage), NULL, codecFlagUpdatePrevious, myData, &myDataSize, &mySimilarity, NULL); |
if (myErr != noErr) |
goto bail; |
// at this point, myData points to the image data for just the difference between the two (thus generating transparency) |
// also, hit-testing data is contained in the image data if so specified |
} else { |
// no hit-testing and no transparency.... |
SetGWorld(myGWImage, NULL); |
// draw the image into the GWorld |
myErr = theDrawProc(kRecoProcDrawMsg, &myRect, myGWImage, kRecoProcOriginalImageType, theDrawProcRefCon); |
if (myErr != noErr) |
goto bail; |
// compress the GWorld containing the image painted on white |
myErr = CompressSequenceFrame(mySeqID, GetGWorldPixMap(myGWImage), NULL, 0, myData, &myDataSize, &mySimilarity, NULL); |
if (myErr != noErr) |
goto bail; |
// at this point, myData points to the image data for just the image, newly compressed; also, hit - data is contained |
// in the image data if it was specified |
} |
////////// |
// |
// end the compression sequence and clean up |
// |
////////// |
CDSequenceEnd(mySeqID); |
mySeqID = 0; |
// free the GWorlds and drop references so we have more memory for PtrToHand |
if (myGWImage != NULL) |
DisposeGWorld(myGWImage); |
myGWImage = NULL; |
if (myGWMap != NULL) |
DisposeGWorld(myGWMap); |
myGWMap = NULL; |
if (myGWPrev != NULL) |
DisposeGWorld(myGWPrev); |
myGWPrev = NULL; |
// return the image data and the image description to the caller |
myErr = PtrToHand(myData, theImageData, myDataSize); |
if (myErr) goto bail; |
*theImageDesc = myDesc; |
myDesc = NULL; // forget about this name for ImageDescriptionHandle so dispose below doesn't catch it |
bail: |
// tell callback to dispose of anything it allocated; we pass 'err ' in theImageType if an error occurred |
theDrawProc(kRecoProcDisposeMsg, NULL, NULL, myErr ? FOUR_CHAR_CODE('err ') : 0, theDrawProcRefCon); |
if (mySeqID != 0) |
CDSequenceEnd(mySeqID); |
// restore the original graphics port and device |
SetGWorld(mySavedPort, mySavedDevice); |
if (myGWImage != NULL) |
DisposeGWorld(myGWImage); |
if (myGWMap != NULL) |
DisposeGWorld(myGWMap); |
if (myGWPrev != NULL) |
DisposeGWorld(myGWPrev); |
if (myDesc != NULL) |
DisposeHandle((Handle) myDesc); |
if (myGWMapDesc != NULL) |
DisposeHandle((Handle) myGWMapDesc); |
if (myData != NULL) |
DisposePtr(myData); |
return(myErr); |
} |
////////// |
// |
// ICUtils_PictureCompressDrawProc |
// |
// Helper routine to be used with ICUtils_RecompressWithTransparencyFromProc to compress QuickDraw pictures. |
// |
////////// |
static PASCAL_RTN OSErr ICUtils_PictureCompressDrawProc (short theMessage, Rect *theRect, GWorldPtr theDrawingPort, OSType theImageType, void *theRefCon) |
{ |
#if TARGET_OS_MAC |
#pragma unused(theDrawingPort) |
#endif |
ICUtils_PictureCompressProcData *myData = theRefCon; |
Rect myRect; |
OSErr myErr = noErr; |
switch (theMessage) { |
case kRecoProcInitMsg: |
break; |
case kRecoProcDisposeMsg: |
break; |
case kRecoProcGetBoundsMsg: |
myRect = (**myData->picture).picFrame; |
myRect.left = EndianS16_BtoN(myRect.left); |
myRect.top = EndianS16_BtoN(myRect.top); |
myRect.bottom = EndianS16_BtoN(myRect.bottom); |
myRect.right = EndianS16_BtoN(myRect.right); |
MacOffsetRect(&myRect, (short)-myRect.left, (short)-myRect.top); |
*theRect = myRect; |
break; |
case kRecoProcDrawMsg: |
myRect = (**myData->picture).picFrame; |
myRect.left = EndianS16_BtoN(myRect.left); |
myRect.top = EndianS16_BtoN(myRect.top); |
myRect.bottom = EndianS16_BtoN(myRect.bottom); |
myRect.right = EndianS16_BtoN(myRect.right); |
MacOffsetRect(&myRect, (short)-myRect.left, (short)-myRect.top); |
if (theImageType == kRecoProcOriginalImageType) |
ICUtils_DrawPictureNoDither(myData->picture, &myRect); |
break; |
default: |
myErr = -1; |
} |
return(myErr); |
} |
////////// |
// |
// ICUtils_ImageCompressDrawProc |
// |
// Helper routine to be used with ICUtils_RecompressWithTransparencyFromProc to compress QuickTime compressed image data. |
// |
////////// |
static PASCAL_RTN OSErr ICUtils_ImageCompressDrawProc (short theMessage, Rect *theRect, GWorldPtr theDrawingPort, OSType theImageType, void *theRefCon) |
{ |
#if TARGET_OS_MAC |
#pragma unused(theImageType) |
#endif |
ICUtils_CompressedImageCompressProcData *myData = theRefCon; |
Rect myRect; |
OSErr myErr = noErr; |
switch(theMessage) { |
case kRecoProcInitMsg: |
break; |
case kRecoProcDisposeMsg: |
break; |
case kRecoProcGetBoundsMsg: |
myRect.left = myRect.top = 0; |
myRect.right = (**myData->imageDesc).width; |
myRect.bottom = (**myData->imageDesc).height; |
*theRect = myRect; |
break; |
case kRecoProcDrawMsg: |
{ |
SignedByte mySavedState; |
myRect.left = myRect.top = 0; |
myRect.right = (**myData->imageDesc).width; |
myRect.bottom = (**myData->imageDesc).height; |
mySavedState = HGetState(myData->imageData); |
HLockHi(myData->imageData); |
if (theImageType == kRecoProcOriginalImageType) |
myErr = DecompressImage(*myData->imageData, myData->imageDesc, GetGWorldPixMap(theDrawingPort), &myRect, &myRect, srcCopy, NULL); |
HSetState(myData->imageData, mySavedState); |
} |
break; |
default: |
myErr = -1; |
} |
return(myErr); |
} |
////////// |
// |
// ICUtils_RecompressCompressedImageWithTransparency |
// |
// Given an ImageDescriptionHandle and a handle to some image data, generate new RLE compressed data with |
// optional hit-testing and transparency. |
// |
////////// |
OSErr ICUtils_RecompressCompressedImageWithTransparency ( |
ImageDescriptionHandle theOrigDesc, |
Handle theOrigImageData, |
RGBColor *theKeyColor, |
RgnHandle theHitTestRegion, |
ImageDescriptionHandle *theImageDesc, |
Handle *theImageData) |
{ |
ICUtils_CompressedImageCompressProcData myParams; |
OSErr myErr = noErr; |
myParams.imageDesc = theOrigDesc; |
myParams.imageData = theOrigImageData; |
myErr = ICUtils_RecompressWithTransparencyFromProc( |
ICUtils_ImageCompressDrawProc, |
&myParams, |
(Boolean)(theHitTestRegion != NULL), |
theKeyColor, |
theHitTestRegion, |
theImageDesc, |
theImageData); |
return(myErr); |
} |
////////// |
// |
// ICUtils_RecompressPictureWithTransparency |
// |
// Given a QuickDraw PicHandle, generate new RLE compressed data with optional hit-testing and transparency. |
// |
////////// |
OSErr ICUtils_RecompressPictureWithTransparency ( |
PicHandle theOrigPicture, |
RGBColor *theKeyColor, |
RgnHandle theHitTestRegion, |
ImageDescriptionHandle *theImageDesc, |
Handle *theImageData) |
{ |
ICUtils_PictureCompressProcData myParams; |
OSErr myErr = noErr; |
myParams.picture = theOrigPicture; |
myErr = ICUtils_RecompressWithTransparencyFromProc( |
ICUtils_PictureCompressDrawProc, |
&myParams, |
(Boolean)(theHitTestRegion != NULL), |
theKeyColor, |
theHitTestRegion, |
theImageDesc, |
theImageData); |
return(myErr); |
} |
////////// |
// |
// ICUtils_RecompressPictureFileWithTransparency |
// |
// Given a QuickDraw PICT file, generate new RLE compressed data with optional hit -testing and transparency. |
// This function uses ICUtils_RecompressPictureWithTransparency to do the actual work on the PicHandle retrieved from |
// the PICT file. |
// |
////////// |
OSErr ICUtils_RecompressPictureFileWithTransparency ( |
FSSpec *theFSSpec, |
RGBColor *theKeyColor, |
RgnHandle theHitTestRegion, |
ImageDescriptionHandle *theImageDesc, |
Handle *theImageData) |
{ |
short myRefNum = 0; |
PicHandle myPicture = NULL; |
long myEOF; |
long myCount; |
OSErr myErr = noErr; |
*theImageDesc = NULL; |
*theImageData = NULL; |
myErr = FSpOpenDF(theFSSpec, fsRdPerm, &myRefNum); |
if (myErr != noErr) |
goto bail; |
myErr = GetEOF(myRefNum, &myEOF); |
if (myErr != noErr) |
goto bail; |
myEOF -= 512; |
myErr = SetFPos(myRefNum, fsFromStart, 512); |
if (myErr != noErr) |
goto bail; |
myPicture = (PicHandle)NewHandle(myEOF); |
myErr = MemError(); |
if (myErr != noErr) |
goto bail; |
myCount = myEOF; |
HLock((Handle)myPicture); |
myErr = FSRead(myRefNum, &myCount, *myPicture); |
if (myErr != noErr) |
goto bail; |
HUnlock((Handle)myPicture); |
myErr = ICUtils_RecompressPictureWithTransparency(myPicture, theKeyColor, theHitTestRegion, theImageDesc, theImageData); |
bail: |
if (myPicture != NULL) |
DisposeHandle((Handle)myPicture); |
if (myRefNum != 0) |
FSClose(myRefNum); |
return(myErr); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-02-25