-
Notifications
You must be signed in to change notification settings - Fork 3
/
listing22.html
executable file
·982 lines (773 loc) · 33.3 KB
/
listing22.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
<html>
<head>
<!-- BEGIN META TAG INFO -->
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link rel="home" href="http://developer.apple.com/">
<link rel="find" href="http://developer.apple.com/search/">
<link rel="stylesheet" type="text/css" href="../../documentation/css/adcstyle.css" title="fonts">
<script language="JavaScript" src="../../documentation/js/adc.js" type="text/javascript"></script>
<!-- END META TAG INFO -->
<!-- BEGIN TITLE -->
<title>Desktop Sprites - /Start Code/ImageCompressionUtilities.c</title>
<!-- END TITLE -->
<script language="JavaScript">
function JumpToNewPage() {
window.location=document.scpopupmenu.gotop.value;
return true;
}
</script>
</head>
<!-- BEGIN BODY OPEN -->
<body>
<!--END BODY OPEN -->
<!-- START CENTER OPEN -->
<center>
<!-- END CENTER OPEN -->
<!-- BEGIN LOGO AND SEARCH -->
<!--#include virtual="/includes/adcnavbar"-->
<!-- END LOGO AND SEARCH -->
<!-- START BREADCRUMB -->
<div id="breadcrumb">
<table width="680" border="0" cellpadding="0" cellspacing="0">
<tr>
<td scope="row"><img width="340" height="10" src="images/1dot.gif" alt=""></td>
<td><img width="340" height="10" src="images/1dot.gif" alt=""></td>
</tr>
<tr valign="middle">
<td align="left" colspan="2">
<a href="http://developer.apple.com/">ADC Home</a> > <a href="../../referencelibrary/index.html">Reference Library</a> > <a href="../../samplecode/index.html">Sample Code</a> > <a href="../../samplecode/LegacyTechnologies/index.html">Legacy Documents</a> > <a href="../../samplecode/LegacyTechnologies/idxQuickTime-date.html">QuickTime</a> > <A HREF="javascript:location.replace('index.html');">Desktop Sprites</A> >
</td>
</tr>
<tr>
<td colspan="2" scope="row"><img width="680" height="35" src="images/1dot.gif" alt=""></td>
</tr>
</table>
</div>
<!-- END BREADCRUMB -->
<div style="width:100%; position:fixed;"><div align="center" id="watermark" style="position: relative; margin-left:auto; margin-right:auto; z-index:20; width:500px;"><div class="legacybox"><h1>Legacy Document<span class=closebutton><a href="javascript:closeWatermark()"><img src="../../images/closebutton.png" width="14" height="14" border="0" alt="close button"></a></span></h1>
<p><strong>Important: </strong>This document is part of the Legacy section of the ADC Reference Library. This information should not be used for new development.</p>
<div class="reflibtopic">
<p>Current information on this Reference Library topic can be found here:</p>
<ul>
<li><a href="http://developer.apple.com/referencelibrary/QuickTime/idxMovieBasics-date.html" target="_blank">QuickTime > Movie Basics</a></li>
</ul>
</div>
</div></div></div>
<!-- START MAIN CONTENT -->
<!-- START TITLE GRAPHIC AND INTRO-->
<table width="680" border="0" cellpadding="0" cellspacing="0">
<tr align="left" valign="top">
<td><h1><div id="pagehead">Desktop Sprites</div></h1></td>
</tr>
</table>
<!-- END TITLE GRAPHIC AND INTRO -->
<!-- START WIDE COLUMN -->
<table width="680" border="0" cellpadding="0" cellspacing="0">
<tr align="left" valign="top">
<td id="scdetails">
<h2>/Start Code/ImageCompressionUtilities.c</h2>
<form name="scpopupmenu" onSubmit="return false;" method=post>
<p><strong>View Source Code:</strong>
<select name="gotop" onChange="JumpToNewPage();" style="width:340px"><option selected value="ingnore">Select File</option>
<option value="listing1.html">/Clippings/animsprite.c/SetSpriteImage.txt</option>
<option value="listing2.html">/Clippings/animsprite.c/SetSpriteMatrix.txt</option>
<option value="listing3.html">/Clippings/createsprites.c/CreateSpriteLayerGWorld.txt</option>
<option value="listing4.html">/Clippings/createsprites.c/CreateSpriteWorld.txt</option>
<option value="listing5.html">/Clippings/createsprites.c/NewSprite.txt</option>
<option value="listing6.html">/Clippings/dispsprite.c/DisposeSprites.txt</option>
<option value="listing7.html">/Clippings/main.c/SpriteWorldIdle.txt</option>
<option value="listing8.html">/Completed Lab/animsprite.c</option>
<option value="listing9.html">/Completed Lab/animsprite.h</option>
<option value="listing10.html">/Completed Lab/createsprites.c</option>
<option value="listing11.html">/Completed Lab/createsprites.h</option>
<option value="listing12.html">/Completed Lab/dispsprite.c</option>
<option value="listing13.html">/Completed Lab/dispsprite.h</option>
<option value="listing14.html">/Completed Lab/ImageCompressionUtilities.c</option>
<option value="listing15.html">/Completed Lab/ImageCompressionUtilities.h</option>
<option value="listing16.html">/Completed Lab/main.c</option>
<option value="listing17.html">/Completed Lab/main.h</option>
<option value="listing18.html">/MacPrefix.h</option>
<option value="listing19.html">/Start Code/animsprite.c</option>
<option value="listing20.html">/Start Code/createsprites.c</option>
<option value="listing21.html">/Start Code/dispsprite.c</option>
<option value="listing22.html">/Start Code/ImageCompressionUtilities.c</option>
<option value="listing23.html">/Start Code/main.c</option></select>
</p>
</form>
<p><strong><a href="Desktop_Sprites.zip">Download Sample</a></strong> (“Desktop_Sprites.zip”, 795.0K)<BR>
<strong><a href="Desktop_Sprites.dmg">Download Sample</a></strong> (“Desktop_Sprites.dmg”, 1.18M)</p>
<!--
<p><strong><a href="#">Download Sample</a></strong> (“filename.sit”, 500K)</p>
-->
</td>
</tr>
<tr>
<td scope="row"><img width="680" height="10" src="images/1dot.gif" alt=""><br>
<img height="1" width="680" src="images/1dot_919699.gif" alt=""><br>
<img width="680" height="20" src="images/1dot.gif" alt=""></td>
</tr>
<tr>
<td scope="row">
<!--googleon: index -->
<pre class="sourcecodebox">////////////// 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)://// <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////////////#ifndef __CONDITIONALMACROS__#include "ConditionalMacros.h"#endif#ifndef __COLORPICKER__#include <ColorPicker.h>#endif#ifndef __RESOURCES__#include <Resources.h>#endif#ifndef __ENDIAN__#include <Endian.h>#endif#ifndef _IMAGECOMPRESSIONUTILITIES_#include "ImageCompressionUtilities.h"#endif#ifndef __QUICKDRAW__#include "QuickDraw.h"#endifpascal void extractStdPix( PixMap *src, Rect *srcRect, MatrixRecord *matrix, short mode, RgnHandle mask, PixMap *matte, Rect *matteRect, short flags );static ImageDescriptionHandle createImageDescription( CodecType cType, PixMapHandle pixmap );static void DrawPictureNoDither(PicHandle pic, const Rect *bounds);static OSErr prepareFor16BitCompress(PicHandle *pic);// We use the Animation compressor at 16 bit depth in these utilities#define kCompressDepth 16// Used for compressing QuickDraw pictures with transparency/hittestingtypedef struct { PicHandle picture;} PictureCompressProcData;static pascal OSErr myPictureCompressDrawProc( short message, Rect * bounds, GWorldPtr drawingPort, OSType portType, void * refcon );// Used for recompressing QuickTime compressed data with transparency/hittestingtypedef struct { ImageDescriptionHandle imageDesc; Handle imageData;} CompressedImageCompressProcData;static pascal OSErr myImageCompressDrawProc( short message, Rect * bounds, GWorldPtr drawingPort, OSType portType, void * refcon );// A few macros to help with error handling#define BailIf(a, e) {if (a) { err = e; goto bail; }}#define BailOSErr(a) {if ((err = a) != noErr) goto bail;}#define BailMemErr(a) {a; if ((err = MemError()) != noErr) goto bail;}// 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.//typedef struct { CGrafPtr tempPort; Handle data; ImageDescriptionHandle idh;} extractPictRecord;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 ); state.tempPort = CreateNewPort(); SetStdCProcs( &procs ); procs.newProc1 = (UniversalProcPtr)/*NewStdPixProc*/NewStdPixUPP(extractStdPix); SetPortGrafProcs(state.tempPort, &procs); state.data = nil; state.idh = nil; MacSetPort( state.tempPort ); HidePen(); bounds = (**thePict).picFrame; DrawPicture(thePict, &bounds); MacSetPort( savePort ); DisposePort(state.tempPort); DisposeStdPixUPP((StdPixUPP)procs.newProc1); *dataOut = state.data; *idh = state.idh; return err;}pascal 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; OSErr err; if ( (err=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 void noDitherBitsProc(BitMap *srcBits, Rect *srcRect, Rect *dstRect, short mode, RgnHandle maskRgn);pascal 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(savePort, &procs); DrawPicture(pic, bounds); SetPortGrafProcs(savePort, saveProcs); DisposeQDBitsUPP((QDBitsUPP)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.//#define kThreshold (255 - 16)OSErr prepareFor16BitCompress(PicHandle *pic){ OSErr err = noErr; PicHandle newPicture = nil; Rect r; GWorldPtr gw = nil; CGrafPtr savePort; GDHandle saveGD; short rowBytes; Ptr baseAddr; long w, h; PixMapHandle pm; 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((BitMap *)&pm, (BitMap *)&pm, &r, &r, ditherCopy, nil); ClosePicture(); UnlockPixels(pm);bail: if (gw) DisposeGWorld(gw); if (err == noErr) { if (newPicture) { KillPicture(*pic); *pic = newPicture; } } SetGWorld(savePort, saveGD); return err;}/* ---------------- 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(noErr != (err = MemError())) 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 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 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, &params, (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, &params, (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;}</pre>
<!--googleoff: index -->
</td>
</tr>
</table>
<!-- END WIDE COLUMN -->
<!-- END MAIN CONTENT -->
<table width="680" border="0" cellpadding="0" cellspacing="0">
<tr>
<td><div style="width: 100%; height: 1px; background-color: #919699; margin-top: 5px; margin-bottom: 15px"></div></td>
</tr>
<tr>
<td align="center"><br/>
<table border="0" cellpadding="0" cellspacing="0" class="graybox">
<tr>
<th>Did this document help you?</th>
</tr>
<tr>
<td>
<div style="margin-bottom: 8px"><a href="http://developer.apple.com/feedback/?v=1&url=/samplecode/Desktop_Sprites/listing22.html%3Fid%3DDTS10001036-1.0&media=dvd" target=_new>Yes</a>: Tell us what works for you.</div>
<div style="margin-bottom: 8px"><a href="http://developer.apple.com/feedback/?v=2&url=/samplecode/Desktop_Sprites/listing22.html%3Fid%3DDTS10001036-1.0&media=dvd" target=_new>It’s good, but:</a> Report typos, inaccuracies, and so forth.</div>
<div><a href="http://developer.apple.com/feedback/?v=3&url=/samplecode/Desktop_Sprites/listing22.html%3Fid%3DDTS10001036-1.0&media=dvd" target=_new>It wasn’t helpful</a>: Tell us what would have helped.</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!-- START BOTTOM APPLE NAVIGATION -->
<!--#include virtual="/includes/footer"-->
<!-- END BOTTOM APPLE NAVIGATION -->
<!-- START CENTER CLOSE -->
</center>
<!-- END CENTER CLOSE -->
</body>
</html>