00001 /*********************************************************************** 00002 * 00003 Sample Code Disclaimer 00004 00005 Copyright © 2002-2005 PalmSource, Inc. or its subsidiaries. All 00006 rights reserved. 00007 00008 You may incorporate this sample code (the "Code") into your applications 00009 for Palm OS(R) platform products and may use the Code to develop 00010 such applications without restriction. The Code is provided to you on 00011 an "AS IS" basis and the responsibility for its operation is 100% yours. 00012 PALMSOURCE, INC. AND ITS SUBSIDIARIES (COLLECTIVELY, "PALM") DISCLAIM 00013 ALL WARRANTIES, TERMS AND CONDITIONS WITH RESPECT TO THE CODE, EXPRESS, 00014 IMPLIED, STATUTORY OR OTHERWISE, INCLUDING WARRANTIES, TERMS OR 00015 CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 00016 NONINFRINGEMENT AND SATISFACTORY QUALITY. You are not permitted to 00017 redistribute the Code on a stand-alone basis. TO THE FULL EXTENT ALLOWED BY LAW, 00018 PALMSOURCE ALSO EXCLUDES ANY LIABILITY, WHETHER BASED IN CONTRACT OR TORT 00019 (INCLUDING NEGLIGENCE), FOR INCIDENTAL, CONSEQUENTIAL, INDIRECT, SPECIAL OR 00020 PUNITIVE DAMAGES OF ANY KIND, OR FOR LOSS OF REVENUE OR PROFITS, LOSS OF 00021 BUSINESS, LOSS OF INFORMATION OR DATA, OR OTHER FINANCIAL LOSS ARISING OUT 00022 OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE CODE. The Code is 00023 subject to Restricted Rights for U.S. government users and export regulations. 00024 00025 00026 SAMPLE NAME: Bitmap Resource 00027 00028 FILE: BitmapRsrc.c 00029 00030 DATE: 1/31/2005 00031 00032 DESCRIPTION: Source Code 00033 00034 Requires Palm OS 5 SDK (DR12) or later 00035 * 00036 * 00037 *****************************************************************************/ 00038 /***************************************************************************** 00039 * 00040 * $RCSfile: BitmapRsrc_8c-source.html,v $ 00041 * 00042 * $Author: mp $ 00043 * 00044 * $Date: 2007-10-08 20:40:32 $ 00045 * 00046 * $Revision: 1.1.2.1 $ 00047 * 00048 * $Log: BitmapRsrc_8c-source.html,v $ 00048 * Revision 1.1.2.1 2007-10-08 20:40:32 mp 00048 * updated for gps4palm V0.9.5 beta 00048 * 00049 * Revision 1.2 2005-05-06 13:31:21 mp 00050 * removed unused variable transparentValue 00051 * 00052 * Revision 1.1 2005/04/08 14:44:38 mp 00053 * imported from 'Bitmap Resource' sample code by PalmSource 00054 * 00055 * 00056 ****************************************************************************/ 00057 00058 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00059 00060 00061 00062 #include <PalmOS.h> 00063 #include "BitmapRsrc.h" 00064 00065 00066 // Just before deleting a bitmap, fill it with this byte. 00067 // Then, if used later and error checking is on, this code 00068 // can detect the use of a deleted bitmap. 00069 #define DEAD_FILL_BYTE 0xFE 00070 00071 #if 0 00072 #pragma mark - 00073 #pragma mark === Error Checking Level === 00074 #endif // 0 00075 00076 00077 // ErrIf_() gives a fatal error on debug builds and just 00078 // goes to the "cleanup" for non-debug builds. 00079 #if ERROR_CHECK_LEVEL == ERROR_CHECK_FULL 00080 #define ErrIf_(test, message) ErrFatalDisplayIf(test,message) 00081 #define SimpleVerify_(bmp) VerifyBitmap(bmp) 00082 #else 00083 #define ErrIf_(test, message) if (test) goto cleanup 00084 #define SimpleVerify_(bmp) while(false) { ; } 00085 #endif 00086 00087 00088 00089 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00090 static Boolean VerifyBitmap(const BmpRsrcType * bmp) 00091 { 00092 // Do some basic checking. Nothing special... just something 00093 // fast that will catch some of the common mistakes. 00094 00095 ErrIf_(bmp==NULL, "Bitmap is NULL"); 00096 ErrIf_(((UInt16)(bmp->v0.width) == ((DEAD_FILL_BYTE<<8) | DEAD_FILL_BYTE)), 00097 "Bitmap used after being deleted"); 00098 ErrIf_(bmp->v2.version!=0 && bmp->v2.version != 1 00099 && bmp->v2.version!=2 && bmp->v2.version!=3, 00100 "Bitmap has invalid version; possibly corrupt bitmap or ARM-native bitmap"); 00101 00102 00103 return true; 00104 00105 cleanup: 00106 return false; 00107 } 00108 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00109 #if 0 00110 #pragma mark - 00111 #pragma mark === Private Utilities === 00112 #endif // 0 00113 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00114 static inline Int32 CalcRowBytes(Int16 width, Int16 pixelSize) 00115 { 00116 // The number of bits is the width in pixels * the number of 00117 // bits used per pixel. 00118 Int32 numberOfBits = (Int32)width * pixelSize; 00119 00120 00121 // rowBytes is the # of bytes but must be rounded UP to an even 00122 // number of bytes. By adding 15 to the number of bits, 00123 // dividing by 16, and then 00124 // multiplying by 2 we arrive at the correct answer. 00125 // Instead of the painful multiply and divide sequence, 00126 // we can shift right by 4 and then shift left by 1 00127 // to achieve the same result. 00128 Int16 rowBytes = (numberOfBits+15) >> 4 << 1; 00129 00130 00131 00132 return rowBytes; 00133 } 00134 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00135 static inline UInt32 RomVersion() 00136 { 00137 // Determin the ROM version. 00138 UInt32 romVersion; 00139 FtrGet(sysFtrCreator, sysFtrNumROMVersion, &romVersion); 00140 return romVersion; 00141 } 00142 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00143 static inline Boolean HasHighDensityAPIs() 00144 { 00145 // Determins if a device has the high-density APIs. Note that 00146 // some devices might have the APIs but their screens could be 00147 // standard (low) density. In this, high-density offscreens 00148 // can still be created although their use is somewhat limited. 00149 return SysGetTrapAddress(sysTrapHighDensityDispatch) != 00150 SysGetTrapAddress(sysTrapSysUnimplemented); 00151 } 00152 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00153 static inline Int32 CalcColorTableSize(const ColorTableType * ct) 00154 { 00155 // Equivalent to BmpColortableSize() except this code operates 00156 // directly on a colortable instead of on a colortable embedded in 00157 // a bitmap. 00158 if (ct == NULL) return 0; 00159 else return sizeof(ColorTableType) + sizeof(RGBColorType)*ct->numEntries; 00160 } 00161 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00162 static const BitmapDirectInfoType * FindDirectInfo(const BmpRsrcV2Type * v2) 00163 { 00164 // On V2 16bit bitmaps this routine finds the "directInfo" structure. 00165 Int32 offset = sizeof(BmpRsrcV2Type); 00166 if (v2->flags.indirectColorTable) offset += sizeof(void*); 00167 else offset += CalcColorTableSize(BmpRsrcGetColorTable((BmpRsrcType*)v2)); 00168 return (const BitmapDirectInfoType *)(((const UInt8 *)v2) + offset); 00169 } 00170 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00171 static Boolean IsDummyBitmap(const BmpRsrcType * bmp) 00172 { 00173 // Determins if a resource bitmap is the "fake" bitmap that separates 00174 // the standard density bitmaps from the high density bitmaps in 00175 // a bitmap family. 00176 return (bmp != NULL 00177 && BmpRsrcGetVersion(bmp) == 1 00178 && (BmpRsrcGetPixelSize(bmp) == 0xFF)); 00179 } 00180 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00181 00182 SysAppInfoPtr SysGetAppInfo(SysAppInfoPtr *uiAppPP, SysAppInfoPtr *actionCodeAppPP) 00183 SYS_TRAP(sysTrapSysGetAppInfo); 00184 #define memNewChunkFlagAllowLarge 0x1000 // allow >64K allocations 00185 00186 00187 static void * BigMemoryAlloc(Int32 size) 00188 { 00189 // Allocate a chunk of memory where the size of the memory might exceed 00190 // 64k. There are a few potential problems here: 00191 // (a) the memory cannot be saved to a database 00192 // (b) if you forget to free the large chunk before 00193 // you application quits, you will cause a MEMORY LEAK on 00194 // Palm OS 5 and 5.1 . 00195 if (size > 65500) 00196 { 00197 SysAppInfoPtr unusedAppInfoP; 00198 UInt16 currentOwnerID = SysGetAppInfo(&unusedAppInfoP, &unusedAppInfoP)->memOwnerID; 00199 return MemChunkNew(0, size, currentOwnerID | memNewChunkFlagNonMovable | memNewChunkFlagAllowLarge); 00200 } 00201 else return MemPtrNew(size); 00202 } 00203 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00204 static inline void BigMemoryFree(void * ptr) 00205 { 00206 // Memory allocated with MemChunkNew() and MemPtrNew() can both be 00207 // freed with MemPtrFree(). There is never a need to call MemChunkFree(). 00208 00209 ErrIf_(!ptr, "Invalid memory free"); 00210 MemPtrFree(ptr); 00211 00212 cleanup: 00213 ; 00214 } 00215 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00216 #if 0 00217 #pragma mark - 00218 #pragma mark === Create / Delete === 00219 #endif // 0 00220 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00221 BmpRsrcType * BmpRsrcV0Create(Int16 width, Int16 height) 00222 { 00223 // Pixel depth is always 1-bit (black and white). 00224 // No color table, transparent color is implied white. 00225 00226 Int16 rowBytes; 00227 Int32 pixelDataSize, totalSize; 00228 BmpRsrcV0Type * bmp = NULL; 00229 00230 ErrIf_(width<=0 || width>4096 || height<=0 || height>4096, 00231 "Improper bitmap dimensions"); 00232 00233 rowBytes = CalcRowBytes(width,1); 00234 pixelDataSize = (Int32)rowBytes * height; 00235 totalSize = sizeof(BmpRsrcV0Type) + pixelDataSize; 00236 00237 00238 bmp = BigMemoryAlloc(totalSize); 00239 ErrNonFatalDisplayIf(bmp==NULL, "Out of memory"); 00240 if (bmp == NULL) goto cleanup; 00241 00242 // This clears out everything. The important thing is that 00243 // it sets all the flags to 0 (false), sets the reserved 00244 // bytes to 0, and sets the pixel data to zero (white). 00245 MemSet(bmp, totalSize, 0); 00246 00247 bmp->width = width; 00248 bmp->height = height; 00249 bmp->rowBytes = rowBytes; 00250 00251 00252 00253 cleanup: 00254 return (BmpRsrcType*)bmp; 00255 } 00256 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00257 BmpRsrcType * BmpRsrcV2Create(Int16 width, Int16 height, 00258 Int16 pixelSize, 00259 const ColorTableType * ct, 00260 const UInt8 * bits) 00261 { 00262 // If bits is NULL, the bitmap will be created with one 00263 // chunk of memory. Otherwise, an indirect bitmap is created and 00264 // the bits are allocated by the caller and DELETED after the 00265 // bitmap is deleted (if the bits is part of a resource, then 00266 // you don't delete, but the resource must be locked while the 00267 // bitmap is in use). 00268 00269 // On devices with double-density support, it is preferable that 00270 // bitmaps be created without color tables (pass NULL for ct). 00271 // On older devices, bitmaps used as a destination by 00272 // calling WinCreateBitmapWindow() should contain a color table 00273 // if the pixel size of the offscreen is different than the pixel size 00274 // of the screen. 00275 00276 00277 Int16 rowBytes; 00278 Int32 pixelDataSize, totalSize, colorTableSize; 00279 BmpRsrcV2Type * bmp = NULL; 00280 UInt8 * ptr; 00281 00282 ErrIf_(width<=0 || width>4096 || height<=0 || height>4096, 00283 "Improper bitmap dimensions"); 00284 ErrIf_(pixelSize!=1 && pixelSize!=2 && pixelSize!=4 00285 && pixelSize!=8 && pixelSize!=16, 00286 "Unsupported pixel size"); 00287 00288 00289 // 16-bit bitmaps may include (surprisingly) a 256-entry colortable. 00290 // 1, 2, 4, and 8-bit bitmaps may include a colortable that 00291 // has many colors as the pixelSize can allow. 00292 ErrIf_(ct!=NULL && ((pixelSize==16&&ct->numEntries!=256) 00293 || (pixelSize<=8 && ct->numEntries != 1<<pixelSize)), 00294 "Invalid colortable"); 00295 00296 00297 // Note that Palm OS 3.5 doesn't support 16 bbp. In theory, 00298 // you could still use the BitmapRsrc code. You just can't use 00299 // the native graphics of the Palm OS to work on a 16 bbp bitmap. 00300 ErrIf_(RomVersion() < sysMakeROMVersion(3,5,0,sysROMStageRelease,0), 00301 "Palm OS higher than 3.5 required for 16 bit"); 00302 00303 rowBytes = CalcRowBytes(width,pixelSize); 00304 if (bits == NULL) pixelDataSize = (Int32)rowBytes * height; 00305 else pixelDataSize = 4; 00306 totalSize = sizeof(BmpRsrcV2Type) + pixelDataSize; 00307 00308 00309 // If we have a user color table, make room for it in the 00310 // bitmap. 00311 if (ct != NULL) 00312 { 00313 colorTableSize = CalcColorTableSize(ct); 00314 totalSize += colorTableSize; 00315 } 00316 00317 // If the pixelSize is 16, make room for the BitmapDirectInfoType. 00318 if (pixelSize == 16) totalSize += sizeof(BitmapDirectInfoType); 00319 00320 00321 bmp = BigMemoryAlloc(totalSize); 00322 ErrNonFatalDisplayIf(bmp==NULL, "Out of memory"); 00323 if (bmp == NULL) goto cleanup; 00324 00325 // This clears out everything in the V2 structure. 00326 // The important thing is that 00327 // it sets all the flags to 0 (false), the nextDepthOffset to 00328 // 0 (this isn't a "bitmap family"), the transparentIndex to 00329 // 0 (transparent color is white), compressionType to 0 00330 // (no compression) and the reserved field to 0. 00331 MemSet(bmp, sizeof(BmpRsrcV2Type), 0); 00332 00333 00334 bmp->width = width; 00335 bmp->height = height; 00336 bmp->rowBytes = rowBytes; 00337 bmp->pixelSize = pixelSize; 00338 bmp->version = 2; 00339 00340 // Point ptr right after the structure. Then, 00341 // as we handle color table and 16-bit structure below we 00342 // can increment ptr beyond those pieces. In the end, 00343 // ptr will point to where the pixels go and we can clear 00344 // that area of memory. 00345 ptr = (UInt8*)(bmp+1); 00346 00347 if (ct) 00348 { 00349 // Place the color table into the bitmap following the 00350 // structure. 00351 MemMove(ptr, ct, colorTableSize); 00352 ptr += colorTableSize; 00353 bmp->flags.hasColorTable = 1; 00354 } 00355 00356 if (pixelSize == 16) 00357 { 00358 static const BitmapDirectInfoType defaultDirect 00359 = { 5,6,5, 0, {0,255,255,255} }; 00360 BitmapDirectInfoType * direct = (BitmapDirectInfoType*)ptr; 00361 ptr += sizeof(BitmapDirectInfoType); 00362 *direct = defaultDirect; 00363 bmp->flags.directColor = 1; 00364 } 00365 00366 00367 if (bits == NULL) 00368 { 00369 // Now clear the bitmap's pixels to white. Note that 00370 // white is 0xFFFF for 16-bit bitmaps but 0 for all 00371 // other bitmaps. 00372 MemSet(ptr, pixelDataSize, pixelSize==16?0xFF:0); 00373 } 00374 else 00375 { 00376 *(const UInt8**)ptr = bits; 00377 bmp->flags.indirect = true; 00378 } 00379 00380 00381 cleanup: 00382 return (BmpRsrcType*)bmp; 00383 } 00384 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00385 BmpRsrcType * BmpRsrcV3Create(Int16 width, Int16 height, 00386 Int16 pixelSize, const ColorTableType * ct, 00387 const UInt8 * bits, 00388 Int16 density, PixelFormatType pixelFormat 00389 ) 00390 { 00391 // If bits is NULL, the bitmap will be created with one 00392 // chunk of memory. Otherwise, an indirect bitmap is created and 00393 // the bits is allocated by the caller and DELETED after the 00394 // bitmap is deleted (if the bits is part of a resource, then 00395 // you don't delete, but the resource must be locked while the 00396 // bitmap is in use). 00397 00398 // On devices with double-density support, it is preferable that 00399 // bitmaps be created without color tables (pass NULL for ct). 00400 // On older devices, bitmaps used as a destination by 00401 // calling WinCreateBitmapWindow() should contain a color table 00402 // if the pixel size of the offscreen is different than the pixel size 00403 // of the screen. 00404 00405 00406 Int16 rowBytes; 00407 Int32 pixelDataSize, totalSize, colorTableSize; 00408 BmpRsrcV3Type * bmp = NULL; 00409 UInt8 * ptr; 00410 00411 ErrIf_(width<=0 || width>4096 || height<=0 || height>4096, 00412 "Improper bitmap dimensions"); 00413 ErrIf_(pixelSize!=1 && pixelSize!=2 && pixelSize!=4 00414 && pixelSize!=8 && pixelSize!=16, 00415 "Unsupported pixel size"); 00416 ErrIf_(density!=kDensityLow && density!=kDensityDouble, "Unsupported density"); 00417 ErrIf_(pixelFormat<pixelFormatIndexed || pixelFormat>pixelFormatIndexedLE, 00418 "Unsupported pixel format"); 00419 00420 // 16-bit bitmaps may include (surprisingly) a 256-entry colortable. 00421 // 1, 2, 4, and 8-bit bitmaps may include a colortable that 00422 // has many colors as the pixelSize can allow. 00423 ErrIf_(ct!=NULL && ((pixelSize==16&&ct->numEntries!=256) 00424 || (pixelSize<=8 && ct->numEntries != 1<<pixelSize)), 00425 "Invalid colortable"); 00426 00427 // If little-pixel-endian is requested, make sure the OS supports it. 00428 // In theory, you could still use the BitmapRsrc code. You just can't use 00429 // the native graphics of the Palm OS on he bitmap. 00430 ErrIf_((pixelFormat==pixelFormatIndexedLE || pixelFormat==pixelFormat565LE) 00431 && RomVersion() < sysMakeROMVersion(5,0,0,sysROMStageRelease,0) 00432 && HasHighDensityAPIs() == false, 00433 "OS doesn't support little-pixel-endian btmaps"); 00434 00435 00436 // See if the OS supports V3 bitmaps. If the OS does not, you 00437 // could still use BitmapRsrc code to work with V3 bitmaps; you just 00438 // can't use the native graphics of the Palm OS on V3 bitmaps. 00439 ErrIf_(HasHighDensityAPIs() == false, "OS doesn't support V3 bitmaps"); 00440 00441 00442 // We'll be nice to the caller about the pixelFormat. 00443 // The caller can pass either of the big-pixel-endian values to 00444 // specify big-pixel-endian or either of the little-pixel-endian 00445 // values to specify little-pixel-endian. We'll figure out 00446 // indexed or 565 here based on the pixelSize; 00447 if (pixelFormat==pixelFormatIndexed || pixelFormat==pixelFormat565) 00448 { 00449 pixelFormat = (pixelSize == 16 ? pixelFormat565 : pixelFormatIndexed); 00450 } 00451 else 00452 { 00453 if (pixelSize == 16) pixelFormat = pixelFormat565LE; 00454 else if (pixelSize == 8) pixelFormat = pixelFormatIndexed; // not LE 00455 else pixelFormat = pixelFormatIndexedLE; 00456 } 00457 00458 00459 rowBytes = CalcRowBytes(width,pixelSize); 00460 if (bits == NULL) pixelDataSize = (Int32)rowBytes * height; 00461 else pixelDataSize = 4; 00462 totalSize = sizeof(BmpRsrcV3Type) + pixelDataSize; 00463 00464 00465 // If we have a user color table, make room for it in the bitmap. 00466 if (ct != NULL) 00467 { 00468 colorTableSize = CalcColorTableSize(ct); 00469 totalSize += colorTableSize; 00470 } 00471 00472 00473 bmp = BigMemoryAlloc(totalSize); 00474 ErrNonFatalDisplayIf(bmp==NULL, "Out of memory"); 00475 if (bmp == NULL) goto cleanup; 00476 00477 // This clears out everything in the V3 structure. 00478 // The important thing is that 00479 // it sets all the flags to 0 (false), the nextDepthOffset to 00480 // 0 (this isn't a "bitmap family"), the transparentIndex to 00481 // 0 (transparent color is white), compressionType to 0 00482 // (no compression) and the reserved field to 0. 00483 MemSet(bmp, sizeof(BmpRsrcV3Type), 0); 00484 00485 00486 bmp->width = width; 00487 bmp->height = height; 00488 bmp->rowBytes = rowBytes; 00489 bmp->pixelSize = pixelSize; 00490 bmp->version = 3; 00491 bmp->size = sizeof(BmpRsrcV3Type); 00492 bmp->pixelFormat = pixelFormat; 00493 bmp->density = density; 00494 00495 00496 // Point ptr right after the structure. Then, 00497 // as we handle color table we 00498 // can increment ptr beyond those pieces. In the end, 00499 // ptr will point to where the pixels go and we can clear 00500 // that area of memory. 00501 ptr = (UInt8*)(bmp+1); 00502 00503 if (ct) 00504 { 00505 // Place the color table into the bitmap following the 00506 // structure. 00507 MemMove(ptr, ct, colorTableSize); 00508 ptr += colorTableSize; 00509 bmp->flags.hasColorTable = 1; 00510 } 00511 00512 if (pixelSize == 16) 00513 { 00514 bmp->flags.directColor = 1; // might not need to set this for V3 00515 } 00516 00517 if (bits == NULL) 00518 { 00519 // Now clear the bitmap's pixels to white. Note that 00520 // white is 0xFFFF for 16-bit bitmaps but 0 for all 00521 // other bitmaps. 00522 MemSet(ptr, pixelDataSize, pixelSize==16?0xFF:0); 00523 } 00524 else 00525 { 00526 *(const UInt8**)ptr = bits; 00527 bmp->flags.indirect = true; 00528 } 00529 00530 00531 cleanup: 00532 return (BmpRsrcType*)bmp; 00533 } 00534 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00535 BmpRsrcType * BmpRsrcCreate(Int16 width, Int16 height, 00536 Int16 pixelSize, const ColorTableType * ct, 00537 Int16 density, PixelFormatType pixelFormat) 00538 { 00539 // Create the lowest version bitmap that the input parameters will allow. 00540 00541 // Note that if density is 72 or 144 (kDensityLow or kDensityDouble) 00542 // the lowest version is V3. If 00543 // you pass 0 for density, then a V2 or V0 bitmap can be created. 00544 00545 00546 // By default, a NULL ct matches the screen's colortable. 00547 // So, just leave the colortable alone. 00548 00549 // If caller specified -1 for pixelSize, then use the pixelSize of 00550 // the current draw window. (Game developers might like this code.) 00551 if (pixelSize == -1) 00552 { 00553 pixelSize = BmpGetBitDepth(WinGetBitmap(WinGetDrawWindow())); 00554 } 00555 00556 // If density is -1, then use the density of the current draw window. 00557 if (density == -1) 00558 { 00559 if (HasHighDensityAPIs()) 00560 density = BmpGetDensity(WinGetBitmap(WinGetDrawWindow())); 00561 else 00562 density = 0; 00563 } 00564 00565 // If pixelFormat is -1, use the pixelformat of the screen. 00566 // Note that pixelFormatIndexed and pixelFormat565 always work, 00567 // they just might require extra work with drawing the bitmap 00568 // to the screen. 00569 if ((Int8)pixelFormat == (Int8)-1) 00570 { 00571 if (HasHighDensityAPIs()) 00572 { 00573 // Unfortunately, there is no BmpGetDensity() API. 00574 // The best we can do is to query the screen's 00575 // format and hope for the best. 00576 UInt32 attr; 00577 (void) WinScreenGetAttribute(winScreenPixelFormat, &attr); 00578 pixelFormat = attr; 00579 } 00580 else pixelFormat = 0; 00581 } 00582 00583 00584 00585 if (density != 0 || pixelFormat == pixelFormatIndexedLE 00586 || pixelFormat == pixelFormat565LE) 00587 { 00588 return BmpRsrcV3Create(width,height,pixelSize, 00589 ct, NULL,density,pixelFormat); 00590 } 00591 else if (pixelSize > 1 || ct != NULL) 00592 { 00593 return BmpRsrcV2Create(width,height,pixelSize,ct, NULL); 00594 } 00595 else 00596 { 00597 // Might be better to return a V2 so that you could later change 00598 // the transparent value. Oh well. If you are reading this 00599 // comment, then you obviously have the source code so can make 00600 // the change yourself... 00601 // return BmpRsrcV2Create(width,height,1,NULL,NULL); 00602 return BmpRsrcV0Create(width,height); 00603 } 00604 } 00605 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00606 void BmpRsrcDelete(BmpRsrcType * bmp) 00607 { 00608 SimpleVerify_(bmp); 00609 00610 00611 #if ERROR_CHECK_LEVEL == ERROR_CHECK_FULL 00612 // ### zero out memory for stronger error checking 00613 MemSet(bmp, BmpRsrcGetTotalSize(bmp), DEAD_FILL_BYTE); 00614 #endif 00615 00616 BigMemoryFree(bmp); 00617 00618 cleanup: 00619 return; 00620 } 00621 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00622 #if 0 00623 #pragma mark - 00624 #pragma mark === Utilities === 00625 #endif // 0 00626 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00627 Int32 BmpRsrcGetTotalSize(const BmpRsrcType * bmp) 00628 { 00629 // Computes the size of the structure. If the bitmap contains 00630 // "indirect" bits or "indirect" color table, then only sizeof(void*) 00631 // is added to the total size. "indirect" means that the bits or 00632 // the colortable are pointed to by a void* in the main structure 00633 // instead of being in-line in the main structure. 00634 00635 Int32 size = 0; 00636 00637 SimpleVerify_(bmp); 00638 00639 00640 switch (BmpRsrcGetVersion(bmp)) 00641 { 00642 case 0: 00643 size = sizeof(BmpRsrcV0Type); 00644 break; 00645 case 1: 00646 size = sizeof(BmpRsrcV1Type); 00647 break; 00648 case 2: 00649 size = sizeof(BmpRsrcV2Type); 00650 if (bmp->v2.flags.directColor) size += sizeof(BitmapDirectInfoType); 00651 break; 00652 case 3: 00653 size = bmp->v3.size; 00654 break; 00655 00656 default: 00657 goto cleanup; 00658 } 00659 00660 00661 if (bmp->v0.flags.hasColorTable) 00662 { 00663 // If the colortable is just a pointer, increase size by 4. 00664 // Otherwise the colortable is in line with the strucure 00665 // and the structure's size must be increased by the 00666 // size of the entire colortable. 00667 if (bmp->v0.flags.indirectColorTable) size += sizeof(void*); 00668 else size += CalcColorTableSize(BmpRsrcGetColorTable(bmp)); 00669 } 00670 00671 00672 00673 // When the bits are "indirect" then the bitmap structure 00674 // just has a pointer to those bits. So the total size of 00675 // that is just 4. 00676 if (bmp->v2.flags.indirect) size += sizeof(void*); 00677 else 00678 { 00679 if (bmp->v0.flags.compressed) 00680 { 00681 // For compressed bitmaps of type 3, the 00682 // first LONGWORD is the size. For older bitmaps, 00683 // the size is stored only as a 16-bit entry. 00684 void * ptr = BmpRsrcGetBits(bmp); 00685 if (bmp->v2.version == 3) size += *(UInt32*)ptr; 00686 else size += *(UInt16*)ptr; 00687 } 00688 else 00689 { 00690 // Uncompressed bitmap. Compute the size of the bits. 00691 size += (Int32)(bmp->v0.rowBytes) * bmp->v0.height; 00692 } 00693 } 00694 00695 00696 cleanup: 00697 return size; 00698 } 00699 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00700 UInt8 * BmpRsrcGetBits(const BmpRsrcType * bmp) 00701 { 00702 // Same as BmpGetBits(); 00703 00704 UInt8 * ptr = NULL; 00705 Int32 size = 0; 00706 00707 SimpleVerify_(bmp); 00708 00709 switch (BmpRsrcGetVersion(bmp)) 00710 { 00711 case 0: 00712 size = sizeof(BmpRsrcV0Type); 00713 break; 00714 case 1: 00715 case 2: 00716 size = sizeof(BmpRsrcV2Type); 00717 if (bmp->v2.flags.directColor) size += sizeof(BitmapDirectInfoType); 00718 break; 00719 case 3: 00720 size = bmp->v3.size; 00721 break; 00722 00723 default: 00724 goto cleanup; 00725 } 00726 00727 if (bmp->v0.flags.hasColorTable) 00728 { 00729 if (bmp->v0.flags.indirectColorTable) size += sizeof(void*); 00730 else size += CalcColorTableSize(BmpRsrcGetColorTable(bmp)); 00731 } 00732 00733 00734 ptr = ((UInt8*)bmp) + size; 00735 00736 if (bmp->v0.flags.indirect) ptr = *(UInt8**)ptr; 00737 00738 cleanup: 00739 return ptr; 00740 } 00741 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00742 UInt32 BmpRsrcGetTransparentValue(const BmpRsrcType * bmp) 00743 { 00744 // Same as BmpGetTransparentValue(). 00745 00746 UInt32 val = 0; 00747 00748 SimpleVerify_(bmp); 00749 00750 // Use a 32-bit return here to make room for 24-bit bitmaps in the future. 00751 switch (BmpRsrcGetVersion(bmp)) 00752 { 00753 case 0: 00754 case 1: 00755 // default value of 0 is already set 00756 break; 00757 case 2: 00758 if (bmp->v2.pixelSize <= 8) val = bmp->v2.transparentIndex; 00759 else 00760 { 00761 // Find the direct info and convert the 24-bit RGB value 00762 // stored there into 565. 00763 const BitmapDirectInfoType * direct = FindDirectInfo(&bmp->v2); 00764 val = (direct->transparentColor.r & 0x000000F8L) << 8; 00765 val |= (direct->transparentColor.g & 0x000000FCL) << 3; 00766 val |= (direct->transparentColor.b & 0x000000F8L) >> 3; 00767 } 00768 break; 00769 case 3: 00770 val = bmp->v3.transparentValue; 00771 break; 00772 default: 00773 goto cleanup; 00774 } 00775 00776 cleanup: 00777 return val; 00778 } 00779 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00780 ColorTableType * BmpRsrcGetColorTable(const BmpRsrcType * bmp) 00781 { 00782 // Same as BmpGetColortable(). 00783 Int32 offset = 0; 00784 00785 SimpleVerify_(bmp); 00786 00787 00788 switch (BmpRsrcGetVersion(bmp)) 00789 { 00790 case 0: 00791 // no color table 00792 break; 00793 case 1: 00794 if (bmp->v1.flags.hasColorTable) 00795 offset = sizeof(BmpRsrcV1Type); 00796 break; 00797 case 2: 00798 if (bmp->v2.flags.hasColorTable) 00799 offset = sizeof(BmpRsrcV2Type); 00800 break; 00801 case 3: 00802 if (bmp->v3.flags.hasColorTable) 00803 offset = bmp->v3.size; 00804 break; 00805 00806 default: 00807 goto cleanup; 00808 } 00809 00810 00811 cleanup: 00812 if (offset) 00813 { 00814 const UInt8 * ptr = ((const UInt8 *)bmp) + offset; 00815 00816 if (bmp->v0.flags.indirectColorTable == 0) return (ColorTableType*)ptr; 00817 else return *(ColorTableType**)ptr; 00818 } 00819 else return NULL; 00820 } 00821 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00822 PixelFormatType BmpRsrcGetPixelFormat(const BmpRsrcType * bmp) 00823 { 00824 PixelFormatType format = pixelFormatIndexed; 00825 00826 SimpleVerify_(bmp); 00827 00828 00829 switch (BmpRsrcGetVersion(bmp)) 00830 { 00831 case 0: 00832 case 1: 00833 break; 00834 case 2: 00835 if (bmp->v2.pixelSize == 16) format = pixelFormat565; 00836 break; 00837 case 3: 00838 format = bmp->v3.pixelFormat; 00839 break; 00840 } 00841 00842 cleanup: 00843 return format; 00844 } 00845 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00846 void BmpRsrcSetFlag(BmpRsrcType * bmp, BmpRsrcFlagEnum which, Boolean value) 00847 { 00848 // Only set the flag if the bitmap format allows that flag to be set. 00849 00850 // ### not allowing compressed bitmaps in this sample code 00851 00852 // hasColorTable, indrect, forScreen, directColor, indirectColorTable 00853 // cannot be changed on an existing bitmap. 00854 00855 SimpleVerify_(bmp); 00856 00857 00858 switch (BmpRsrcGetVersion(bmp)) 00859 { 00860 case 0: 00861 ErrIf_(which!=kNoDitherFlag, "Invalid flag for type 0 bitmap"); 00862 break; 00863 case 1: 00864 ErrIf_(which != kNoDitherFlag, 00865 "Invalid flag for type 1 bitmap"); 00866 break; 00867 case 2: 00868 ErrIf_(which != kHasTransparencyFlag 00869 && which != kNoDitherFlag, 00870 "Invalid flag for type 2 bitmap"); 00871 break; 00872 case 3: 00873 ErrIf_(which != kHasTransparencyFlag 00874 && which != kNoDitherFlag, 00875 "Invalid flag for type 3 bitmap"); 00876 break; 00877 } 00878 00879 if (value) *(UInt16*)&bmp->v0.flags |= (0x8000 >> which); 00880 else *(UInt16*)&bmp->v0.flags &= ~(0x8000 >> which); 00881 00882 00883 cleanup: 00884 return; 00885 } 00886 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00887 void BmpRsrcSetTransparentValue(BmpRsrcType * bmp, UInt32 value) 00888 { 00889 // Similar to BmpSetTransparentValue() except that this routine 00890 // does NOT set the hasTransparecy flag. This is useful 00891 // when using the winOverlay, winMask, winErase modes of the 00892 // double-density Window Manager & blitter. To simulate 00893 // the effect of BmpSetTransparentValue() you may also 00894 // want to issue a BmpRsrcSetFlag() to turn on the hasTransparency bit. 00895 00896 00897 SimpleVerify_(bmp); 00898 00899 ErrIf_(value >= ((UInt32)1 << BmpRsrcGetPixelSize(bmp)), 00900 "Transparent value out of range for bitmap's pixel size"); 00901 00902 switch (BmpRsrcGetVersion(bmp)) 00903 { 00904 case 0: 00905 case 1: 00906 // default value of 0 is already set 00907 ErrIf_(true, "Bitmap type1 0 and 1 don't support transparent value"); 00908 break; 00909 case 2: 00910 if (bmp->v2.pixelSize <= 8) bmp->v2.transparentIndex = value; 00911 else 00912 { 00913 UInt8 r = (value >> 11) /* & 0x001F */; 00914 UInt8 g = (value >> 5) & 0x003F; 00915 UInt8 b = (value /* >> 0 */) & 0x001F; 00916 00917 BitmapDirectInfoType * direct; 00918 direct = (BitmapDirectInfoType*)FindDirectInfo(&bmp->v2); 00919 00920 direct->transparentColor.r = (r<<3) | (r>>2); 00921 direct->transparentColor.g = (g<<2) | (g>>4); 00922 direct->transparentColor.b = (b<<3) | (b>>2); 00923 00924 00925 // No need to set the transparentIndex. 00926 } 00927 break; 00928 case 3: 00929 bmp->v3.transparentValue = value; 00930 break; 00931 default: 00932 goto cleanup; 00933 } 00934 00935 cleanup: 00936 return; 00937 } 00938 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00939 void BmpRsrcSetDensity(BmpRsrcType * bmp, Int16 density) 00940 { 00941 // Normally you wouldn't change the density of a bitmap on-the-fly. 00942 // It could lead to some interesting effects though.... 00943 // Suppose you created a low-density bitmap, used WinCreateBitmapWindow() 00944 // to attach a window to that offscreen bitmap, drew some text into 00945 // that offscreen using WinDrawChars() (this would be low-density text, 00946 // as the bitmap is low density), set density of the bitmap to 00947 // kDensityDouble, and then WinDrawBitmap() that bitmap to the real 00948 // screen. Voila! You have just succeeded in drawing a low density 00949 // font to a high density display; better get a magnifying glass to read 00950 // that text! 00951 00952 SimpleVerify_(bmp); 00953 00954 ErrIf_(BmpRsrcGetVersion(bmp) != 3, 00955 "Must have V3 bitmap to set density."); 00956 00957 ErrIf_(density!=kDensityLow && density !=kDensityDouble, 00958 "Unsupported bitmap density."); 00959 00960 bmp->v3.density = density; 00961 00962 cleanup: 00963 return; 00964 } 00965 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00966 #if 0 00967 #pragma mark - 00968 #pragma mark === Drawing Utilities === 00969 #endif // 0 00970 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 00971 UInt32 BmpRsrcGetPixel(const BmpRsrcType * bmp, Int16 x, Int16 y) 00972 { 00973 // Return value is 32-bit for future 24-bbp formats. 00974 // This code is very slow, as it handles a single pixel with lots of 00975 // computation overhead. Use this code as a starting point to 00976 // understand how the pixels of a bitmap are ordered and how to 00977 // write your own high-speed code. 00978 00979 const UInt8 * rowPtr; 00980 UInt32 value = -1; // returns -1 if an error occurrs. 00981 Int16 pixelSize; 00982 00983 SimpleVerify_(bmp); 00984 00985 ErrIf_(x<0 || y<0 || x>=bmp->v0.width || y>=bmp->v0.height, 00986 "Coordinate out of range"); 00987 ErrIf_(BmpRsrcGetFlag(bmp, kCompressedFlag), 00988 "can't operate on compressed bitmaps"); 00989 00990 // Figure out on which row the pixel lives. 00991 rowPtr = BmpRsrcGetBits(bmp) + (Int32)BmpRsrcGetRowBytes(bmp) * y; 00992 00993 pixelSize = BmpRsrcGetPixelSize(bmp); 00994 switch (pixelSize) 00995 { 00996 case 1: 00997 case 2: 00998 case 4: 00999 // Convert x from pixels into bits. Then pick the 01000 // correct byte. 01001 x *= pixelSize; 01002 value = rowPtr[x>>3]; 01003 01004 // Now figure out which bits within that byte we need. 01005 if (BmpRsrcGetPixelFormat(bmp) == pixelFormatIndexed) 01006 { 01007 x = 8 - (x & 7); 01008 x -= pixelSize; 01009 } 01010 else // pixelFormatIndexedLE 01011 { 01012 x = (x & 7); 01013 } 01014 01015 // Extract the bits. 01016 value >>= x; 01017 value &= ((1<<pixelSize)-1); 01018 break; 01019 case 8: 01020 value = rowPtr[x]; 01021 break; 01022 case 16: 01023 value = ((const UInt16*)rowPtr)[x]; 01024 if (BmpRsrcGetPixelFormat(bmp) == pixelFormat565LE) 01025 value = ((value >> 8) | (value << 8)) & 0x0000FFFF; 01026 break; 01027 } 01028 01029 01030 01031 01032 cleanup: 01033 return value; 01034 } 01035 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 01036 void BmpRsrcSetPixel(BmpRsrcType * bmp, Int16 x, Int16 y, UInt32 value) 01037 { 01038 // This code is very slow, as it handles a single pixel with lots of 01039 // computation overhead. Use this code as a starting point to 01040 // understand how the pixels of a bitmap are ordered and how to 01041 // write your own high-speed code. 01042 01043 // value is 32-bit for future 24-bbp formats. 01044 01045 UInt8 * rowPtr; 01046 Int16 pixelSize = BmpRsrcGetPixelSize(bmp); 01047 01048 SimpleVerify_(bmp); 01049 01050 ErrIf_(x<0 || y<0 || x>=bmp->v0.width || y>=bmp->v0.height, 01051 "Coordinate out of range"); 01052 01053 ErrIf_(BmpRsrcGetFlag(bmp, kCompressedFlag), 01054 "can't operate on compressed bitmaps"); 01055 01056 ErrIf_(value >= (1L<<pixelSize), "Pixel value too large for pixelSize"); 01057 01058 // Figure out on which row the pixel lives. 01059 rowPtr = BmpRsrcGetBits(bmp) + (Int32)BmpRsrcGetRowBytes(bmp) * y; 01060 01061 01062 switch (pixelSize) 01063 { 01064 case 1: 01065 case 2: 01066 case 4: 01067 // Convert x from pixels into bits. Then pick the 01068 // correct byte. 01069 x *= pixelSize; 01070 rowPtr += (x >> 3); 01071 01072 // Now figure out which bits within that byte we need. 01073 if (BmpRsrcGetPixelFormat(bmp) == pixelFormatIndexed) 01074 { 01075 x = 8 - (x & 7); 01076 x -= pixelSize; 01077 } 01078 else // pixelFormatIndexedLE 01079 { 01080 x = (x & 7); 01081 } 01082 01083 // Mask off the bits in the destination. 01084 *rowPtr &= ~(((1<<pixelSize)-1) << x); 01085 01086 // Write the bits to the destination. 01087 *rowPtr |= (value << x); 01088 01089 break; 01090 case 8: 01091 rowPtr[x] = value; 01092 break; 01093 case 16: 01094 if (BmpRsrcGetPixelFormat(bmp) == pixelFormat565LE) 01095 value = ((value >> 8) | (value << 8)) & 0x0000FFFF; 01096 ((UInt16*)rowPtr)[x] = value; 01097 break; 01098 } 01099 01100 01101 01102 01103 cleanup: 01104 return; 01105 } 01106 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 01107 UInt32 BmpRsrcBlackPixelValue(const BmpRsrcType * bmp) 01108 { 01109 // Give a bitmap, returns the value that will result in a black pixel. 01110 // Assumes that colortable (if any) has the standard values. 01111 01112 UInt32 value = 0; // on error, return this value 01113 Int16 pixelSize = BmpRsrcGetPixelSize(bmp); 01114 01115 SimpleVerify_(bmp); 01116 01117 if (pixelSize == 16) value = 0; 01118 else value = (1<<pixelSize) - 1; 01119 01120 cleanup: 01121 return value; 01122 } 01123 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 01124 UInt32 BmpRsrcWhitePixelValue(const BmpRsrcType * bmp) 01125 { 01126 // Give a bitmap, returns the value that will result in a white pixel. 01127 // Assumes that colortable (if any) has the standard values. 01128 01129 UInt32 value = 0; // on error, return this value 01130 Int16 pixelSize = BmpRsrcGetPixelSize(bmp); 01131 01132 SimpleVerify_(bmp); 01133 01134 if (pixelSize == 16) value = 0x0000FFFF; 01135 else value = 0; 01136 01137 cleanup: 01138 return value; 01139 } 01140 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 01141 IndexedColorType BmpRsrcBlackPixelIndex(const BmpRsrcType * bmp) 01142 { 01143 // Suitable for use with WinSetForeColor() 01144 01145 IndexedColorType value = 0; // on error, return this value 01146 Int16 pixelSize = BmpRsrcGetPixelSize(bmp); 01147 01148 SimpleVerify_(bmp); 01149 01150 01151 if (pixelSize == 16) value = 255; 01152 else value = (1<<pixelSize) - 1; 01153 01154 cleanup: 01155 return value; 01156 } 01157 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 01158 IndexedColorType BmpRsrcWhitePixelIndex(const BmpRsrcType * bmp) 01159 { 01160 // Suitable for use with WinSetForeColor() 01161 01162 SimpleVerify_(bmp); 01163 01164 01165 cleanup: 01166 return 0; 01167 } 01168 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 01169 #if 0 01170 #pragma mark - 01171 #pragma mark === Resource Bitmap Family === 01172 #endif // 0 01173 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 01174 const BmpRsrcType * BmpRsrcGetNextMemberFromFamily(const BmpRsrcType * bmp) 01175 { 01176 // Iterates through a bitmap family. 01177 01178 const BmpRsrcType * next = NULL; 01179 01180 01181 SimpleVerify_(bmp); 01182 01183 if (IsDummyBitmap(bmp)) 01184 { 01185 next = (const BmpRsrcType *)(((const BmpRsrcV1Type *)bmp) + 1); 01186 01187 } 01188 else 01189 { 01190 switch (BmpRsrcGetVersion(bmp)) 01191 { 01192 case 0: 01193 break; 01194 case 1: 01195 case 2: 01196 if (bmp->v2.nextDepthOffset != 0) 01197 next = (const BmpRsrcType *)((UInt32*)bmp + bmp->v2.nextDepthOffset); 01198 break; 01199 case 3: 01200 if (bmp->v3.nextBitmapOffset != 0) 01201 next = (const BmpRsrcType *)((UInt8*)bmp + bmp->v3.nextBitmapOffset); 01202 break; 01203 } 01204 } 01205 01206 cleanup: 01207 return next; 01208 } 01209 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 01210 BmpRsrcType * BmpRsrcCreateIndirectCopy(const BmpRsrcType * bmpRsrc) 01211 { 01212 01213 // Create an in-memory structure that points to the pixels (and 01214 // optional colortable) of the resource bitmap. 01215 01216 // Note well that the resouce bitmap must remain locked for the duration 01217 // of the created in-memory bitmap, as the in-memory bitmap 01218 // indirectly references the pixels (bits) of the resource bitmap 01219 // and the (optional) resource colortable. 01220 01221 01222 UInt8 * bits = BmpRsrcGetBits(bmpRsrc); 01223 Int16 density = BmpRsrcGetDensity(bmpRsrc); 01224 PixelFormatType pixelFormat = BmpRsrcGetPixelFormat(bmpRsrc); 01225 BmpRsrcType * bmp = NULL; 01226 Int16 width = BmpRsrcGetWidth(bmpRsrc); 01227 Int16 height = BmpRsrcGetHeight(bmpRsrc); 01228 const ColorTableType * ct = BmpRsrcGetColorTable(bmpRsrc); 01229 Int16 pixelSize = BmpRsrcGetPixelSize(bmpRsrc); 01230 int compressed = BmpRsrcGetFlag(bmpRsrc, kCompressedFlag); 01231 01232 // Create a V2 bitmap if source bitmap is V2 or less. 01233 // If source bitmap is V3, then creates a V3. 01234 // You can change this logic here if you want to ALWAYS 01235 // have a V3. Just set the createVersion variable to 3 below. 01236 int createVersion = (BmpRsrcGetVersion(bmpRsrc) <= 2) ? 2 : 3; 01237 01238 01239 // If the source is a compressed bitmap, deal with possible 01240 // mix-match between V2 and V3. A V2 bitmap stores a SHORT 01241 // before the compressed data to hold the compressed data size. 01242 // A V3 bitmap stores a LONG betfore the compressed data to hold 01243 // the compressed data size. 01244 // We handle the situation by finding the start of the compressed data 01245 // and then backing up by 2 or 4 bytes to find the pointer we need 01246 // to send in as the start of the data including the size short or long. 01247 // There is a potential bug here, though. If the new value for 01248 // "bits" is different from the unchanged value, then there will be 01249 // either a truncation of the field or the field will have garbage 01250 // in the top short. Fortunately, the blitter ignores this field 01251 // altogether. 01252 if (compressed) 01253 { 01254 // Make bits skip the compression size and point to the data. 01255 // This is dependent on the original bitmap's version. 01256 if (BmpRsrcGetVersion(bmpRsrc) <= 2) bits += 2; 01257 else bits += 4; 01258 01259 // Now back up bits enough for the NEW bitmap. 01260 // This is dependent on the NEW bitmap's version. 01261 if (createVersion <= 2) bits -= 2; 01262 else bits -= 4; 01263 } 01264 01265 01266 // The new bitmap will indirectly point back to the pixels (bits) of the 01267 // original. This "indirect" feature is only available in v2 and v3 01268 // bitmaps. Accordingly, if the version of the original is less than 2 01269 // then we create a V2. This also gives the added benefit of 01270 // allowing you to set the transparency even if the original was 01271 // v1 or v0. You might opt to always create a v3, then you could 01272 // alter the density as well. 01273 if (createVersion <= 2) 01274 bmp = BmpRsrcV2Create(width,height, pixelSize, ct, bits); 01275 else 01276 bmp = BmpRsrcV3Create(width, height, pixelSize, 01277 ct, bits, density, pixelFormat); 01278 01279 01280 01281 // Set the appropriate flags. 01282 if (compressed) 01283 { 01284 bmp->v3.flags.compressed = 1; 01285 01286 // Find the compression type and then set the compression type. 01287 // This is done in two stages so that the versions of the original 01288 // and created bitmaps can be different. 01289 compressed = bmpRsrc->v2.version == 2 01290 ? bmpRsrc->v2.compressionType : bmpRsrc->v3.compressionType; 01291 if (bmp->v2.version == 2) 01292 bmp->v2.compressionType = compressed; 01293 else 01294 bmp->v3.compressionType = compressed; 01295 } 01296 BmpRsrcSetFlag(bmp, kHasTransparencyFlag, BmpRsrcGetFlag(bmpRsrc, kHasTransparencyFlag)); 01297 BmpRsrcSetFlag(bmp, kNoDitherFlag, BmpRsrcGetFlag(bmpRsrc, kNoDitherFlag)); 01298 01299 01300 01301 if (BmpRsrcGetVersion(bmpRsrc) >= 2) 01302 BmpRsrcSetTransparentValue(bmp, BmpRsrcGetTransparentValue(bmpRsrc)); 01303 01304 01305 01306 cleanup: 01307 return bmp; 01308 } 01309 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 01310 static const BmpRsrcType * SelectBitmapFromFamily(const BmpRsrcType * bmp) 01311 { 01312 // This is a tricky function. It looks through a bitmap family 01313 // and selects the "best" one from the family for drawing to the 01314 // current draw window. This function attempts to mimic the selection 01315 // behavior of WinDrawBitmap(). However, this code attempts to handle 01316 // even more than just 2 different densities even though the Window Manager's 01317 // code at this time only handles 2. Accordingly, there may be differences. 01318 01319 // One danger is that you call this routine to see what will be 01320 // drawn with WinDrawBitmap() but for some future OS, the algorithms 01321 // differ and a different bitmap family member actually gets drawn. 01322 // An easy way around this is 01323 // to use BmpRsrcBestMemberFromFamily() instead to 01324 // make an in-memory copy of the best bitmap from the family. 01325 // Then call WinDrawBitmap() on the in-memory copy. This will force 01326 // WinDrawBitmap() to use exactly the bitmap selected with this code, 01327 // since that bitmap will be separated out from the family. 01328 01329 // If you have other ideas as to the "best" bitmap for a given situation, 01330 // modify this function. If you modify this function, you should 01331 // definitly use BmpRsrcBestMemberFromFamily(). (see previous paragraph) 01332 01333 const BitmapType * drawBitmap; 01334 WinHandle drawWindow; 01335 Int16 drawDepth, drawDensity; 01336 const BmpRsrcType * bmp2; 01337 01338 drawWindow = WinGetDrawWindow(); 01339 ErrIf_(drawWindow==NULL, "no draw window"); 01340 drawBitmap = WinGetBitmap(drawWindow); 01341 01342 drawDepth = BmpGetBitDepth(drawBitmap); 01343 01344 if (HasHighDensityAPIs()) 01345 drawDensity = BmpGetDensity(drawBitmap); 01346 else 01347 drawDensity = kDensityLow; 01348 01349 01350 01351 01352 // Version 0 bitmaps don't have families, so just return the input bitmap. 01353 if (BmpRsrcGetVersion(bmp) == 0) goto cleanup; 01354 01355 // check for dummy bitmap, and skip over it 01356 if (IsDummyBitmap(bmp)) bmp = BmpRsrcGetNextMemberFromFamily(bmp); 01357 ErrIf_(bmp==NULL, "empty bitmap family"); 01358 01359 // if there is only one bitmap, just return it 01360 if (BmpRsrcGetNextMemberFromFamily(bmp) == NULL) goto cleanup; 01361 01362 01363 01364 if (HasHighDensityAPIs()) 01365 { 01366 Int16 bestScore = -20000; 01367 // On machines that can handle high-density, we use this algorithm: 01368 // 1: avoid at all cost choosing a bitmap of higher density 01369 // than the draw window's density. 01370 // 2: choose color if the draw window is color; choose grayscale 01371 // if the draw window is grayscale 01372 // 3: if exact density is not available, try standard density 01373 // 4: if neither exact density nor standard density are available, 01374 // choose any density 01375 // 5: within color or grayscale, 01376 // select the highest depth not exceeding the draw window depth 01377 // or the lowest depth higher than the draw window depth if 01378 // lower is not available 01379 01380 for (bmp2=bmp; bmp2!=NULL; bmp2=BmpRsrcGetNextMemberFromFamily(bmp2)) 01381 { 01382 Int16 density, depth; 01383 Int16 score; 01384 if (IsDummyBitmap(bmp2)) continue; 01385 01386 density = BmpRsrcGetDensity(bmp2); 01387 depth = BmpRsrcGetPixelSize(bmp2); 01388 01389 score = 0; 01390 01391 01392 if (density > drawDensity) 01393 { 01394 // Rule 1: avoid any sort of down-sampling by giving 01395 // downsampling such a negative score that it will 01396 // only be chosen as a last resort. 01397 score += -10000; 01398 } 01399 else if (density == drawDensity) 01400 { 01401 // Rule 3: exact density is good 01402 score += 100; 01403 } 01404 else if (density == kDensityLow) 01405 { 01406 // Rule 3: low-density is next-best behind exact density 01407 score += 50; 01408 } 01409 else 01410 { 01411 // Rule 4: we're neutral to any other density 01412 score += 0; 01413 } 01414 01415 01416 01417 if ((depth>=8 && drawDepth>=8) || (depth<8 && drawDepth<8)) 01418 { 01419 // Rule 2: try to match color with color and gray with gray. 01420 // Note that this scoring trumps rule 3, so 01421 // we favor color / gray matching over density. 01422 score += 1000; 01423 } 01424 01425 if (depth <= drawDepth) 01426 { 01427 // Rule 5: extra weight to get depths within color/gray 01428 // to be chosen correctly. 01429 score += (depth - drawDepth); 01430 } 01431 else if (depth > drawDepth) 01432 { 01433 // Rule 5 again. We don't need to adjust the weight 01434 // negatively, since bitmaps are ordered by bit depth; 01435 // thus the first high-depth bitmap will be selected and 01436 // not replaced by even-higher-depth bitmaps with other 01437 // equal features. 01438 } 01439 01440 if (bestScore < score) 01441 { 01442 bestScore = score; 01443 bmp = bmp2; 01444 } 01445 } 01446 01447 01448 } 01449 else 01450 { 01451 // The machine we're running on doesn't support 01452 // the high-density APIs (NOT the same as having high-density 01453 // API's but a low-density screen, by the way). 01454 // Accordingly, we only choose from standard-density bitmaps. 01455 // Note that standard-density bitmaps appear first in the list. 01456 if (BmpRsrcGetDensity(bmp) != kDensityLow) 01457 { 01458 bmp = NULL; 01459 goto cleanup; 01460 } 01461 01462 // The algorithm is pretty simple: choose the highest depth 01463 // less than or equal to the the draw window's depth if possible. 01464 // If all bitmaps are higher depth than draw window, then choose 01465 // the lowest of those. 01466 // Note that bitmaps are ordered lowest-to-highest pixel size; 01467 // this simplifies searching. 01468 01469 01470 bmp2 = bmp; 01471 while (bmp2!=NULL && !IsDummyBitmap(bmp2) 01472 && BmpRsrcGetPixelSize(bmp2) <= drawDepth) 01473 { 01474 bmp = bmp2; 01475 bmp2 = BmpRsrcGetNextMemberFromFamily(bmp2); 01476 } 01477 } 01478 01479 01480 cleanup: 01481 return bmp; 01482 01483 01484 } 01485 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 01486 BmpRsrcType * BmpRsrcBestMemberFromFamily(const BmpRsrcType * bmpFamily) 01487 { 01488 // Iterate through bitmap family and find most appropriate bitmap to 01489 // draw into the current draw window. Then create an in-memory bitmap 01490 // from that bitmap. 01491 01492 // This could be useful if you wanted to know what bitmap WinDrawBitmap() 01493 // will draw when handed a bitmap family. Please also see comments 01494 // with SelectBitmapFromFamily() routine above. 01495 01496 // Note well that the bitmap family must remain locked for the duration 01497 // of the created in-memory bitmap. 01498 01499 // Please remember to BmpRsrcDelete() the resource when you are done! 01500 01501 // This routine isn't as inefficient as it sounds, since 01502 // the in-memory bitmap that is returned has indirect pointers back 01503 // to the color table and pixels (bits) of the original bitmap 01504 // from which it was cloned. Thus the colortable and the pixels 01505 // don't get duplicated. 01506 01507 01508 const BmpRsrcType * best = SelectBitmapFromFamily(bmpFamily); 01509 if (best == NULL) return NULL; 01510 01511 return BmpRsrcCreateIndirectCopy(best); 01512 } 01513 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 01514 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 01515 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */