GPS4Palm

Source Code Documentation


BitmapRsrc.c

Go to the documentation of this file.
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 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

Created: Mon, 08 Oct 2007 22:33:16 +0200
Copyright ©2004 M. Prinke