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: Image Compression Utilities. |
// |
// Written by: Peter Hoddie, Sean Allen, Chris Flick |
// Revised by: Tim Monroe |
// |
// Copyright: © 1998 by Apple Computer, Inc., all rights reserved. |
// |
// Change History (most recent first): |
// |
// <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> 03/22/98 rtm made changes to RecompressPictureFileWithTransparency, as per Chris' fixes |
// <1> 03/27/98 rtm existing file |
// |
////////// |
////////// |
// |
// header files |
// |
////////// |
#ifndef __IMAGECOMPRESSIONUTILITIES__ |
#include "ImageCompressionUtilities.h" |
#endif |
////////// |
// |
// prototypes |
// |
////////// |
static ImageDescriptionHandle createImageDescription ( CodecType cType, PixMapHandle pixmap ); |
static void DrawPictureNoDither (PicHandle pic, const Rect *bounds); |
//static OSErr prepareFor16BitCompress (PicHandle *pic); |
static PASCAL_RTN OSErr myPictureCompressDrawProc ( |
short message, |
Rect * bounds, |
GWorldPtr drawingPort, |
OSType portType, |
void * refcon ); |
static PASCAL_RTN OSErr myImageCompressDrawProc ( |
short message, |
Rect * bounds, |
GWorldPtr drawingPort, |
OSType portType, |
void * refcon ); |
// PICT to compressed image conversion |
// Given a QuickDraw picture, extract QuickTime compressed image data and description, if any. |
// |
// It does this by creating a temporary CGrafPort, installing a QuickDraw bottleneck |
// routine for the StdPix call, and then drawing the picture. Since this routine will |
// be called whenever QuickTime compressed image data is encountered, it can |
// stash away any found compressed data and description. On DrawPicture's return, the |
// stashed data and description is retrieved and returned to the caller. |
// |
// Worth noting in this utility is definition of the extractPictRecord. This is a |
// structure consisting of a CGrafPort structure followed by fields for a handle to |
// image data and an ImageDescription. This layout allows ExtractCompressData to open |
// a CGrafPort using the embedded CGrafPort field, and set this as the current port. |
// Then, in the StdPix routine extractStdPix, the current port can be retrieved and |
// cast to a pointer to an extractPictRecord to get access to the other fields. |
// |
#if 0 |
OSErr ExtractCompressData ( PicHandle thePict, Handle *dataOut, ImageDescriptionHandle *idh ) |
{ |
OSErr err = noErr; |
extractPictRecord state; |
CQDProcs procs; |
GrafPtr savePort; |
Rect bounds; |
if ( dataOut ) |
*dataOut = nil; |
if ( idh ) |
*idh = nil; |
GetPort( &savePort ); |
OpenCPort( &state.tempPort ); |
SetStdCProcs( &procs ); |
procs.newProc1 = (UniversalProcPtr)NewStdPixProc(extractStdPix); |
state.tempPort.grafProcs = &procs; |
state.data = nil; |
state.idh = nil; |
MacSetPort( (GrafPtr)&state.tempPort ); |
HidePen(); |
bounds = (**thePict).picFrame; |
DrawPicture(thePict, &bounds); |
MacSetPort( savePort ); |
CloseCPort( &state.tempPort ); |
DisposeRoutineDescriptor( procs.newProc1 ); |
*dataOut = state.data; |
*idh = state.idh; |
return err; |
} |
#endif |
PASCAL_RTN void extractStdPix ( PixMap *src, Rect *srcRect, MatrixRecord *matrix, short mode, RgnHandle mask, PixMap *matte, Rect *matteRect, short flags ) |
{ |
#if TARGET_OS_MAC |
#pragma unused(srcRect,matrix,mode,mask,matte,matteRect,flags) |
#endif |
extractPictRecord *state; |
GetPort( (GrafPtr *)&state ); |
if ( state->idh == nil ) { |
ImageDescriptionHandle desc; |
Ptr data; |
long bufferSize; |
if ( GetCompressedPixMapInfo(src, &desc, &data, &bufferSize, nil, nil) == noErr ) { |
state->idh = desc; |
HandToHand( (Handle *)&state->idh ); |
PtrToHand( data, &state->data, bufferSize ); |
} |
} |
} |
static ImageDescriptionHandle createImageDescription ( CodecType cType, PixMapHandle pixmap ) |
{ |
ImageDescriptionHandle desc = nil; |
if ( ( desc = (ImageDescription **)NewHandleClear(sizeof(ImageDescription)) ) != nil ) { |
ImageDescription *dp = *desc; |
Rect bounds = (**pixmap).bounds; |
dp->idSize = sizeof(ImageDescription); |
dp->cType = cType; |
dp->spatialQuality = codecNormalQuality; |
dp->width = bounds.right - bounds.left; |
dp->height = bounds.bottom - bounds.top; |
dp->hRes = 72L << 16; |
dp->vRes = 72L << 16; |
dp->dataSize = ((**pixmap).rowBytes & 0x3fff) * dp->height; |
dp->depth = (**pixmap).pixelSize; |
dp->clutID = -1; |
if ( SetImageDescriptionCTable( desc, (**pixmap).pmTable ) ) { |
DisposeHandle( (Handle) desc ); |
desc = nil; |
} |
} |
return desc; |
} |
PASCAL_RTN void noDitherBitsProc (BitMap *srcBits, Rect *srcRect, Rect *dstRect, short mode, RgnHandle maskRgn) |
{ |
mode &= ~ditherCopy; |
StdBits(srcBits, srcRect, dstRect, mode, maskRgn); |
} |
// DrawPictureNoDither is used to draw a QuickDraw picture but to turn convert any |
// use of ditherCopy graphics modes to graphics modes that don't use ditherCopy. It |
// only performs this with the stdbits bottleneck routine. Since ditherCopy is simply |
// ORed in with other graphics modes, the replaced bottleneck routine only needs to |
// AND off the ditherCopy flag. |
void DrawPictureNoDither(PicHandle pic, const Rect *bounds) |
{ |
CQDProcs procs; |
GrafPtr savePort; |
CQDProcsPtr saveProcs; |
GetPort(&savePort); |
saveProcs = GetPortGrafProcs(savePort); |
SetStdCProcs( &procs ); |
procs.bitsProc = NewQDBitsUPP((QDBitsProcPtr)noDitherBitsProc); |
SetPortGrafProcs((CGrafPtr)savePort, &procs); |
DrawPicture(pic, bounds); |
SetPortGrafProcs((CGrafPtr)savePort, saveProcs); |
DisposeQDBitsUPP( procs.bitsProc ); |
} |
// |
// The following is a routine that can be used to 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. |
// |
// By clean up, what's meant is the forcing of any colors that are sufficiently close |
// to white to colors that are not as close. Since the Animation compressor will |
// perform threshholding 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, 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. |
// |
#if 0 |
OSErr prepareFor16BitCompress(PicHandle *pic) |
{ |
PicHandle newPicture = nil; |
Rect r; |
GWorldPtr gw = nil; |
CGrafPtr savePort; |
GDHandle saveGD; |
short rowBytes; |
Ptr baseAddr; |
long w, h; |
PixMapHandle pm; |
OSErr err = noErr; |
GetGWorld(&savePort, &saveGD); |
r = (***pic).picFrame; |
MacOffsetRect(&r, (short)-r.left, (short)-r.top); |
err = NewGWorld(&gw, 32, &r, nil, nil, useTempMem); |
if (err) { |
err = NewGWorld(&gw, 32, &r, nil, nil, 0); |
if (err) goto bail; |
} |
pm = GetGWorldPixMap(gw); |
LockPixels(pm); |
SetGWorld(gw, nil); |
EraseRect(&r); |
DrawPicture(*pic, &r); |
baseAddr = GetPixBaseAddr(pm); |
rowBytes = (**pm).rowBytes & 0x3fff; |
for (h=0; h<r.bottom; h++) { |
long *pixelPtr = (long *)baseAddr; |
for (w=0; w<r.right; w++, pixelPtr++) { |
UInt8 r, g, b, a; |
long pixel = *pixelPtr; |
if ((pixel & 0x0ffffff) == 0x00ffffff) // pure white |
continue; |
a = (pixel >> 24) & 0x0ff; |
r = (pixel >> 16) & 0x0ff; |
g = (pixel >> 8) & 0x0ff; |
b = (pixel >> 0) & 0x0ff; |
if ((r > kThreshold) && (g > kThreshold) && (b > kThreshold)) { |
r = g = b = kThreshold; |
*pixelPtr = (a << 24) | (kThreshold << 16) | (kThreshold << 8) | (kThreshold << 0); |
} |
} |
baseAddr += rowBytes; |
} |
newPicture = OpenPicture(&r); |
CopyBits((BitMapPtr)*GetGWorldPixMap(gw), |
(BitMapPtr)*GetGWorldPixMap(gw), |
&r, |
&r, |
ditherCopy, |
NULL); |
ClosePicture(); |
UnlockPixels(pm); |
bail: |
if (gw) |
DisposeGWorld(gw); |
if (err == noErr) { |
if (newPicture) { |
KillPicture(*pic); |
*pic = newPicture; |
} |
} |
SetGWorld(savePort, saveGD); |
return err; |
} |
#endif |
/* |
---------------- Callback based routines for compressing with hittesting and transparency ---------------- |
*/ |
/* |
RecompressWithTransparencyFromProc |
This is a routine either called indirectly through RecompressCompressedImageWithTransparency, |
RecompressPictureWithTransparency, or RecompressPictureFileWithTransparency or called directly. |
It takes a callback procedure which is responsible for returning the dimensions of the |
area of some type of drawable entity and for actually drawing that entity. |
includeHitTesting TRUE if hit testing data should be added to the compressed data |
keyColor A RGBColor that should be used as the transparency color. Pass nil |
if the image doesn't have transparent portions. |
hitTestRegion 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 |
itself of the hit test area which is often suitable when both the |
image and hit test area were painted in a drawing program. |
idh Returned ImageDescriptionHandle for the compressed image data |
imageData Returned Handle to the compressed image data |
*/ |
OSErr RecompressWithTransparencyFromProc( CompressDrawProc drawProc, void * drawProcRefcon, |
Boolean includeHitTesting, |
RGBColor *keyColor, |
RgnHandle hitTestRegion, |
ImageDescriptionHandle *idh, Handle * imageData ) |
{ |
OSErr err = noErr; |
Rect bounds; |
CGrafPtr savePort; |
GDHandle saveDevice; |
GWorldPtr gwImage = nil; // always used |
GWorldPtr gwPrev = nil; // used if compressing with transparency (via keycolor) |
GWorldPtr gwMap = nil; // used if compressing with hittesting data |
ImageDescriptionHandle desc = nil; // resulting image description |
ImageDescriptionHandle gwMapDesc = nil; |
ImageSequence seq = 0; // compress sequence |
ImageSequenceDataSource mapSource = 0L; |
Ptr data = nil; |
long dataSize; |
UInt8 similarity; |
Boolean includeTransparency = false; |
RGBColor saveBackColor; |
GetGWorld( &savePort, &saveDevice ); |
if( !drawProc || !idh || !imageData ){ |
err = paramErr; |
goto bail; |
} |
// tell callback that it should initialize any storage it needs |
err = drawProc( kRecoProcInitMsg, nil, nil, 0, drawProcRefcon ); |
if(err) goto bail; |
// determine bounds to use for compression |
err = drawProc( kRecoProcGetBoundsMsg, &bounds, nil, 0, drawProcRefcon ); |
if(err) goto bail; |
err = QTNewGWorld(&gwImage, kCompressDepth, &bounds, nil, nil, kICMTempThenAppMemory); |
if(err) goto bail; |
if( keyColor ) { |
includeTransparency = true; |
} |
// Include hit testing? If so, we need a previous buffer and an 8-bit GWorld for the mask data |
if( includeHitTesting ) { |
err = QTNewGWorld(&gwPrev, kCompressDepth, &bounds, nil, nil, kICMTempThenAppMemory); |
if(err) goto bail; |
err = QTNewGWorld(&gwMap, 8, &bounds, nil, nil, kICMTempThenAppMemory); |
if(err) goto bail; |
} |
LockPixels( GetGWorldPixMap(gwImage) ); |
if( gwPrev ) |
LockPixels( GetGWorldPixMap(gwPrev) ); |
if( gwMap ) |
LockPixels( GetGWorldPixMap(gwMap) ); |
if(gwPrev) { |
SetGWorld( gwPrev, nil ); |
ClipRect( &bounds ); |
GetBackColor( &saveBackColor ); |
if( keyColor ) |
RGBBackColor( keyColor ); |
EraseRect( &bounds ); |
RGBBackColor( &saveBackColor ); |
} |
if( gwMap ) { |
SetGWorld( gwMap, nil ); |
EraseRect( &bounds ); // paint background white |
err = drawProc( kRecoProcDrawMsg, &bounds, gwMap, kRecoProcHitTestingImageType, drawProcRefcon ); |
if(err) goto bail; |
if( hitTestRegion ) { |
RGBColor blackRGB; |
blackRGB.red = blackRGB.green = blackRGB.blue = 0; |
RGBForeColor( &blackRGB ); |
MacPaintRgn( hitTestRegion ); |
} |
gwMapDesc = createImageDescription(kRawCodecType, GetGWorldPixMap(gwMap)); |
err = MemError(); |
if(err) goto bail; |
} |
SetGWorld( gwImage, nil ); |
ClipRect( &bounds ); |
EraseRect( &bounds ); |
desc = (ImageDescriptionHandle) NewHandle(sizeof(ImageDescription)); |
// NOTE: 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 threshhold processing on the source image's pixels and pass codecNormalQuality. |
if( includeHitTesting ) { |
// Allocate a compression sequence and add source data for hittest mask |
err = CompressSequenceBegin(&seq, GetGWorldPixMap(gwPrev), nil, nil, nil, kCompressDepth, kAnimationCodecType, |
anyCodec, codecLosslessQuality, codecLosslessQuality, 2, nil, 0, desc); |
// with hit testing, we have to add a data source to hold the mask data |
err = CDSequenceNewDataSource(seq, &mapSource, kRecoProcHitTestingImageType, 1, (Handle)gwMapDesc, nil, nil); |
if (err) goto bail; |
err = CDSequenceSetSourceData(mapSource, GetPixBaseAddr(GetGWorldPixMap(gwMap)), (**gwMapDesc).dataSize); |
if (err) goto bail; |
// What's the maximum size the compressed data could be--including hit-test data? |
err = GetCSequenceMaxCompressionSize(seq, GetGWorldPixMap(gwPrev), &dataSize); |
} |
else |
{ // not hit-testing so we only need the image buffer |
err = CompressSequenceBegin( &seq, GetGWorldPixMap(gwImage), nil, &bounds, nil, kCompressDepth, kAnimationCodecType, 0, |
codecLosslessQuality, codecLosslessQuality, 2, nil, 0, desc ); |
if(err) goto bail; |
// What's the maximum size the compressed data could be? |
err = GetCSequenceMaxCompressionSize(seq, GetGWorldPixMap(gwImage), &dataSize); |
} |
if (err) goto bail; |
data = NewPtr( dataSize ); |
if( (err = MemError()) != noErr) goto bail; |
if( includeHitTesting /* with or without transparency */ ) { |
// With hittesting, we use two buffers. Actually we don't have to but do so to show how it can be |
// done. Also, this code was based upon some older code that did. |
// compress the GWorld painted with the keyColor exclusively |
err = CompressSequenceFrame( seq, GetGWorldPixMap(gwPrev), nil, 0, data, &dataSize, &similarity, nil ); |
if ( err ) goto bail; |
err = SetCSequencePrev(seq, GetGWorldPixMap(gwPrev), nil); |
if (err) goto bail; |
// draw the image into the GWorld over area painted with keyColor so that if picture is transparent already |
// areas it doesn't paint will be in the key color |
SetGWorld( gwImage, nil ); |
GetBackColor( &saveBackColor ); |
if( keyColor ) |
RGBBackColor( keyColor ); |
EraseRect( &bounds ); |
RGBBackColor( &saveBackColor ); |
err = drawProc( kRecoProcDrawMsg, &bounds, gwImage, kRecoProcOriginalImageType, drawProcRefcon ); |
if(err) goto bail; |
// now compress the GWorld holding the image drawn on top of the keyColor |
err = CompressSequenceFrame(seq, GetGWorldPixMap(gwImage), nil, 0, data, &dataSize, &similarity, nil); |
if (err) goto bail; |
// At this point, data 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 it was specified. |
} |
else if( includeTransparency ) { |
// For transparency case without hittesting, we get by with only using a single buffer so we special case the |
// code here. This is also for clarity. |
// compress the GWorld painted with the keyColor exclusively |
err = CompressSequenceFrame( seq, GetGWorldPixMap(gwImage), nil, codecFlagUpdatePrevious, data, &dataSize, &similarity, nil ); |
if ( err ) goto bail; |
// draw the image into the GWorld over area painted with keyColor so that if picture is transparent already |
// areas it doesn't paint will be in the key color |
SetGWorld( gwImage, nil ); |
GetBackColor( &saveBackColor ); |
if( keyColor ) |
RGBBackColor( keyColor ); |
EraseRect( &bounds ); |
RGBBackColor( &saveBackColor ); |
err = drawProc( kRecoProcDrawMsg, &bounds, gwImage, kRecoProcOriginalImageType, drawProcRefcon ); |
if(err) goto bail; |
// now compress the GWorld holding the image drawn on top of the keyColor |
err = CompressSequenceFrame(seq, GetGWorldPixMap(gwImage), nil, codecFlagUpdatePrevious, data, &dataSize, &similarity, nil); |
if (err) goto bail; |
// At this point, data 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 it was specified. |
} |
else |
{ |
SetGWorld( gwImage, nil ); |
// draw the image into the GWorld |
err = drawProc( kRecoProcDrawMsg, &bounds, gwImage, kRecoProcOriginalImageType, drawProcRefcon ); |
if(err) goto bail; |
// compress the GWorld containing the image painted on white |
err = CompressSequenceFrame( seq, GetGWorldPixMap(gwImage), nil, 0, data, &dataSize, &similarity, nil ); |
if ( err ) goto bail; |
// At this point, data points to the image data for just the image, newly compressed. Also, hit testing data is contained |
// in the image data if it was specified. |
} |
CDSequenceEnd( seq ); |
seq = 0; |
// free the GWorlds and drop references so we have more memory for PtrToHand |
if( gwImage ) DisposeGWorld( gwImage ); |
gwImage = nil; |
if( gwMap ) DisposeGWorld( gwMap ); |
gwMap = nil; |
if( gwPrev ) DisposeGWorld( gwPrev ); |
gwPrev = nil; |
err = PtrToHand( data, imageData, dataSize ); |
if ( err ) goto bail; |
*idh = desc; |
desc = nil; // 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 portType if an error occurred |
drawProc( kRecoProcDisposeMsg, nil, nil, err ? FOUR_CHAR_CODE('err ') : 0, drawProcRefcon ); |
CDSequenceEnd( seq ); |
SetGWorld( savePort, saveDevice ); |
if(gwImage) DisposeGWorld( gwImage ); |
if(gwMap ) DisposeGWorld( gwMap ); |
if(gwPrev ) DisposeGWorld( gwPrev ); |
if(desc) DisposeHandle((Handle) desc ); |
if(gwMapDesc) DisposeHandle((Handle) gwMapDesc ); |
if(data) DisposePtr( data ); |
return err; |
} |
/* |
myPictureCompressDrawProc |
Helper routine to be used with RecompressWithTransparencyFromProc to compress QuickDraw Pictures. |
*/ |
static PASCAL_RTN OSErr myPictureCompressDrawProc( short message, Rect * bounds, GWorldPtr drawingPort, OSType drawingImageType, void * refcon ) |
{ |
#if TARGET_OS_MAC |
#pragma unused(drawingPort) |
#endif |
OSErr err = noErr; |
PictureCompressProcData * data = refcon; |
Rect r; |
switch( message ) { |
case kRecoProcInitMsg: |
break; |
case kRecoProcDisposeMsg: |
break; |
case kRecoProcGetBoundsMsg: |
r = (**data->picture).picFrame; |
r.left = EndianS16_BtoN(r.left); |
r.top = EndianS16_BtoN(r.top); |
r.bottom = EndianS16_BtoN(r.bottom); |
r.right = EndianS16_BtoN(r.right); |
MacOffsetRect(&r, (short)-r.left, (short)-r.top ); |
*bounds = r; |
break; |
case kRecoProcDrawMsg: |
r = (**data->picture).picFrame; |
r.left = EndianS16_BtoN(r.left); |
r.top = EndianS16_BtoN(r.top); |
r.bottom = EndianS16_BtoN(r.bottom); |
r.right = EndianS16_BtoN(r.right); |
MacOffsetRect( &r, (short)-r.left, (short)-r.top ); |
if( kRecoProcOriginalImageType == drawingImageType ) |
DrawPictureNoDither( data->picture, &r ); |
break; |
default: |
err = -1; |
} |
return err; |
} |
/* |
myImageCompressDrawProc |
Helper routine to be used with RecompressWithTransparencyFromProc to compress QuickTime compressed image data. |
*/ |
static PASCAL_RTN OSErr myImageCompressDrawProc( short message, Rect * bounds, GWorldPtr drawingPort, OSType drawingImageType, void * refcon ) |
{ |
#if TARGET_OS_MAC |
#pragma unused(drawingImageType) |
#endif |
OSErr err = noErr; |
CompressedImageCompressProcData * data = refcon; |
Rect r; |
switch( message ) { |
case kRecoProcInitMsg: |
break; |
case kRecoProcDisposeMsg: |
break; |
case kRecoProcGetBoundsMsg: |
r.left = r.top = 0; |
r.right = (**data->imageDesc).width; |
r.bottom = (**data->imageDesc).height; |
*bounds = r; |
break; |
case kRecoProcDrawMsg: |
{ |
SignedByte saveState; |
r.left = r.top = 0; |
r.right = (**data->imageDesc).width; |
r.bottom = (**data->imageDesc).height; |
saveState = HGetState( data->imageData ); |
HLockHi( data->imageData ); |
if( kRecoProcOriginalImageType == drawingImageType ) |
err = DecompressImage( *data->imageData, data->imageDesc, GetGWorldPixMap(drawingPort), &r, &r, srcCopy, nil ); |
HSetState( data->imageData, saveState ); |
} |
break; |
default: |
err = -1; |
} |
return err; |
} |
/* |
RecompressCompressedImageWithTransparency |
Given an ImageDescriptionHandle and a handle to image data, generate new RLE compressed data |
with optional hitTesting and transparency. |
*/ |
OSErr RecompressCompressedImageWithTransparency( ImageDescriptionHandle originalDesc, Handle originalImageData, |
RGBColor *keyColor, |
RgnHandle hitTestRegion, |
ImageDescriptionHandle *idh, Handle * imageData ) |
{ |
OSErr err = noErr; |
CompressedImageCompressProcData params; |
params.imageDesc = originalDesc; |
params.imageData = originalImageData; |
err = RecompressWithTransparencyFromProc( myImageCompressDrawProc, ¶ms, |
(Boolean)(hitTestRegion != nil), |
keyColor, |
hitTestRegion, |
idh, imageData ); |
return err; |
} |
/* |
RecompressPictureWithTransparency |
Given a QuickDraw PicHandle, generate new RLE compressed data with optional hitTesting and transparency. |
*/ |
OSErr RecompressPictureWithTransparency( PicHandle originalPicture, |
RGBColor *keyColor, |
RgnHandle hitTestRegion, |
ImageDescriptionHandle *idh, Handle * imageData ) |
{ |
OSErr err = noErr; |
PictureCompressProcData params; |
params.picture = originalPicture; |
err = RecompressWithTransparencyFromProc( myPictureCompressDrawProc, ¶ms, |
(Boolean)(hitTestRegion != nil), |
keyColor, |
hitTestRegion, |
idh, imageData ); |
return err; |
} |
/* |
RecompressPictureFileWithTransparency |
Given a QuickDraw PICT file, generate new RLE compressed data with optional hitTesting and transparency. |
This function uses GetCompressedImageFromPicture to do the actual work on the PicHandle retrieved from |
the PICT file. |
*/ |
OSErr RecompressPictureFileWithTransparency( FSSpec * spec, |
RGBColor *keyColor, |
RgnHandle hitTestRegion, |
ImageDescriptionHandle *idh, Handle * imageData ) |
{ |
OSErr err = noErr; |
short sourceRefNum = 0; |
PicHandle picture = nil; |
long eof; |
long countBytes; |
*idh = nil; |
*imageData = nil; |
BailOSErr(FSpOpenDF( spec, fsRdPerm, &sourceRefNum )); |
BailOSErr(GetEOF( sourceRefNum, &eof )); |
eof -= 512; |
BailOSErr(SetFPos( sourceRefNum, fsFromStart, 512 )); |
picture = (PicHandle) NewHandle(eof); |
err = MemError(); |
BailOSErr(err); |
countBytes = eof; |
HLock((Handle) picture); |
BailOSErr( FSRead( sourceRefNum, &countBytes, *picture) ); |
HUnlock((Handle) picture); |
BailOSErr( RecompressPictureWithTransparency( picture, keyColor, hitTestRegion, |
idh, imageData )); |
bail: |
if ( picture ) DisposeHandle((Handle) picture ); |
if ( sourceRefNum ) FSClose( sourceRefNum ); |
return err; |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-02-25