dibutil.cpp

Go to the documentation of this file.
00001 // $Id: dibutil.cpp 1694 2006-08-12 19:00:40Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 
00099 // DIB utility routines
00100 
00101 /*
00102 */
00103 
00104 #include "camtypes.h"
00105 //#include "dibutil.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00106 //#include "ensure.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00107 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00108 #include "grndrgn.h"
00109 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00110 //#include "resource.h"
00111 //#include "ccfile.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00112 //#include "andy.h"
00113 //#include "outptdib.h"
00114 #include "bitfilt.h"
00115 #include "bitmpinf.h"       // kernel class for storing BitmapInfo
00116 #include "progress.h"
00117 #include "tunemem.h"
00118 //#include "outptgif.h"     // GIF_TRANS_COLOUR
00119 //#include "bitmap.h"           // KernelBitmap class - in camtypes.h [AUTOMATICALLY REMOVED]
00120 #include "oilbitmap.h"      // CWxBitmap class
00121 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00122 //#include "camfiltr.h"     // BaseCamelotFilter - in camtypes.h [AUTOMATICALLY REMOVED]
00123 #include "gpalopt.h"
00124 //#include "bmapprev.h"
00125 #include "hardwaremanager.h"
00126 using namespace oilHardwareManager;
00127 
00128 // Declare smart memory handling in Debug builds
00129 #define new CAM_DEBUG_NEW
00130 
00131 // if this is non-zero, then extra scanlines get allocated to help find walking-past bitmap
00132 // type bugs
00133 #define DIB_DEBUG   0
00134 
00135 // These RenderDirection flags determine in which direction screen blits are done when subbanding
00136 // during conversion in PlotBitmap. The 16 bit one is the other way round by default as it gives
00137 // a perceived faster bit speed on some 16 bit machines.
00138 static BOOL RenderDirection4=FALSE;
00139 static BOOL RenderDirection8=FALSE;
00140 static BOOL RenderDirection16=TRUE;
00141 static BOOL RenderDirection24=FALSE;
00142 // the size of the 24-bit temporary buffer, currently 64k. Not too big as usually used
00143 // when there are large 32-bit DIBs around. Not too small as screen will seem slow.
00144 // 64k=0x10000
00145 // 1M =0x100000
00146 //
00147 // Should anyone try and do a 16 bit build the 'INT32' bit may be problematic but thats the
00148 // prefs system for you
00149 //
00150 static UINT32 SubbandConversionSize=0x80000;
00151 
00152 
00153 /********************************************************************************************
00154 
00155 >   LPBITMAPINFO AllocDIB( UINT32 Width, UINT32 Height, UINT32 Depth, LPBYTE *Bits, MemoryBlock *Blk=NULL,
00156                             , BOOL UseLimitedHeap)
00157 
00158     Author:     Andy_Pennell (Xara Group Ltd) <camelotdev@xara.com>
00159     Created:    13/4/94
00160     Inputs:     Size in pixels of DIB, Depth of bitmap (1,4,8,16,24,32)
00161                 UseLimitedHeap - TRUE if we should use the Limited memory allocator
00162     Outputs:    Bits is updated to point to an array of bytes, or NULL if failed. If Blk is
00163                 not NULL then the bitmap is allocated into it instead of using CCMalloc and
00164                 Bits will point to that. If Bits is NULL then no memory for the bitmap bytes
00165                 are allocated, just the bitmap header. Due to GDraw restrictions, we actually
00166                 allocate an extra 2 bytes plus one scanline.
00167     Returns:    Pointer to suitable BITMAPINFO or NULL if failed.
00168     Purpose:    Allocate and initialise a Windows DIB. Note biclrUsed is set only for 8-bit
00169                 and less deep bitmaps, 0 for high-colour ones. biClrImportant is zeroed.
00170     Errors:     If passed an invalid depth, will ensure and return NULL. If passed a zero
00171                 width or height, it will return a 0x0 bitmap with four bytes allocated for
00172                 the 'bits'.
00173     Scope:      Global
00174     SeeAlso:    FreeDIB & GetDIBBitsSize
00175 
00176     NB NB NB    If this changes please ensure mem allocation changes are reflected in
00177                 GetDIBBitsSize as well.
00178 
00179 ********************************************************************************************/
00180 
00181 LPBITMAPINFO AllocDIB( UINT32 Width, UINT32 Height, UINT32 Depth, LPBYTE *Bits, MemoryBlock *Blk, BOOL UseLimitedHeap)
00182 {
00183     LPBITMAPINFO lpInfo;
00184 
00185     ENSURE(Blk==NULL, "Cannot do blks yet");
00186 
00187     INT32 size = DIBUtil::ScanlineSize( Width, Depth ) * Height;
00188     #if DIB_DEBUG
00189     const INT32 dbsize = DIBUtil::ScanlineSize( Width, Depth ) * DIB_DEBUG*2;
00190     if (dbsize<16)
00191         dbsize = 16;
00192     #else
00193     const INT32 dbsize = 0;
00194     #endif
00195 
00196     if (size==0)
00197         size = 4;                                       // in case of zero w or h
00198 
00199     // Get the memory manager
00200     TunedMemory* pTuned = GetTunedMemManager();
00201 
00202     // get the bytes
00203     LPBYTE Bytes = NULL;
00204     if (Bits)
00205     {
00206         // in case of failure
00207         *Bits = NULL;
00208 
00209         // allocate the actual bits of the bitmap first
00210         if (UseLimitedHeap)
00211             Bytes = (LPBYTE) pTuned->LimitedCCMalloc(size + dbsize + EXTRA_GAVIN_BYTES + DIBUtil::ScanlineSize(Width, Depth));
00212         else
00213             Bytes = (LPBYTE)CCMalloc(size + dbsize + EXTRA_GAVIN_BYTES + DIBUtil::ScanlineSize(Width, Depth));
00214 
00215         // See what we got
00216         if (Bytes==NULL)
00217             return NULL;
00218     }
00219 
00220     // we need a BITMAPINFO structure
00221     size_t extras;
00222     INT32 used_cols = 0;
00223 
00224     switch (Depth)
00225     {
00226         case 1:
00227             extras = 2*sizeof(COLORREF);
00228             used_cols = 2;
00229             break;
00230         case 4:
00231             extras = 16*sizeof(COLORREF);
00232             used_cols = 16;
00233             break;
00234         case 8:
00235             extras = 256*sizeof(COLORREF);
00236             used_cols = 256;
00237             break;
00238         case 16:
00239             extras = 3*sizeof(COLORREF);
00240             break;
00241         case 24:
00242             extras = 0;
00243             break;
00244         case 32:
00245             extras = 3*sizeof(COLORREF);
00246             break;
00247         default:
00248             ENSURE(FALSE, "Bad bitmap depth");
00249             return NULL;
00250     }
00251 
00252     // get the bitmap info block
00253     if (UseLimitedHeap)
00254         lpInfo = (LPBITMAPINFO) pTuned->LimitedCCMalloc(sizeof(BITMAPINFO) + extras);
00255     else
00256         lpInfo = (LPBITMAPINFO) CCMalloc(sizeof(BITMAPINFO) + extras);
00257         
00258     // See if it worked
00259     if (lpInfo == NULL)
00260     {
00261         // Free the memory from the appropriate place
00262         if (UseLimitedHeap)
00263             pTuned->LimitedCCFree(Bytes);
00264         else
00265             CCFree(Bytes);
00266 
00267         return NULL;
00268     }
00269 
00270     lpInfo->bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
00271     lpInfo->bmiHeader.biWidth       = Width;
00272     lpInfo->bmiHeader.biHeight      = Height;
00273     lpInfo->bmiHeader.biPlanes      = 1;
00274     lpInfo->bmiHeader.biBitCount    = Depth;
00275     lpInfo->bmiHeader.biCompression = BI_RGB;
00276     lpInfo->bmiHeader.biXPelsPerMeter   = 3780;             // Default to 96 dpi
00277     lpInfo->bmiHeader.biYPelsPerMeter   = 3780;
00278     lpInfo->bmiHeader.biClrUsed         = used_cols;
00279     lpInfo->bmiHeader.biClrImportant    = 0;
00280     lpInfo->bmiHeader.biSizeImage       = size;
00281 
00282     if (extras > 0)
00283     {
00284         memset(&(lpInfo->bmiColors[0]), 0, extras);
00285     }
00286 
00287     if (Bits)
00288     {
00289         #if DIB_DEBUG
00290         const size_t count = DIBUtil::ScanlineSize( Width, Depth ); // bytes per scanline
00291         memset( Bytes, 0x42, count*DIB_DEBUG );                     // top area
00292         memset( Bytes + count * (Height + DIB_DEBUG), 0x42, count*DIB_DEBUG );
00293         Bytes += count * DIB_DEBUG;
00294         PINT32 lpLong = (PINT32) (Bytes-4);
00295         *lpLong = count;                                    // store count
00296         lpLong[-1] = (INT32)(Bytes + count * Height);       // and ptr to end
00297         #endif
00298         *Bits = Bytes;                                      // return for caller
00299     }
00300 
00301     return lpInfo;
00302 }
00303 
00304 /********************************************************************************************
00305 
00306 >   void FreeDIB( LPBITMAPINFO lpInfo, LPBYTE Bits, MemoryBlock *Blk, BOOL UseLimitedHeap = FALSE)
00307 
00308     Author:     Andy_Pennell (Xara Group Ltd) <camelotdev@xara.com>
00309     Created:    13/4/94
00310     Inputs:     Results of AllocDIB.
00311                 UseLimitedHeap - TRUE if we should use the Limited heap. Defaults to FALSE
00312     Outputs:    -
00313     Returns:    -
00314     Purpose:    Free up a DIB allocated with AllocDIB.
00315     Errors:     -
00316     Scope:      Global
00317     SeeAlso:    AllocDIB
00318 
00319 ********************************************************************************************/
00320 
00321 void FreeDIB( LPBITMAPINFO lpInfo, LPBYTE Bits, MemoryBlock *Blk, BOOL UseLimitedHeap)
00322 {
00323     ENSURE(Blk==NULL, "Cannot free blocks");
00324     #if DIB_DEBUG
00325     if (Bits)
00326     {
00327         const size_t count = *(PINT32)(Bits-4);
00328         const LPBYTE endbuf= (LPBYTE)*(PINT32)(Bits-8);
00329         LPBYTE p = Bits - count * DIB_DEBUG;
00330         size_t i = count - 8;
00331         while (i--)
00332         {
00333             if (*p != 0x42)
00334                 ENSURE(FALSE, "top of bitmap corrupted");
00335             p++;
00336         }
00337         p = endbuf;
00338         i = count;
00339         while (i--)
00340         {
00341             if (*p != 0x42)
00342                 ENSURE(FALSE, "bottom of bitmap corrupted");
00343             p++;
00344         }
00345         Bits -= count * DIB_DEBUG;
00346     }
00347     #endif
00348 
00349     // Free the bits
00350     if (UseLimitedHeap)
00351     {
00352         // Get the memory manager
00353         TunedMemory* pTuned = GetTunedMemManager();
00354         pTuned->LimitedCCFree(Bits);
00355         pTuned->LimitedCCFree(lpInfo);
00356     }
00357     else
00358     {
00359         CCFree(Bits);
00360         CCFree(lpInfo);
00361     }
00362 }
00363 
00364 /********************************************************************************************
00365 
00366 >   void FreeDIB( LPBITMAPINFO lpInfo, LPBYTE Bits, MemoryBlock *Blk, BOOL UseLimitedHeap = FALSE)
00367 
00368     Author:     Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com>
00369     Created:    24/5/00
00370     Inputs:     lpInfo - LPBITMAPINFO struct returned by AllocDIB
00371     Returns:    Actual size of bmp memory block allocated by AllocDIB for the bitmap bits
00372                 described by the bmp header lpInfo
00373     Purpose:    Give actual mem size allocations made by AllocDIB - more mem is allocated than
00374                 width * height * Bytes per pix
00375     Errors:     -
00376     Scope:      Global
00377     SeeAlso:    AllocDIB
00378 
00379     NOTES:      NB NB Don't use this on a LPBITMAPINFO that was not created by AllocDIB.
00380                 The calculations are specific to the way AllocDIB allocs mem, so may give you
00381                 inaccurate results for other bmp buffers
00382 
00383 ********************************************************************************************/
00384 INT32 GetDIBBitsSize( LPBITMAPINFOHEADER bh )
00385 {
00386     // Mem calc from Dibutils AllocDIB
00387     // Bytes = (LPBYTE)CCMalloc(size + dbsize + EXTRA_GAVIN_BYTES + DIBUtil::ScanlineSize(Width, Depth));
00388     return bh->biSizeImage;
00389 /*  INT32 size = DIBUtil::ScanlineSize( bh->biWidth, bh->biBitCount ) * bh->biHeight;
00390     #if DIB_DEBUG
00391     const INT32 dbsize = DIBUtil::ScanlineSize( bh->biWidth, bh->biBitCount ) * DIB_DEBUG*2;
00392     if (dbsize<16)
00393         dbsize = 16;
00394     #else
00395     const INT32 dbsize = 0;
00396     #endif
00397 
00398     if (size==0)
00399         size = 4;                                       // in case of zero w or h
00400 
00401     return size + dbsize + EXTRA_GAVIN_BYTES + DIBUtil::ScanlineSize( bh->biWidth, bh->biBitCount );
00402 */
00403 }
00404 
00405 /********************************************************************************************
00406 
00407 >   UINT32 DIBUtil::DIBScanlineSize( UINT32 PixelWidth, UINT32 Depth )
00408 
00409     Author:     Andy_Pennell (Xara Group Ltd) <camelotdev@xara.com>
00410     Created:    4/3/94
00411     Inputs:     Width in pixels of DIB, Depth of bitmap (1,4,8,16,24,32)
00412     Outputs:    -
00413     Returns:    Size on bytes of a scanline in that format
00414     Purpose:    Used in calculating bitmap memory requirements. Based on Gavin's code in
00415                 GDraw_SetDIBitmap, which it had better agree with!
00416     Errors:     If passed an invalid depth, will ensure and return 0.
00417     Scope:      Static
00418 
00419 ********************************************************************************************/
00420 
00421 UINT32 DIBUtil::ScanlineSize( UINT32 Width, UINT32 Depth )
00422 {
00423     switch (Depth)
00424     {
00425         case 1:
00426             return ((Width+31)&~31)>>3;
00427         case 2:
00428             // although Gavin doesn't support 2-bit DIBs, this function does.
00429             return ((Width+15)&~15)>>2;
00430         case 4:
00431             return ((Width+7)&~7)>>1;
00432         case 8:
00433             return ((Width+3)&~3);
00434         case 16:
00435             return ((Width+1)&~1)<<1;
00436         case 24:
00437             // although Gavin doesn't support 24-bit DIBs, this function does.
00438             return ((Width*3)+3)&~3;
00439         case 32:
00440             return Width<<2;
00441         default:
00442             ENSURE(FALSE, "Unknown bitmap depth");
00443             return 0L;
00444     }
00445 }
00446 
00447 /********************************************************************************************
00448 
00449 >   UINT32 DIBUtil::ScanlineBytes( UINT32 PixelWidth, UINT32 Depth )
00450 
00451     Author:     Andy_Pennell (Xara Group Ltd) <camelotdev@xara.com>
00452     Created:    4/3/94
00453     Inputs:     Width in pixels of DIB, Depth of bitmap (1,4,8,16,24,32)
00454     Outputs:    -
00455     Returns:    Size on bytes of a scanline in that format
00456     Purpose:    Used in calculating offsets along scanlines.
00457                 NOTE! Differs from ScanlineSize in that it DOES NOT
00458                 word align the result!!!
00459     Errors:     If passed an invalid depth, will ensure and return 0.
00460     Scope:      Static
00461 
00462 ********************************************************************************************/
00463 
00464 UINT32 DIBUtil::ScanlineBytes( UINT32 Width, UINT32 Depth )
00465 {
00466     switch (Depth)
00467     {
00468         case 1:
00469             return Width >> 3;
00470         case 2:
00471             return Width >> 2;
00472         case 4:
00473             return Width >> 1;
00474         case 8:
00475             return Width;
00476         case 16:
00477             return Width << 1;
00478         case 24:
00479             ENSURE(FALSE, "Aren't 24-bit bitmaps stored in 32BPP???");
00480             return Width * 3;
00481         case 32:
00482             return Width << 2;
00483         default:
00484             ENSURE(FALSE, "Unknown bitmap depth");
00485             return 0L;
00486     }
00487 }
00488 
00489 // this macro takes a 5-bit number and expands it into an 8-bit number by replicating
00490 // bits i.e. 43210 expands to 43210432. The input arg had better be unsigned (or have its
00491 // top bit cleared).
00492 #define EXPAND(x)   ( (x<<3) | (x>>2) )
00493 
00494 
00495 
00496 // Deep DIB Colour formats:
00497 // regardless of endian-ness:322222222221111111111
00498 //                      10987654321098765432109876543210
00499 // 32-bit as an INT32 is    00000000rrrrrrrrggggggggbbbbbbbb
00500 // 16-bit as a word is                  0rrrrrgggggbbbbb
00501 
00502 
00503 
00504 
00505 
00506 // convert 16-bit scanline to 24-bit
00507 void DIBUtil::Convert16to24( INT32 PixelWidth, LPBYTE InputBits, LPBYTE OutputBits )
00508 {
00509     LPWORD Source = (LPWORD)InputBits;
00510 
00511     while (PixelWidth--)
00512     {
00513         const WORD Data = *Source++;
00514         
00515         // get five-bit RGB values, which we then double-up just like Quickdraw does
00516         // to get an 8-bit result
00517         const BYTE Blue = Data & 0x1F;
00518         *OutputBits++ = EXPAND(Blue);
00519 
00520         const BYTE Green = (Data>>5) & 0x1F;
00521         *OutputBits++ = EXPAND(Green);
00522 
00523         const BYTE Red = (Data>>10) & 0x1F;
00524         *OutputBits++ = EXPAND(Red);
00525     }
00526 }
00527 
00528 // convert 32-bit scanline to 24-bit ignoring alpha
00529 void DIBUtil::Convert32to24( INT32 PixelWidth, LPBYTE InputBits, LPBYTE OutputBits )
00530 {
00531     // source form is B,G,R,spare
00532     // dest is B,G,R
00533     // Note: if not little-endian, is this still true?
00534     while (PixelWidth--)
00535     {
00536         OutputBits[0] = InputBits[0];
00537         OutputBits[1] = InputBits[1];
00538         OutputBits[2] = InputBits[2];
00539         OutputBits += 3;
00540         InputBits  += 4;
00541     }
00542 }
00543 
00544 
00545 // convert 32-bit scanline to 24-bit by alpha merging with the supplied colour
00546 void DIBUtil::Convert32to24Alpha(INT32 PixelWidth, LPBYTE InputBits, LPBYTE OutputBits, COLORREF Colour)
00547 {
00548     // source form is B,G,R,spare
00549     // dest is B,G,R
00550     // Note: if not little-endian, is this still true?
00551     const BYTE RedBG = (BYTE)(Colour & 0xFF);
00552     const BYTE GreenBG = (BYTE)((Colour >> 8) & 0xFF);
00553     const BYTE BlueBG = (BYTE)((Colour >> 16) & 0xFF);
00554     
00555     while (PixelWidth--)
00556     {
00557         const BYTE Trans = InputBits[3];
00558         const BYTE Alpha = 255 - Trans;
00559         OutputBits[0] = ((InputBits[0] * Alpha) + (RedBG * Trans)) / 255;
00560         OutputBits[1] = ((InputBits[1] * Alpha) + (GreenBG * Trans)) / 255;
00561         OutputBits[2] = ((InputBits[2] * Alpha) + (BlueBG * Trans)) / 255;
00562         OutputBits += 3;
00563         InputBits  += 4;
00564     }
00565 }
00566 
00567 // convert 32-bit scanline to 32-bit
00568 // (actually justs zero the rgbReserved field) !!!! I THINK NOT!!! WELL HAVE LESS OF THAT THANK!
00569 void DIBUtil::Convert32to32( INT32 PixelWidth, LPBYTE InputBits, LPBYTE OutputBits )
00570 {
00571     // done as DWORDs for speed
00572     LPDWORD Source = (LPDWORD)InputBits;
00573     LPDWORD Dest = (LPDWORD)OutputBits;
00574     while (PixelWidth--)
00575     {
00576 //      *Dest++ = *Source++ & 0x00FFFFFF; <- MarkH What for? We can deal with 32BMP Alpha channels!
00577         *Dest++ = *Source++;
00578     }
00579 }
00580 
00581 // convert 8-bit scanline to 8-bit
00582 // (straight copy really)
00583 void DIBUtil::Convert8to8( INT32 PixelWidth, LPBYTE InputBits, LPBYTE OutputBits )
00584 {
00585     LPBYTE Source = (LPBYTE)InputBits;
00586     LPBYTE Dest = (LPBYTE)OutputBits;
00587     while (PixelWidth--)
00588     {
00589         *Dest++ = *Source++;
00590     }
00591 }
00592 
00593 
00594 
00595 /********************************************************************************************
00596 
00597 >   BOOL DIBUtil::PlotDeepDIB( HDC hDC, LPBITMAPINFO lpBitmapInfo, LPBYTE lpBits, INT32 Left, INT32 Top, INT32 Width, INT32 Height, INT32 SourceLeft, INT32 SourceTop, BitmapConvertHint Hint, HPALETTE hPal=NULL)
00598 
00599     Author:     Andy_Pennell (Xara Group Ltd) <camelotdev@xara.com>
00600     Created:    9/6/94
00601     Inputs:     lpBitmapInfo must point to a 16- or 32-bpp DIB.
00602                 Using Hint means you can get better dithering
00603                 hPal only required when CONVHINT_SCREEN8/4
00604     Outputs:    -
00605     Returns:    TRUE if worked, FALSE if failed (due to lack of memory). Error will be set.
00606     Purpose:    Plot a deep DIB on a device which does not understand deep DIBs. Works by
00607                 converting to a 24-bit DIB in slices. The DIB must be using the 'standard'
00608                 RGB arrangements. If this is called on a non-True Colour device then it will
00609                 take a very very long time, as 24->8 GDI conversions are terribly slow, unless
00610                 CONVHINT_SCREEN8/4 is used.
00611     Errors:     Will ENSURE if not correct depth. Calls SetError on FALSE returns.
00612     Scope:      Static
00613 
00614 ********************************************************************************************/
00615 
00616 /* Technical notes:
00617     CONVHINT_SCREEN8/4 work, but are incomplete:
00618         1. Bad brush alignment. No attempt is made to align the brushes between slices
00619             or plots in general. It looks prety bad.
00620         2. The wxDC* parameter that is cobbled together to pass to SetPaletteEntries is
00621             a bodge. The function concerned should be modified to take an HDC.
00622     CONVHINT_METAFILE isn't implemented. The idea is that this should produce 24-bit
00623         output, using a metafile-friendly way of plotting bitmaps.
00624 */
00625 
00626 BOOL DIBUtil::PlotDeepDIB( wxDC *pDC, LPBITMAPINFO lpBitmapInfo, LPBYTE lpBits, INT32 Left, INT32 Top, INT32 Width, INT32 Height, INT32 SourceLeft, INT32 SourceTop, BitmapConvertHint Hint, HPALETTE hPal)
00627 {
00628     PORTNOTETRACE("other","DIBUtil::PlotDeepDIB - do nothing");
00629 #ifndef EXCLUDE_FROM_XARALX
00630     const WORD BitmapDepth = lpBitmapInfo->bmiHeader.biBitCount;
00631 
00632     ERROR2IF( BitmapDepth!=16 && BitmapDepth!=32, FALSE, "Wrong depth deep bitmap" );   
00633 
00634     INT32 DitherMode = 0;
00635     BOOL UseGavin = FALSE;
00636     UINT32 TempBitmapDepth = 24;
00637 
00638     // We use Gavin for 32->24 (for 16) so we can dither. We use us for 16->24 (cos its simple)
00639     if (BitmapDepth==32)
00640     {
00641         // 32->24 is us because it is easy.
00642         // 32->24 for 16 is Gavin, dither according to the hint
00643         switch (Hint)
00644         {
00645         case CONVHINT_NONE:
00646             // no hint means we do it
00647             break;
00648         case CONVHINT_PRINTER:
00649             // we assume printer is 24-bit, so that's easy
00650             break;
00651         case CONVHINT_FINAL24:
00652             // final output 24-bit means no dithering so we do it - not any more
00653             DitherMode=8;
00654             UseGavin=TRUE;
00655             break;
00656         case CONVHINT_FINAL16:
00657             DitherMode = 2; //0;                            // default to 565 - now 555
00658             UseGavin = TRUE;
00659             break;
00660         case CONVHINT_FINAL555:
00661             DitherMode = 2;
00662             UseGavin = TRUE;
00663             break;
00664         case CONVHINT_FINAL565:
00665             DitherMode = 0;
00666             UseGavin = TRUE;
00667             break;
00668         case CONVHINT_FINAL655:
00669             DitherMode = 1;
00670             UseGavin = TRUE;
00671             break;
00672         case CONVHINT_FINAL664:
00673             DitherMode = 3;
00674             UseGavin = TRUE;
00675             break;
00676         case CONVHINT_SCREEN8:
00677             DitherMode = 1;
00678             UseGavin = TRUE;
00679             TempBitmapDepth = 8;
00680             break;
00681         case CONVHINT_SCREEN4:
00682             DitherMode = 1;
00683             UseGavin = TRUE;
00684             TempBitmapDepth = 4;
00685             break;
00686         default:
00687             ERROR3( "Strange hint in PlotDeepDIB" );
00688             return FALSE;
00689             break;
00690         }
00691     }
00692 
00693     if (BitmapDepth==16)
00694     {
00695         DitherMode=2;
00696         UseGavin=TRUE; // Forsooth! Gavin can do 16 to 24 bit conversions!
00697     }
00698 
00699     // how many bytes to a source scanline? Don't use Width here, get the real bitmap width
00700     const INT32 ScanlineBytes = ScanlineSize( lpBitmapInfo->bmiHeader.biWidth, BitmapDepth );
00701 
00702     BOOL PlotDownwards = RenderDirection8;
00703 
00704     // We use the hint to determine the screen bits per pixel. Not very reliable but more so than
00705     // TempBitmapDepth (for instance).
00706     switch (Hint)
00707     {
00708     case CONVHINT_SCREEN4:
00709         PlotDownwards = RenderDirection4; break;
00710 
00711     case CONVHINT_PRINTER:
00712         PlotDownwards = FALSE; break;   
00713 
00714     case CONVHINT_FINAL24:
00715         PlotDownwards = RenderDirection24; break;
00716                 
00717     case CONVHINT_FINAL16:
00718     case CONVHINT_FINAL555:
00719     case CONVHINT_FINAL565:
00720     case CONVHINT_FINAL655:
00721     case CONVHINT_FINAL664:
00722         PlotDownwards = RenderDirection16; break;
00723 
00724     case CONVHINT_NONE:
00725     case CONVHINT_SCREEN8:
00726     default:
00727         PlotDownwards = RenderDirection8; break;
00728     }
00729 
00730     // allow for SourceLeft by adjusting address. Will always be DWORD aligned for 32-bit
00731     // DIBs, only WORD aligned for 16-bit ones
00732 
00733     // Unfortunately our source has to be DWORD aligned so fix it up
00734     if ( BitmapDepth==16 && UseGavin && (SourceLeft & 1)!=0 )
00735     {
00736         SourceLeft--;
00737         Left--;
00738         Width++; // DWORD align the plot so lpBits on a DWORD boundary
00739     }
00740 
00741     // allow for X
00742     lpBits += SourceLeft << ( BitmapDepth==16 ? 1 : 2 );
00743     // and allow for Y (remember first scanline in memory is bottom most one)
00744     lpBits += (lpBitmapInfo->bmiHeader.biHeight - ((PlotDownwards?0:Height) + SourceTop) ) * ScanlineBytes;
00745     
00746     // Gavins conversion routine can only do whole bitmaps, so the temp bitmap must be as wide
00747     // as the entire source bitmap
00748     INT32 SliceWidth = UseGavin ? lpBitmapInfo->bmiHeader.biWidth : Width;
00749 
00750     // how many bytes to a destination scanline
00751     const INT32 DestlineBytes = ScanlineSize( SliceWidth, TempBitmapDepth );
00752 
00753     // we want a buffer of a limited maximum. Work out how many scanlines that is.
00754     // (set this to 1 for debugging & even slower plotting)
00755     INT32   SliceHeight = SubbandConversionSize / DestlineBytes;
00756     if (SliceHeight<4)
00757         SliceHeight=4;
00758     else
00759         SliceHeight = (SliceHeight+3) & ~3;
00760 
00761     if (SliceHeight>Height) SliceHeight=Height;
00762 
00763     INT32 OurSliceHeight=SliceHeight; // The height of the 
00764     
00765     if (PlotDownwards)
00766     {
00767         // To get dither alignment correct we want the 1st slice to be the 'left over bit' which
00768         // isn't of height SliceHeight
00769         SliceHeight=Height;
00770         while (OurSliceHeight>SliceHeight) 
00771             OurSliceHeight-=Height;
00772     }
00773 
00774     // allocate a temporary 24-bit DIB. IMPORTANT: Due to the way we frig around with the bitmap
00775     // start address, we must allocate an additional scaline of memory to the source, else he will read past
00776     // the end of the bitmap (because that's actually what we're asking of him). AllocDIB handily
00777     // does this for us
00778     LPBYTE Buffer;
00779     LPBITMAPINFO BufferDIB = AllocDIB( SliceWidth, SliceHeight, TempBitmapDepth, &Buffer, NULL );
00780 
00781     ERROR1IF( BufferDIB==NULL, FALSE, _R(IDS_OUT_OF_MEMORY) );
00782 
00783     INT32 ColourFlag = 0;
00784 
00785     if (TempBitmapDepth<24)
00786     {
00787         // only need to do this once
00788         ColourFlag = GRenderRegion::SetPaletteEntries( BufferDIB, pDC );
00789     }
00790 
00791     // Note that the first scanline of a DIB in memory is the bottom, not the top
00792     INT32 DestY = Top + (PlotDownwards?0:Height);
00793     INT32 ThisSlice;
00794 
00795     FNPTR_SCANLINE ConvertFn = NULL;
00796     INT32 RealHeight = lpBitmapInfo->bmiHeader.biHeight;
00797     
00798     if (!UseGavin)
00799     {
00800         // calculate the correct function pointer
00801         ConvertFn = BitmapDepth==16 ? Convert16to24 : Convert32to24;
00802     }
00803 
00804     // now convert in chunks
00805     while (Height)
00806     {
00807         // how tall is this chunk going to be?
00808         ThisSlice = min(OurSliceHeight, Height);
00809         OurSliceHeight=SliceHeight; // now use strips of the correct size
00810 
00811         if (UseGavin)
00812         {
00813             // have to butcher the  bitmap params (source height restored at the end)
00814             lpBitmapInfo->bmiHeader.biHeight = ThisSlice;
00815             BufferDIB->bmiHeader.biHeight = ThisSlice;
00816             
00817             // then get the man to convert it. We assume a 5-6-5 RGB split for the moment - should
00818             // pass in a parameter to control it at some point. See gdraw.wri for list of alternatives
00819             if (PlotDownwards) lpBits -= ThisSlice * ScanlineBytes;
00820 
00821             GRenderRegion::GetStaticDrawContext()->ConvertBitmap( &lpBitmapInfo->bmiHeader, lpBits,
00822                                                         &BufferDIB->bmiHeader, Buffer, DitherMode );
00823 
00824             if (!PlotDownwards) lpBits += ThisSlice * ScanlineBytes;
00825         
00826         }
00827         else
00828         {
00829             // convert that block of scanlines into 24-bit DIB (also 'upside-down')
00830             LPBYTE ConvertedBuffer = Buffer;
00831             if (PlotDownwards) lpBits -= ThisSlice * ScanlineBytes;
00832             for (INT32 i=0; i<ThisSlice; i++)
00833             {
00834                 ConvertFn( Width, lpBits, ConvertedBuffer );
00835                 lpBits += ScanlineBytes;
00836                 ConvertedBuffer += DestlineBytes;
00837             }
00838             if (PlotDownwards) lpBits -= ThisSlice * ScanlineBytes;
00839         }
00840 
00841         // now plot our baby-DIB
00842 
00843         if (!PlotDownwards) DestY -= ThisSlice;
00844 
00845         if( Hint == CONVHINT_PRINTER )
00846         { 
00847             // printers have to do it this way else they don't half-tone correctly
00848             StretchDIBits( hDC, Left, DestY,                            // Dest top left
00849                             Width, ThisSlice,                       // Dest width/height
00850                             0,0,                                    // Source xy
00851                             Width, ThisSlice,                       // Soruce w/h
00852                             Buffer, BufferDIB,
00853                             DIB_RGB_COLORS,
00854                             SRCCOPY );
00855         }
00856         else if (TempBitmapDepth<24)
00857         {
00858             // output 4/8-bit to screen using most efficient mechanism possible
00859             GRenderRegion::PlotBitmap( hDC, ColourFlag, BufferDIB, Buffer, Left, DestY,
00860                                         Width, ThisSlice, hPal, 0,0 );
00861         }
00862         else
00863         {
00864             INT32 num = SetDIBitsToDevice( hDC, Left, DestY,                            // dest top left
00865                                 Width, ThisSlice,                       // dest w & h
00866                                 0,0,                                    // source
00867                                 0,ThisSlice,                            // scanlines (all)
00868                                 Buffer, BufferDIB,                      // the temp 24-bit DIB
00869                                 DIB_RGB_COLORS );
00870 //GdiFlush();
00871         }
00872 
00873         if (PlotDownwards) DestY += ThisSlice;
00874         Height -= ThisSlice;
00875     }
00876 
00877     if (UseGavin)
00878         lpBitmapInfo->bmiHeader.biHeight = RealHeight;
00879 
00880     FreeDIB( BufferDIB, Buffer );
00881 #endif
00882     return TRUE;
00883 }
00884 
00885 #define RLE_ESCAPE  0
00886 #define RLE_EOL     0
00887 #define RLE_EOF     1
00888 #define RLE_JMP     2
00889 #define RLE_RUN     3
00890 
00891 // this code based on DecodeRle286 from rle.c from RLEAPP from the MSDN
00892 // it reads directly from the file. The variable names have been changed to protect the innocent
00893 
00894 static BOOL UnpackRle8( CCLexFile *File, const BITMAPINFOHEADER& Header, LPBYTE Bits )
00895 {
00896     BYTE    Buffer[2];
00897     BYTE    cnt;
00898     BYTE    b;
00899     WORD    x;
00900     WORD    dx,dy;
00901     DWORD    wWidthBytes;
00902 
00903     wWidthBytes = Header.biWidth+3 & ~3;
00904 
00905     x = 0;
00906 
00907     for(;;)
00908     {
00909         if (File->read( Buffer, 2 ).bad())
00910             return FALSE;
00911         cnt = Buffer[0];
00912         b   = Buffer[1];
00913 
00914         if (cnt == RLE_ESCAPE)
00915         {
00916             switch (b)
00917             {
00918                 case RLE_EOF:
00919                     return TRUE;
00920 
00921                 case RLE_EOL:
00922                     Bits += wWidthBytes - x;
00923                     x = 0;
00924                     break;
00925 
00926                 case RLE_JMP:
00927                     if (File->read( Buffer, 2 ).bad())
00928                         return FALSE;
00929                     dx = (WORD)Buffer[0];
00930                     dy = (WORD)Buffer[1];
00931 
00932                     Bits += wWidthBytes * dy + dx;
00933                     x  += dx;
00934 
00935                     break;
00936 
00937                 default:
00938                     cnt = b;
00939                     x  += cnt;
00940                     if (File->read( Bits, cnt ).bad())
00941                         return FALSE;
00942                     Bits += cnt;
00943 
00944                     if (b & 1)
00945                     {
00946                         if (File->read( Buffer, 1).bad())               // pad read
00947                             return FALSE;
00948                     }
00949 
00950                     break;
00951             }
00952         }
00953         else
00954         {
00955             x += cnt;
00956 
00957             while (cnt-- > 0)
00958                 *Bits++ = b;
00959         }
00960     }
00961     return TRUE;
00962 }
00963 
00964 
00965 /********************************************************************************************
00966 
00967     static void ReadPalette( CCLexFile *File, INT32 HowMany, size_t SizeOfRGB, LPRGBQUAD Result )
00968 
00969     Author:     Andy_Pennell (Xara Group Ltd) <camelotdev@xara.com>
00970     Created:    19/8/94
00971     Inputs:     A file, count of how many palette entries there are, and either
00972                 sizeof(RGBTRIPLE) or sizeof(RGBQUAD).
00973     Outputs:    Result gets filled in with the palette.
00974     Returns:    -
00975     Purpose:    Read the palette section of a BMP, either in modern format or old OS 2
00976                 format. Always ends up in RGBQUAD format.
00977     Scope:      Static
00978 
00979 ********************************************************************************************/
00980 
00981 static void ReadPalette( CCLexFile *File, INT32 HowMany, size_t SizeOfRGB, LPRGBQUAD Result )
00982 {
00983     // this isn't exactly efficient but it works, is endian-independent and reliable
00984     while (HowMany--)
00985     {
00986         // Read byte by byte so we get endianness right
00987         File->read( &(Result->rgbBlue), sizeof(BYTE));
00988         File->read( &(Result->rgbGreen), sizeof(BYTE));
00989         File->read( &(Result->rgbRed), sizeof(BYTE));
00990         if (SizeOfRGB==sizeof(RGBQUAD))
00991         {   
00992             File->read( &(Result->rgbReserved), sizeof(BYTE));
00993         }
00994         else if (SizeOfRGB==sizeof(RGBTRIPLE))
00995         {
00996             Result->rgbReserved=0;
00997         }
00998         else
00999         {
01000             ENSURE(FALSE, "Strange RGB size if ReadPalette");
01001         }
01002         Result++;
01003     }
01004 }
01005 
01006 // 1 to make up transparency, 0 for normal
01007 #define FAKE_32_TRANS   0
01008 
01009 
01010 /********************************************************************************************
01011 
01012 >   BOOL DIBUtil::CanReadFromFile( const BitmapInfo *pInfo )
01013 
01014     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01015     Created:    2/2/95
01016     Inputs:     pInfo points to a kernel (BitmapInfo) bitmap info structure to look at.
01017     Outputs:    - 
01018     Returns:    TRUE if ReadFromFile will cope with it, FALSE otherwise.
01019     Purpose:    To check to see if a .bmp file can be read into memory using ReadFromFile.
01020                 At present, ReadFromFile only likes 8- & 24- & 32-bit BMPs and so we must
01021                 tell the caller that this is the case.
01022                 This is for the old OS/2 1.0 style BMPs.
01023     Scope:      Static
01024     SeeAlso:    DIBUtil::ReadFromFile;
01025 
01026 ********************************************************************************************/
01027 
01028 BOOL DIBUtil::CanReadFromFile( const BitmapInfo *pInfo )
01029 {
01030 ERROR2IF(pInfo==NULL,FALSE,"CanReadFromFile BitmapInfo pointer is null");
01031     BOOL Understand = FALSE;
01032 
01033     // Check the depth in the supplied info header to see if we like it or not
01034     INT32 Depth = pInfo->PixelDepth;
01035 TRACEUSER( "Neville", wxT("DIBUtil::CanReadFromFile depth = %d\n"), Depth );
01036     if (Depth == 32)
01037         Understand = TRUE;      // it is one of our 32bpp bmp so we definitely like it
01038     else
01039         Understand = FALSE;     // Not sure that we can cope with this
01040 
01041     return Understand;
01042 }
01043 
01044 /********************************************************************************************
01045 
01046 >   BOOL DIBUtil::CanReadFromFile( const LPBITMAPCOREHEADER pCoreHeader )
01047 
01048     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01049     Created:    2/2/95
01050     Inputs:     LPBITMAPCOREHEADER points to a bitmap info structure to look at.
01051     Outputs:    - 
01052     Returns:    TRUE if ReadFromFile will cope with it, FALSE otherwise.
01053     Purpose:    To check to see if a .bmp file can be read into memory using ReadFromFile.
01054                 At present, ReadFromFile only likes 8- & 24- & 32-bit BMPs and so we must
01055                 tell the caller that this is the case.
01056                 This is for the old OS/2 1.0 style BMPs.
01057     Scope:      Static
01058     SeeAlso:    DIBUtil::ReadFromFile;
01059 
01060 ********************************************************************************************/
01061 
01062 BOOL DIBUtil::CanReadFromFile( const LPBITMAPCOREHEADER pCoreHeader )
01063 {
01064 ERROR2IF(pCoreHeader==NULL,FALSE,"CanReadFromFile CoreHeader pointer is null");
01065     BOOL Understand = FALSE;
01066 
01067     // Check the depth in the supplied info header to see if we like it or not
01068     INT32 Depth = pCoreHeader->bcBitCount;
01069 TRACEUSER( "Neville", wxT("DIBUtil::CanReadFromFile OS/2 type depth = %d\n"), Depth );
01070     if (Depth == 32)
01071         Understand = TRUE;      // it is one of our 32bpp bmp so we definitely like it
01072     else
01073         Understand = FALSE;     // Not sure that we can cope with this
01074 
01075     return Understand;
01076 }
01077 
01078 /********************************************************************************************
01079 
01080 >   BOOL DIBUtil::CanReadFromFile( const LPBITMAPINFOHEADER pInfoHeader )
01081 
01082     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01083     Created:    2/2/95
01084     Inputs:     LPBITMAPFILEINFO points to a bitmap info structure to look at.
01085     Outputs:    - 
01086     Returns:    TRUE if ReadFromFile will cope with it, FALSE otherwise.
01087     Purpose:    To check to see if a .bmp file can be read into memory using ReadFromFile.
01088                 At present, ReadFromFile only likes 8- & 24- & 32-bit BMPs and so we must
01089                 tell the caller that this is the case.
01090                 This is for the Win 3.0+ style BMPs.
01091     Scope:      Static
01092     SeeAlso:    DIBUtil::ReadFromFile;
01093 
01094 ********************************************************************************************/
01095 
01096 BOOL DIBUtil::CanReadFromFile( const LPBITMAPINFOHEADER pInfoHeader )
01097 {
01098 ERROR2IF(pInfoHeader==NULL,FALSE,"CanReadFromFile InfoHeader pointer is null");
01099     BOOL Understand = FALSE;
01100 
01101     // Check the depth in the supplied info header to see if we like it or not
01102     INT32 Depth = pInfoHeader->biBitCount;
01103 TRACEUSER( "Neville", wxT("DIBUtil::CanReadFromFile Win 3.0+ type depth = %d\n"), Depth );
01104     if (Depth == 32)
01105         Understand = TRUE;      // it is one of our 32bpp bmp so we definitely like it
01106     else
01107         Understand = FALSE;     // Not sure that we can cope with this
01108 
01109     return Understand;
01110 }
01111 
01112 /********************************************************************************************
01113 
01114 >   static BOOL DIBUtil::ReadFromFile( CCLexFile *File, LPBITMAPINFO *Info, LPBYTE *Bits,
01115                                        BOOL ReadHeader = TRUE,
01116                                        String_64 *ProgressString = NULL, BaseCamelotFilter *pFilter = NULL)
01117 
01118     Author:     Andy_Pennell (Xara Group Ltd) <camelotdev@xara.com>
01119     Created:    4/8/94
01120     Inputs:     File            A opened CCFile that can be read from. It should be positioned at the
01121                                 start. Caller is responsible for closing it. The file needs to be in
01122                                 Binary mode.
01123                 ReadHeader      TRUE then a BITMAPFILEHEADER struct is expected
01124                                 FALSE we skip straight to the BITMAPINFO. Defaults to TRUE.
01125                 ProgressString  allows the user to specify whether they require a progress hourglass or not.
01126                                 If NULL then none is shown, otherwise an progress bar is shown
01127                                 using the text supplied. Defaults to NULL i.e. no progress bar.
01128                 BaseCamelotFilter is an alternative way of handling the progress bar, assume the
01129                                 progress bar has been start and just call the IncProgressBarCount in BaseCamelotFilter
01130                                 to do the progress bar update. Defaults to NULL i.e. no progress bar.
01131     Outputs:    Info points to a new LPBITMAPINFO struct and Bits points to the bytes.
01132                 These can be freed up with FreeDIB.
01133     Returns:    TRUE if worked, FALSE if failed (error will be set accordingly but not reported)
01134     Purpose:    Read a .bmp file into memory.
01135                 ***ONLY READS 8- & 24- & 32-bit BMPs currently***.
01136                 ***Errors on 16-bit builds***
01137                 A progress hourglass can be shown if required.
01138     Errors:     Calls SetError on FALSE returns.
01139     Scope:      Static, Public
01140     SeeAlso:    AccusoftFilters::ReadFromFile;
01141 
01142 ********************************************************************************************/
01143 
01144 BOOL DIBUtil::ReadFromFile( CCLexFile *File, LPBITMAPINFO *Info, LPBYTE *Bits, BOOL ReadHeader,
01145                             String_64 *ProgressString, BaseCamelotFilter *pFilter )
01146 {
01147     ERROR2IF(File == NULL,FALSE,"DIBUtil::ReadFromFile null File pointer");
01148     ERROR2IF(Info == NULL,FALSE,"DIBUtil::ReadFromFile null Info pointer");
01149     ERROR2IF(Bits == NULL,FALSE,"DIBUtil::ReadFromFile null Bits pointer");
01150 
01151     BITMAPINFOHEADER InfoHeader;
01152     UINT32 Depth;
01153     DWORD BitsSize=0;
01154     INT32 SizeOfHeader = 0;
01155 
01156     *Info = NULL;                                       // in case of early exit
01157     *Bits = NULL;
01158 
01159     // Must set the exception throwing flag to True and force reporting of errors to False.
01160     // This means that the caller must report an error if the function returns False.
01161     // Any calls to CCFile::GotError will now throw a file exception and should fall into
01162     // the catch handler at the end of the function.
01163     // Replaces the goto's that handled this before.
01164     BOOL OldThrowingState = File->SetThrowExceptions( TRUE );
01165     BOOL OldReportingState = File->SetReportErrors( FALSE );
01166 
01167     // If the caller has specified a string then assume they require a progress bar
01168     // Start it up.
01169     if (ProgressString != NULL)
01170     {
01171         BeginSlowJob(100, FALSE, ProgressString);
01172     }
01173 
01174     try
01175     {
01176         if (ReadHeader)
01177         {
01178             BITMAPFILEHEADER Header;
01179 
01180             File->read( &Header, sizeof(Header) );
01181             Header.bfType = LEtoNative(Header.bfType);
01182             Header.bfSize = LEtoNative(UINT32(Header.bfSize));
01183             Header.bfReserved1 = LEtoNative(Header.bfReserved1);
01184             Header.bfReserved2 = LEtoNative(Header.bfReserved2);
01185             Header.bfOffBits = LEtoNative(UINT32(Header.bfOffBits));
01186             
01187             if (File->bad())
01188                 File->GotError( _R(IDE_FORMATNOTSUPPORTED) );
01189 
01190             if (Header.bfType != 0x4D42)                        // "BM" in little-endian format
01191                 File->GotError( _R(IDE_BADFORMAT) );
01192         }
01193 
01194         // some BMPs (eg 256color.bmp) don't have one of these, they have the old OS2 sort
01195         size_t SizeOfRGB=0;
01196 
01197         File->read( &SizeOfHeader, sizeof(INT32) );
01198         SizeOfHeader = LEtoNative(SizeOfHeader);
01199         if ( SizeOfHeader==sizeof(InfoHeader) )
01200         {
01201             // sensible BMP with normal BITMAPINFOHEADER structure
01202             SizeOfRGB = sizeof(RGBQUAD);
01203             File->read( &InfoHeader.biWidth, sizeof(InfoHeader)-sizeof(INT32) );
01204 
01205             InfoHeader.biWidth          = LEtoNative(InfoHeader.biWidth);
01206             InfoHeader.biHeight         = LEtoNative(InfoHeader.biHeight);
01207             InfoHeader.biPlanes         = LEtoNative(InfoHeader.biPlanes);
01208             InfoHeader.biBitCount       = LEtoNative(InfoHeader.biBitCount);
01209             InfoHeader.biCompression    = LEtoNative(UINT32(InfoHeader.biCompression));
01210             InfoHeader.biSizeImage      = LEtoNative(UINT32(InfoHeader.biSizeImage));
01211             InfoHeader.biXPelsPerMeter  = LEtoNative(InfoHeader.biXPelsPerMeter);
01212             InfoHeader.biYPelsPerMeter  = LEtoNative(InfoHeader.biYPelsPerMeter);
01213             InfoHeader.biClrUsed        = LEtoNative(UINT32(InfoHeader.biClrUsed));
01214             InfoHeader.biClrImportant   = LEtoNative(UINT32(InfoHeader.biClrImportant));
01215         }
01216         else if ( SizeOfHeader==sizeof(BITMAPCOREHEADER) )
01217         {
01218             // silly OS2 thing - read in and convert
01219             BITMAPCOREHEADER TempHeader;
01220             File->read( &TempHeader.bcWidth, sizeof(TempHeader)-sizeof(INT32) );
01221 
01222             TempHeader.bcWidth          = LEtoNative(TempHeader.bcWidth);
01223             TempHeader.bcHeight         = LEtoNative(TempHeader.bcHeight);
01224             TempHeader.bcPlanes         = LEtoNative(TempHeader.bcPlanes);
01225             TempHeader.bcBitCount       = LEtoNative(TempHeader.bcBitCount);
01226 
01227             SizeOfRGB = sizeof(RGBTRIPLE);
01228             InfoHeader.biWidth =    TempHeader.bcWidth;
01229             InfoHeader.biHeight =   TempHeader.bcHeight;
01230             InfoHeader.biPlanes =   TempHeader.bcPlanes;
01231             InfoHeader.biBitCount = TempHeader.bcBitCount;
01232             InfoHeader.biCompression = BI_RGB;
01233             InfoHeader.biSizeImage = 0L;
01234             InfoHeader.biXPelsPerMeter = 0L;
01235             InfoHeader.biYPelsPerMeter = 0L;
01236             InfoHeader.biClrImportant = 0;
01237             if (InfoHeader.biBitCount < 24 )
01238                 InfoHeader.biClrUsed = 1<<InfoHeader.biBitCount;
01239             else
01240                 InfoHeader.biClrUsed = 0;
01241         }
01242         else
01243             File->GotError( _R(IDE_FORMATNOTSUPPORTED) );
01244 
01245 
01246         if (File->bad())
01247             File->GotError( _R(IDE_FORMATNOTSUPPORTED) );
01248 
01249         if (InfoHeader.biWidth == 0 || InfoHeader.biHeight == 0 )
01250             File->GotError( _R(IDE_BADFORMAT) );
01251 
01252         if (InfoHeader.biPlanes != 1)
01253             File->GotError( _R(IDE_BADFORMAT) );
01254 
01255         Depth = InfoHeader.biBitCount;
01256 
01257         BOOL Convert16to24 = FALSE;
01258         if (InfoHeader.biBitCount == 16 && InfoHeader.biCompression == BI_BITFIELDS)
01259         {
01260             // we will create a 24bpp bitmap and then convert the data on entry in 24bpp
01261             Depth = 24;
01262             Convert16to24 = TRUE;
01263         }
01264         
01265         // temp kludge code for now - only copes with certain depth bitmaps
01266         if ( (Depth != 1) && (Depth != 4) && (Depth != 8) && (Depth != 24) && (Depth != 32))
01267             File->GotError( _R(IDE_FORMATNOTSUPPORTED) );
01268 
01269         // we know what sort of bitmap we are - lets allocate a new LPBITMAPINFO and some bytes
01270         *Info = AllocDIB( InfoHeader.biWidth, InfoHeader.biHeight, Depth,
01271                             Bits, NULL );
01272 
01273         if (*Info == NULL)
01274             File->GotError( _R(IDS_OUT_OF_MEMORY) );
01275 
01276         // Copy interesting info from the file to the memory DIB
01277 
01278         
01279         // If PelsPerMeter is a dodgy value such as 39 (= very large pixels!)
01280         // then use 0 which means that we will display it at screen resolution.
01281 TRACEUSER( "Neville", _T("DIBUtil::ReadFromFile XPelsPerMeter=%d\n"),InfoHeader.biXPelsPerMeter);
01282 TRACEUSER( "Neville", _T("DIBUtil::ReadFromFile YPelsPerMeter=%d\n"),InfoHeader.biYPelsPerMeter);
01283         if (InfoHeader.biXPelsPerMeter > BaseBitmapFilter::MinPelsPerMeter)
01284         {
01285             (*Info)->bmiHeader.biXPelsPerMeter = InfoHeader.biXPelsPerMeter;
01286             (*Info)->bmiHeader.biYPelsPerMeter = InfoHeader.biYPelsPerMeter;
01287         }
01288         else
01289         {
01290             (*Info)->bmiHeader.biXPelsPerMeter = 0;
01291             (*Info)->bmiHeader.biYPelsPerMeter = 0;
01292         }
01293 
01294         // If the ClrUsed field is zero, put a sensible value in it
01295         // The read in value of ClrUsed also determines the number of palette entries in
01296         // the palette table.
01297         UINT32 PalColours = 0;
01298         if (Depth <= 8)
01299         {
01300             PalColours = InfoHeader.biClrUsed;
01301             // If zero then assume maximum amount of colours
01302             // otherwise, copy the value across into the new header.
01303             if (InfoHeader.biClrUsed == 0)
01304             {
01305                 (*Info)->bmiHeader.biClrUsed = 1<<Depth;
01306                 PalColours = 1<<Depth;
01307             }
01308             else
01309                 (*Info)->bmiHeader.biClrUsed = InfoHeader.biClrUsed;
01310         }
01311 
01312         // read any palette info
01313         switch (Depth)
01314         {
01315             case 1:
01316             case 4:
01317             case 8:
01318                 // read colour palette (Changed by Neville 14/10/97 to read biClrUsed)
01319                 ReadPalette( File, PalColours, SizeOfRGB, (*Info)->bmiColors);
01320                 break;
01321 
01322             case 24:
01323             case 32:
01324                 // 24-bit files sometimes have a 'hint' palette (e.g country.bmp) which
01325                 // we have to throw away (we can't load it cos the bitmap has no space alloced
01326                 // for a colour table)
01327                 if (InfoHeader.biClrUsed)
01328                     File->seekIn( InfoHeader.biClrUsed * SizeOfRGB, ios::cur );
01329                 break;
01330 
01331             default:
01332                 File->GotError( _R(IDE_FORMATNOTSUPPORTED) );
01333         }
01334 
01335         if (File->bad())
01336             File->GotError( _R(IDE_FORMATNOTSUPPORTED) );
01337 
01338         // now read the bitmap data
01339 
01340         UINT32 RedColourMask    = 0;
01341         UINT32 GreenColourMask  = 0;
01342         UINT32 BlueColourMask   = 0;
01343         switch (InfoHeader.biCompression)
01344         {
01345             case BI_RGB:
01346                 BitsSize = (*Info)->bmiHeader.biSizeImage;          // uncompressed
01347                 break;
01348 
01349             case CC_BMPTYPE:
01350                 if (Depth != 32)
01351                     File->GotError( _R(IDE_FORMATNOTSUPPORTED) );
01352                 BitsSize = (*Info)->bmiHeader.biSizeImage;          // uncompressed
01353                 break;
01354 
01355             case BI_RLE8:
01356                 if (!UnpackRle8( File, InfoHeader, *Bits ))
01357                     File->GotError( _R(IDE_BADFORMAT) );
01358                 BitsSize = 0L;                                      // no more to read
01359                 break;
01360 
01361             case BI_BITFIELDS:
01362                 // Read in the three special colour dword masks that follow the header
01363                 BitsSize = (*Info)->bmiHeader.biSizeImage;          // uncompressed
01364                 File->read( &RedColourMask,     sizeof(RedColourMask) );
01365                 File->read( &GreenColourMask,   sizeof(GreenColourMask) );
01366                 File->read( &BlueColourMask,    sizeof(BlueColourMask) );
01367 
01368                 RedColourMask           = LEtoNative(RedColourMask);
01369                 GreenColourMask         = LEtoNative(GreenColourMask);
01370                 BlueColourMask          = LEtoNative(BlueColourMask);
01371 
01372                 if (File->bad())
01373                     File->GotError( _R(IDE_BADFORMAT) );
01374                 TRACEUSER( "Neville", _T("DIBUtil::ReadFromFile BI_BITFIELDS RedColourMask = %d\n"),RedColourMask);
01375                 TRACEUSER( "Neville", _T("DIBUtil::ReadFromFile BI_BITFIELDS GreenColourMask = %d\n"),GreenColourMask);
01376                 TRACEUSER( "Neville", _T("DIBUtil::ReadFromFile BI_BITFIELDS BlueColourMask = %d\n"),BlueColourMask);
01377                 // The 32bpp case is easy. With 16bpp we need to convert to 24bpp
01378                 // We will take the Windows 95 in 32bpp mode such that it expects
01379                 // The blue mask is 0x000000FF, the green mask is 0x0000FF00, and the red mask is 0x00FF0000.
01380                 if (Depth == 32 && RedColourMask != 0xFF0000 && GreenColourMask != 0xFF00 && BlueColourMask != 0xFF)
01381                     File->GotError( _R(IDE_FORMATNOTSUPPORTED) );
01382                 else if (Depth != 24 && Depth != 32)
01383                     File->GotError( _R(IDE_FORMATNOTSUPPORTED) );
01384                 break;
01385 
01386             default:
01387                 File->GotError( _R(IDE_FORMATNOTSUPPORTED) );           // other compression not supported
01388         }
01389 
01390         if (Convert16to24 == TRUE && Depth == 24)
01391         {
01392             // We need to read in a WORD and use the bitfield to convert this into 24 bit RGB data
01393             // and then put this in the 24bpp pixel
01394             // We take the Windows 95 route in that when the biCompression member is BI_BITFIELDS,
01395             // we only support the following 16bpp color masks:
01396             // A 5-5-5 16-bit image, where
01397             //  the blue mask is 0x001F, the green mask is 0x03E0, and the red mask is 0x7C00;
01398             // and a 5-6-5 16-bit image, where
01399             // the blue mask is 0x001F, the green mask is 0x07E0, and the red mask is 0xF800.
01400             WORD Pixel = 0;
01401             INT32 Bshift = 0; // Always 0
01402             if (BlueColourMask != 0x1F) // Covers both 15bpp and 16bpp
01403                 File->GotError( _R(IDE_FORMATNOTSUPPORTED) );
01404 
01405             INT32 Gshift = 0;
01406             if (GreenColourMask == 0x7e0 || GreenColourMask == 0x3e0)
01407                 Gshift = 5;
01408             else
01409                 File->GotError( _R(IDE_FORMATNOTSUPPORTED) );
01410 
01411             INT32 Rshift = 0;
01412             if (RedColourMask == 0x7c00)
01413                 Rshift = 10;
01414             else if (RedColourMask == 0xf800)
01415                 Rshift = 11;
01416             else
01417                 File->GotError( _R(IDE_FORMATNOTSUPPORTED) );
01418 
01419             UINT32 ScanLineWidth = DIBUtil::ScanlineSize(InfoHeader.biWidth, Depth);
01420             LPBYTE pBits = *Bits;
01421             INT32 Height = InfoHeader.biHeight;
01422             INT32 Width = InfoHeader.biWidth;
01423             for (INT32 y = 0; y < Height; y++ )
01424             {
01425                 for (INT32 x = 0; x < Width; x++ )
01426                 {
01427                     // read in the pixel
01428                     File->read( &Pixel, sizeof(Pixel) );
01429                     
01430                     Pixel = LEtoNative(Pixel);
01431                     
01432                     if (File->bad())
01433                         File->GotError( _R(IDE_BADFORMAT) );
01434                     // Convert it into the B G and R components
01435                     UINT32 B = ((Pixel & BlueColourMask) >> Bshift);    // blue component
01436                     UINT32 G = ((Pixel & GreenColourMask) >> Gshift);   // green component
01437                     UINT32 R = ((Pixel & RedColourMask) >> Rshift); // red component;
01438                     // Need to shift the components into the MSBs leaving gap at bottom
01439                     // then fill in the missing LSBs with the required number of MSBs
01440                     pBits[x * 3 + 0] = (B << 3) | (B >> 2);
01441                     if (GreenColourMask == 0x7e0) // 6 bit green
01442                         pBits[x * 3 + 1] = (G << 2) | (G >> 4);
01443                     else
01444                         pBits[x * 3 + 1] = (G << 3) | (G >> 2);
01445                     pBits[x * 3 + 2] = (R << 3) | (R >> 2);
01446                 }
01447                 
01448                 // Move onto the next line
01449                 pBits += ScanLineWidth;
01450                 // Updating the progress bar as we go
01451                 ContinueSlowJob((INT32)((100 * y)/Height));
01452             }
01453         }
01454         // Read the actual bytes, used to do it in one go but we really require some
01455         // progress bar indication so we will do it in chunks.
01456         else if (BitsSize > 0)
01457         {
01458             // If pFilter is NULL and hence not native/web loading then do it in 
01459             // chunks of bytes
01460             if (pFilter == NULL)
01461             {
01462                 if (BitsSize < 1024 || ProgressString == NULL)
01463                 {
01464                     // File very small or no progress bar required, so load in one go
01465                     File->read( *Bits, BitsSize );
01466                 }
01467                 else
01468                 {
01469                     // Load in chunks, for present split into 100 chunks
01470                     DWORD ChunkSize = BitsSize/100;
01471                     DWORD Position = 0;
01472                     LPBYTE pBitInfo = *Bits;
01473                     
01474                     while (Position < BitsSize)
01475                     {
01476                         if ( (BitsSize - Position) > ChunkSize)
01477                             File->read( pBitInfo, ChunkSize );
01478                         else
01479                         {
01480                             ChunkSize = BitsSize - Position;
01481                             File->read( pBitInfo, ChunkSize );
01482                         }
01483                                 
01484                         // Increment our counters/pointers
01485                         Position += ChunkSize;
01486                         pBitInfo += ChunkSize;
01487                         ContinueSlowJob((INT32)(100*Position/BitsSize));
01488                     }
01489                 }
01490             }
01491             else
01492             {
01493                 // Do the reading a scanline at a time
01494                 // This makes progress bar update easier for native/web files
01495                 LPBYTE pBitInfo = *Bits;
01496                 UINT32 ScanLineWidth = DIBUtil::ScanlineSize(InfoHeader.biWidth, Depth);
01497                 UINT32 height = InfoHeader.biHeight; 
01498                 // Ask the filter what the record size for this bitmap is and hence
01499                 // what the allocation we have for progress bar updates are.
01500                 // We will then have to update our progress bar by
01501                 //  current scanline/total number of scanlines * allocation
01502                 // so that we get update by a proportion of the value.
01503                 // We can assume no interlacing as in native/web files this is turned off.
01504                 UINT32 RecordSize = pFilter->GetCurrentRecordSize();
01505                 if (RecordSize == 0)
01506                     RecordSize = 1;
01507                 INT32 UpdateValue = RecordSize/height;
01508                 // For each scaline in the file, read it in and update the progress bar count
01509                 for (UINT32 i = 0; i < height; i++)
01510                 {
01511                     File->read( pBitInfo, ScanLineWidth );
01512                     pBitInfo += ScanLineWidth;
01513                     pFilter->IncProgressBarCount(UpdateValue);
01514                 }
01515             }
01516         }
01517         
01518         // This shouldn't be required any more as the CATCH handler should be invoked
01519         // when problems happen.
01520         if (File->bad())
01521             File->GotError( _R(IDE_FORMATNOTSUPPORTED) );
01522 
01523         if (FAKE_32_TRANS && (Depth==32) && (InfoHeader.biCompression!=CC_BMPTYPE) )
01524         {
01525             // put some fake transparency in on a scanline by scanline basis
01526             LPRGBQUAD Data = (LPRGBQUAD)(*Bits);
01527 //          size_t size = BitsSize;
01528             UINT32 Height = (*Info)->bmiHeader.biHeight;
01529             UINT32 h = Height;
01530             Height /= 2;
01531 
01532             while (h--)
01533             {
01534                 INT32 TValue = (INT32)h - (INT32)Height;
01535                 TValue = abs(TValue);
01536                 TValue = TValue * 0xFF / Height;
01537 
01538                 UINT32 w = (*Info)->bmiHeader.biWidth;
01539                 while (w--)
01540                 {
01541                     Data->rgbReserved = (BYTE)TValue;
01542                     Data++;
01543                 }
01544                 // 32-bit DIBs automatically DWORD aligned
01545             }
01546         }
01547 
01548         // If started, then stop then progress bar
01549         if (ProgressString != NULL)
01550         {
01551             EndSlowJob();
01552         }
01553 
01554         // Must set the exception throwing and reporting flags back to their entry states
01555         File->SetThrowExceptions( OldThrowingState );
01556         File->SetReportErrors( OldReportingState );
01557 
01558         // er, we seem to have finished OK so say so
01559         return TRUE;
01560     }
01561     catch( CFileException )
01562     {
01563         // catch our form of a file exception
01564         TRACE( _T("DIBUtil::ReadFromFile CC catch handler\n"));
01565 
01566         FreeDIB( *Info, *Bits );                            // free any alloced memory
01567         *Info = NULL;                                       // and NULL the pointers
01568         *Bits = NULL;
01569 
01570         // If started, then stop then progress bar
01571         if (ProgressString != NULL)
01572         {
01573             EndSlowJob();
01574         }
01575 
01576         // Must set the exception throwing and reporting flags back to their entry states
01577         File->SetThrowExceptions( OldThrowingState );
01578         File->SetReportErrors( OldReportingState );
01579 
01580         return FALSE;
01581     }
01582 
01583     ERROR2( FALSE, "Escaped exception clause somehow" );
01584 }
01585 
01586 /********************************************************************************************
01587 
01588 >   static BOOL DIBUtil::WriteToFile ( CCLexFile *File, LPBITMAPINFO Info, LPBYTE Bits,
01589                                        String_64 *ProgressString = NULL, BOOL WriteHeader = TRUE,
01590                                        BaseCamelotFilter *pFilter = NULL )
01591 
01592     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01593     Created:    26/4/95
01594     Inputs:     File    An opened CCFile that can be written to. It should be positioned at the
01595                         start. Caller is responsible for closing it. The file needs to be in
01596                         Binary mode.
01597                 Info    BITMAPINFO structure for the dib.
01598                 Bits    The bitmap data itself
01599                 ProgressString allows the user to specify whether they require a progress
01600                         hourglass or not. If NULL then none is shown, otherwise an progress bar 
01601                         is shown using the text supplied. Defaults to NULL i.e. no progress bar.
01602                 WriteHeader     TRUE then write a BITMAPFILEHEADER to file
01603                                 FALSE skip writing the BITMAPFILEHEADER to file. Defaults to TRUE.
01604                 BaseCamelotFilter is an alternative way of handling the progress bar, assume the
01605                                 progress bar has been start and just call the IncProgressBarCount in BaseCamelotFilter
01606                                 to do the progress bar update. Defaults to NULL i.e. no progress bar.
01607     Outputs:    -
01608     Returns:    TRUE if worked, FALSE if failed (error will be set accordingly but not reported)
01609     Purpose:    Write a bitmap in memory straight out to file with now rendering or conversion.
01610                 ***Errors on 16-bit builds***
01611                 A progress hourglass can be shown if required.
01612                 This function is used by the save bitmap button on the bitmap gallery. All
01613                 other bitmap export uses the OutputDIB class instead as this copes with using
01614                 a render region and converting from 32 to the destination format.
01615                 (caller should close file)
01616     Errors:     Calls SetError on FALSE returns.
01617     Scope:      Static, Public
01618     SeeAlso:    AccusoftFilters::WriteToFile; DIBUtil::ReadFromFile;
01619 
01620 ********************************************************************************************/
01621 BOOL DIBUtil::WriteToFile ( CCLexFile *File, LPBITMAPINFO Info, LPBYTE Bits, String_64 *ProgressString, BOOL WriteHeader, BaseCamelotFilter *pFilter)
01622 {
01623 #ifndef WIN32
01624     Error::SetError( _R(IDE_BADFORMAT) );
01625     return FALSE;
01626 #else
01627     ERROR2IF(File==NULL,FALSE,"DIBUtil::WriteToFile File pointer is null");
01628     ERROR2IF(Info==NULL,FALSE,"DIBUtil::WriteToFile BitmapInfo pointer is null");
01629     ERROR2IF(Bits==NULL,FALSE,"DIBUtil::WriteToFile Bits pointer is null");
01630 
01631     // Must set the exception throwing flag to True and force reporting of errors to False.
01632     // This means that the caller must report an error if the function returns False.
01633     // Any calls to CCFile::GotError will now throw a file exception and should fall into
01634     // the catch handler at the end of the function.
01635     // Replaces the goto's that handled this before.
01636     BOOL OldThrowingState = File->SetThrowExceptions( TRUE );
01637     BOOL OldReportingState = File->SetReportErrors( FALSE );
01638 
01639     // If the caller has specified a string then assume they require a progress bar
01640     // Start it up.
01641     if (ProgressString != NULL)
01642     {
01643         BeginSlowJob(100, FALSE, ProgressString);
01644     }
01645 
01646     try
01647     {
01648         // BITMAPINFO  consists of:-
01649         //      BITMAPINFOHEADER    bmiHeader;
01650         //      RGBQUAD             bmiColors[1];
01651         LPBITMAPINFOHEADER pInfoHeader = &Info->bmiHeader;
01652         ERROR2IF(pInfoHeader==NULL,FALSE,"DIBUtil::WriteToFile BitmapInfoHeader pointer is null");
01653         
01654         // Work out the palette size 
01655         INT32 PalSize = Info->bmiHeader.biClrUsed;      // How many entries in palette
01656 TRACEUSER( "Neville", _T("DIBUtil::WriteToFile PalSize = %d\n"),PalSize);
01657 TRACEUSER( "Neville", _T("DIBUtil::WriteToFile XPelsPerMeter=%d\n"),pInfoHeader->biXPelsPerMeter);
01658 TRACEUSER( "Neville", _T("DIBUtil::WriteToFile YPelsPerMeter=%d\n"),pInfoHeader->biYPelsPerMeter);
01659 
01660         if (WriteHeader)
01661         {
01662             // BITMAPFILEHEADER goes first
01663             BITMAPFILEHEADER Header;
01664 
01665             Header.bfType = ('M'<<8) | 'B';
01666             Header.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
01667                             sizeof(RGBQUAD)*PalSize + pInfoHeader->biSizeImage;
01668             Header.bfReserved1 = 0;
01669             Header.bfReserved2 = 0;
01670             Header.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
01671                                 sizeof(RGBQUAD)*PalSize;
01672 
01673             // Write that headerout ot the file
01674             File->write( &Header, sizeof(Header) );
01675         }
01676 
01677         // then a local BITMAPINFOHEADER
01678 
01679         File->write( pInfoHeader, sizeof(BITMAPINFOHEADER) );
01680 
01681         // then the RGBQUAD palette, if there is one
01682         if (PalSize)
01683         {
01684             // Work out the size of the palette that we should be saving
01685             const UINT32 TotalPal = sizeof(PALETTEENTRY) * PalSize;
01686             File->write( Info->bmiColors, TotalPal );
01687         }
01688 
01689         // Now write out the bitmap data itself.
01690         DWORD BitsSize = pInfoHeader->biSizeImage; 
01691 
01692         // Write the actual bytes out to file. Used to do it in one go but we really
01693         // require some progress bar indication so we will do it in chunks.
01694         if (BitsSize > 0)
01695         {
01696             // If pFilter is NULL and hence not native/web loading then do it in 
01697             // chunks of bytes
01698             if (pFilter == NULL)
01699             {
01700                 if (BitsSize < 1024 || ProgressString == NULL)
01701                 {
01702                     // File very small or no progress bar required, so load in one go
01703                     File->write( Bits, BitsSize);
01704                 }
01705                 else
01706                 {
01707                     // Load in chunks, for present split into 100 chunks
01708                     DWORD ChunkSize = BitsSize/100;
01709                     DWORD Position = 0;
01710                     LPBYTE pBitInfo = Bits;
01711                     
01712                     while (Position < BitsSize)
01713                     {
01714                         if ( (BitsSize - Position) > ChunkSize)
01715                             File->write( pBitInfo, ChunkSize);
01716                         else
01717                         {
01718                             ChunkSize = BitsSize - Position;
01719                             File->write( pBitInfo, ChunkSize);
01720                         }
01721                                 
01722                         // Increment our counters/pointers
01723                         Position += ChunkSize;
01724                         pBitInfo += ChunkSize;
01725                         ContinueSlowJob((INT32)(100*Position/BitsSize));
01726                     }
01727                 }
01728             }
01729             else
01730             {
01731                 // Do the reading a scanline at a time
01732                 // This makes progress bar update easier for native/web files
01733                 LPBYTE pBitInfo = Bits;
01734                 UINT32 ScanLineWidth = DIBUtil::ScanlineSize(pInfoHeader->biWidth, pInfoHeader->biBitCount);
01735                 UINT32 height = pInfoHeader->biHeight; 
01736                 // For each scaline in the file, read it in and update the progress bar count
01737                 for (UINT32 i = 0; i < height; i++)
01738                 {
01739                     File->write( pBitInfo, ScanLineWidth );
01740                     pBitInfo += ScanLineWidth;
01741                     pFilter->IncProgressBarCount(1);
01742                 }
01743             }
01744         }
01745 
01746         // If started, then stop then progress bar
01747         if (ProgressString != NULL)
01748         {
01749             EndSlowJob();
01750         }
01751 
01752         // Must set the exception throwing and reporting flags back to their entry states
01753         File->SetThrowExceptions( OldThrowingState );
01754         File->SetReportErrors( OldReportingState );
01755 
01756         // er, we seem to have finished OK so say so
01757         return TRUE;
01758     }
01759     catch( CFileException )
01760     {
01761         // catch our form of a file exception
01762         TRACE( _T("DIBUtil::WriteToFile CC catch handler\n"));
01763 
01764         // If started, then stop then progress bar
01765         if (ProgressString != NULL)
01766         {
01767             EndSlowJob();
01768         }
01769 
01770         // Must set the exception throwing and reporting flags back to their entry states
01771         File->SetThrowExceptions( OldThrowingState );
01772         File->SetReportErrors( OldReportingState );
01773 
01774         return FALSE;
01775     }
01776 
01777     ERROR2( FALSE, "Escaped exception clause somehow" );
01778 
01779 #endif
01780 }
01781 
01782 
01783 
01784 /********************************************************************************************
01785 >   static BOOL DIBUtil::WriteToFile ( CCLexFile *, LPBYTE Bits, String_64 *ProgressString = NULL, UINT32 Width, UINT32 Height, UINT32 Depth)
01786 
01787     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01788     Created:    6/4/96
01789     Inputs:     File    An opened CCFile that can be written to. It should be positioned at the
01790                         start. Caller is responsible for closing it. The file needs to be in
01791                         Binary mode.
01792                 Bits    The bitmap data itself
01793                 ProgressString allows the user to specify whether they require a progress
01794                         hourglass or not. If NULL then none is shown, otherwise an progress bar 
01795                         is shown using the text supplied. Defaults to NULL i.e. no progress bar.
01796                 Width   The width of the bitmap data in pixels
01797                 Height  The height of the bitmap data in pixels
01798                 Depth   The depth of the bitmap (Only 1 is supported at the mo)
01799     Outputs:    -
01800     Returns:    TRUE if worked, FALSE if failed (error will be set accordingly but not reported)
01801     Purpose:    Generates a BITMAPINFO structor and then saves out the DIB
01802 ********************************************************************************************/
01803 BOOL DIBUtil::WriteToFile ( CCLexFile* pFile, LPBYTE pBits, UINT32 Width, UINT32 Height, UINT32 Depth, String_64 *pProgressString)
01804 {
01805     ERROR3IF(Depth!=1, "Only 1bpp DIBs supported");
01806     ERROR3IF(Width==0, "Zero width");
01807     ERROR3IF(Height==0, "Zero height");
01808     
01809     // Create a new info
01810     const INT32 NumColours = 1 << Depth;
01811     BITMAPINFO* pBmpInfo = (BITMAPINFO*) CCMalloc (sizeof(BITMAPINFO) + sizeof(RGBQUAD)*NumColours);
01812     if (pBmpInfo == NULL)
01813         return FALSE;
01814 
01815     // Fill in the bitmap info
01816     pBmpInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
01817     pBmpInfo->bmiHeader.biWidth = Width;
01818     pBmpInfo->bmiHeader.biHeight = Height;
01819     pBmpInfo->bmiHeader.biPlanes = 1;
01820     pBmpInfo->bmiHeader.biBitCount = Depth;
01821     pBmpInfo->bmiHeader.biCompression = BI_RGB;
01822     pBmpInfo->bmiHeader.biXPelsPerMeter = 0;
01823     pBmpInfo->bmiHeader.biYPelsPerMeter = 0;
01824     pBmpInfo->bmiHeader.biClrImportant = 0;
01825 
01826     // It is these fields at are dependant on the 1bpp ness
01827     pBmpInfo->bmiHeader.biClrUsed = 2;
01828     pBmpInfo->bmiHeader.biSizeImage = Height*(((Width+31)/32)*4);   // Scanlines are word-aligned
01829 
01830     // Generate a black and white palette
01831     pBmpInfo->bmiColors[0].rgbRed = 0x00;   
01832     pBmpInfo->bmiColors[0].rgbGreen = 0x00; 
01833     pBmpInfo->bmiColors[0].rgbBlue = 0x00;  
01834     pBmpInfo->bmiColors[0].rgbReserved = 0;
01835     pBmpInfo->bmiColors[1].rgbRed = 0xff;   
01836     pBmpInfo->bmiColors[1].rgbGreen = 0xff; 
01837     pBmpInfo->bmiColors[1].rgbBlue = 0xff;  
01838     pBmpInfo->bmiColors[1].rgbReserved = 0;
01839 
01840     // Call saving code
01841     BOOL result = DIBUtil::WriteToFile ( pFile, pBmpInfo, pBits, pProgressString );
01842 
01843     CCFree(pBmpInfo);
01844         
01845     return result;
01846 }
01847 
01848 
01849 
01850 // 1 to export as 32-bit DIBs, 0 as 24-bit ones (which are more normal)
01851 #define WRITE_32BIT 0
01852 
01853 
01854 // this function taken from the WinG Help file, except takes a pointer to a PALETTEENTRY
01855 
01856 HPALETTE CreateIdentityPalette( PALETTEENTRY aRGB[], INT32 nColors )
01857 {
01858     PORTNOTETRACE("other","CreateIdentityPalette - do nothing - no palette support anymore");
01859 #ifndef EXCLUDE_FROM_XARALX
01860     INT32 i;
01861     struct {
01862         WORD Version;
01863         WORD NumberOfEntries;
01864         PALETTEENTRY aEntries[256];
01865     } Palette =
01866     {
01867         0x300,
01868         256
01869     };
01870 
01871     //*** Just use the screen DC where we need it
01872     wxScreenDC          dc;
01873 
01874     //*** For SYSPAL_NOSTATIC, just copy the color table into
01875     //*** a PALETTEENTRY array and replace the first and last entries
01876     //*** with black and white
01877     if (GetSystemPaletteUse(hdc) == SYSPAL_NOSTATIC)
01878 
01879     {
01880         //*** Fill in the palette with the given values, marking each
01881         //*** as PC_NOCOLLAPSE
01882         for(i = 0; i < nColors; i++)
01883         {
01884             Palette.aEntries[i].peRed = aRGB[i].peRed;
01885             Palette.aEntries[i].peGreen = aRGB[i].peGreen;
01886             Palette.aEntries[i].peBlue = aRGB[i].peBlue;
01887 //          Palette.aEntries[i].peFlags = PC_NOCOLLAPSE;
01888             Palette.aEntries[i].peFlags = 0;
01889         }
01890 
01891         //*** Mark any unused entries PC_NOCOLLAPSE
01892         for (; i < 256; ++i)
01893         {
01894 //          Palette.aEntries[i].peFlags = PC_NOCOLLAPSE;
01895             Palette.aEntries[i].peFlags = 0;
01896         }
01897 
01898         //*** Make sure the last entry is white
01899         //*** This may replace an entry in the array!
01900         Palette.aEntries[255].peRed = 255;
01901         Palette.aEntries[255].peGreen = 255;
01902         Palette.aEntries[255].peBlue = 255;
01903         Palette.aEntries[255].peFlags = 0;
01904 
01905         //*** And the first is black
01906         //*** This may replace an entry in the array!
01907         Palette.aEntries[0].peRed = 0;
01908         Palette.aEntries[0].peGreen = 0;
01909         Palette.aEntries[0].peBlue = 0;
01910         Palette.aEntries[0].peFlags = 0;
01911 
01912     }
01913     else
01914     //*** For SYSPAL_STATIC, get the twenty static colors into
01915     //*** the array, then fill in the empty spaces with the
01916     //*** given color table
01917     {
01918         INT32 nStaticColors;
01919         INT32 nUsableColors;
01920 
01921         //*** Get the static colors from the system palette
01922         nStaticColors = GetDeviceCaps(hdc, NUMCOLORS);
01923         GetSystemPaletteEntries(hdc, 0, 256, Palette.aEntries);
01924 
01925         //*** Set the peFlags of the lower static colors to zero
01926         nStaticColors = nStaticColors / 2;
01927 
01928         for (i=0; i<nStaticColors; i++)
01929             Palette.aEntries[i].peFlags = 0;
01930 
01931         //*** Fill in the entries from the given color table
01932         nUsableColors = nColors - nStaticColors;
01933         for (; i<nUsableColors; i++)
01934         {
01935             Palette.aEntries[i].peRed = aRGB[i].peRed;
01936             Palette.aEntries[i].peGreen = aRGB[i].peGreen;
01937             Palette.aEntries[i].peBlue = aRGB[i].peBlue;
01938 //          Palette.aEntries[i].peFlags = PC_NOCOLLAPSE;
01939             Palette.aEntries[i].peFlags = 0;
01940         }
01941 
01942         //*** Mark any empty entries as PC_NOCOLLAPSE
01943 
01944         for (; i<256 - nStaticColors; i++)
01945 //          Palette.aEntries[i].peFlags = PC_NOCOLLAPSE;
01946             Palette.aEntries[i].peFlags = 0;
01947 
01948         //*** Set the peFlags of the upper static colors to zero
01949         for (i = 256 - nStaticColors; i<256; i++)
01950             Palette.aEntries[i].peFlags = 0;
01951     }
01952 
01953     //*** Return the palette
01954     return CreatePalette((LOGPALETTE *)&Palette);
01955 #else
01956     return NULL;
01957 #endif
01958 }
01959 
01960 // this function taken from the WinG Help file
01961 
01962 void ClearSystemPalette(void)
01963 {
01964     // This isn't particularly friendly to other palette using apps
01965     // so we'll remove it from Ralph...
01966 #if !defined(EXCLUDE_FROM_RALPH) && !defined(EXCLUDE_FROM_XARALX)
01967 
01968     //*** A dummy palette setup
01969     struct
01970     {
01971         WORD Version;
01972         WORD NumberOfEntries;
01973         PALETTEENTRY aEntries[256];
01974     } Palette =
01975     {
01976         0x300,
01977         256
01978     };
01979 
01980     HPALETTE ScreenPalette = 0;
01981     HDC ScreenDC;
01982     INT32 Counter;
01983 
01984     //*** Reset everything in the system palette to black
01985     for(Counter = 0; Counter < 256; Counter++)
01986     {
01987         Palette.aEntries[Counter].peRed = 0;
01988         Palette.aEntries[Counter].peGreen = 0;
01989         Palette.aEntries[Counter].peBlue = 0;
01990 
01991 
01992         Palette.aEntries[Counter].peFlags = PC_NOCOLLAPSE;
01993     }
01994 
01995     //*** Create, select, realize, deselect, and delete the palette
01996     ScreenDC = GetDC(NULL);
01997     ScreenPalette = CreatePalette((LOGPALETTE *)&Palette);
01998     if (ScreenPalette)
01999     {
02000         ScreenPalette = SelectPalette(ScreenDC,ScreenPalette,FALSE);
02001         RealizePalette(ScreenDC);
02002         ScreenPalette = SelectPalette(ScreenDC,ScreenPalette,FALSE);
02003         DeleteObject(ScreenPalette);
02004     }
02005     ReleaseDC(NULL, ScreenDC);
02006 #endif // EXCLUDE_FROM_RALPH, EXCLUDE_FROM_XARALX
02007 }
02008 
02009 HPALETTE DIBUtil::MakeIdentityPalette(PALETTEENTRY aRGB[], INT32 nColors)
02010 {
02011     ClearSystemPalette();
02012     return CreateIdentityPalette( aRGB, nColors );
02013 }
02014 
02015 
02016 
02017 /********************************************************************************************
02018 
02019 >   static BitmapConvertHint DIBUtil::CalcConvertHint( DWORD ScreenBPP, HDC hDC )
02020 
02021     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> (Rewrote Andy's original function)
02022     Created:    4/7/95 (21/2/95)
02023     Inputs:     ScreenBPP - Indicates the output BPP for which the hint is required
02024                 hDC - should be a device that supports SetPixel. (May be NULL if ScreenBPP
02025                 is less than 16)
02026 
02027     Returns:    Suitable value for hinting in bitmap conversions.
02028                 (CONVHINT_SCREEN4 or _SCREEN8, or any of the 16 or 24 bit CONVHINT_FINAL? values)
02029 
02030     Purpose:    Determines RGB arrangements for 15/16-bit devices which is needed during
02031                 dithering in those modes. User is responsible for preserving the state of
02032                 the pixel at 0,0 if required. Returns CONVHINT_NONE if an error occurs.
02033 
02034     SeeAlso:    BitmapConvertHint; DIBUtil::GetGavinBlitFormat
02035 
02036 ********************************************************************************************/
02037 
02038 BitmapConvertHint DIBUtil::CalcConvertHint( DWORD ScreenBPP, wxDC *pDC )
02039 {
02040     switch(ScreenBPP)
02041     {
02042         case 4:
02043             return(CONVHINT_SCREEN4);
02044 
02045         case 8:
02046             return(CONVHINT_SCREEN8);
02047 
02048         case 16:
02049         case 24:
02050         case 32:
02051             // Drop through to the code below to determine a proper 16/24bpp hint
02052             // (Note: Some cards say they are 24bpp when in fact they're 16bpp, so we must
02053             // do this for both values)
02054             break;
02055 
02056         default:
02057             ERROR2(CONVHINT_NONE, "Unknown output screen BPP");
02058     }
02059 
02060     // Writes all 256 values to each gun, and counts the number of different values which are 
02061     // returned - i.e. a 5 bit gun cannot return more than 32 values
02062     BYTE LastValue[3] = {0, 0, 0};
02063     BYTE     Count[3] = {0, 0, 0};
02064     wxMemoryDC  memdc;
02065     wxBitmap    bitmap( 1, 1 );
02066     memdc.SelectObject( bitmap );
02067     for ( UINT32 Value=0x00; Value<0x100; Value++ )
02068     {
02069         wxColour colour;
02070         memdc.SetPen(wxPen(wxColour(Value,Value,Value)));
02071         memdc.DrawPoint(0,0);
02072         memdc.GetPixel(0,0,&colour);
02073         if ( colour.Red()!=LastValue[0] )
02074         {
02075             LastValue[0] = colour.Red();
02076             Count[0]++;
02077         }
02078         if ( colour.Green()!=LastValue[1] )
02079         {
02080             LastValue[1] = colour.Green();
02081             Count[1]++;
02082         }
02083         if ( colour.Blue()!=LastValue[2] )
02084         {
02085             LastValue[2] = colour.Blue();
02086             Count[2]++;
02087         }
02088     }
02089     memdc.SelectObject( wxNullBitmap );
02090 
02091     // Now determine how many bits would be needed to store the number of values we generated
02092     // for each gun. Note that this code will return (eg) 5 bits for all values between 17-32 inclusive
02093     for (INT32 Gun = 0; Gun < 3; Gun++)
02094     {
02095         INT32 BitPos = 0;
02096         while (Count[Gun] > 0)
02097         {
02098             BitPos++;
02099             Count[Gun] /= 2;
02100         }
02101         Count[Gun] = BitPos;
02102     }
02103 
02104     TRACEALL( wxT("16bpp RGB gun configuration auto-detected as %ld.%ld.%ld\n"),
02105                 Count[0], Count[1], Count[2]);
02106 
02107     // OK. Now determine the enum constant which represents this configuration (if any)
02108     switch(Count[0])
02109     {
02110         case 5:
02111             if (Count[2] == 5)
02112             {
02113                 if (Count[1] == 5)
02114                     return(CONVHINT_FINAL555);
02115                 
02116                 if (Count[1] == 6)
02117                     return(CONVHINT_FINAL565);
02118             }
02119             break;
02120 
02121         case 6:
02122             if (Count[1] == 5 && Count[2] == 5)
02123                 return(CONVHINT_FINAL655);
02124 
02125             if (Count[1] == 6 && Count[2] == 4)
02126                 return(CONVHINT_FINAL664);
02127             break;
02128 
02129         case 8:
02130             if (Count[1] == 8 && Count[2] == 8)
02131                 return(CONVHINT_FINAL24);
02132             break;
02133     }
02134 
02135     // Nope. It's an unknown signature. We'll just have to try 555 and hope for the best
02136     TRACEALL( wxT("Unknown 16bpp RGB gun configuration (%ld.%ld.%ld). Defaulting to CONVHINT_NONE\n"),
02137                 Count[0], Count[1], Count[2]);
02138     return(CONVHINT_NONE);
02139 }
02140 
02141 
02142 /********************************************************************************************
02143 
02144 >   static DWORD DIBUtil::GetGavinBlitFormat(DWORD ScreenBPP, DWORD BitmapBPP,
02145                                                 BitmapConvertHint ScreenHint)
02146 
02147 
02148     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02149     Created:    4/7/95
02150 
02151     Inputs:     ScreenBPP -     The depth of the screen/bitmap we'll be plotting to
02152                 BitmapBPP -     The depth of the Gavin bitmap we're plotting to
02153                 ScreenHint -    The conversion hint as returned by DIBUtil::CalcConvertHint
02154 
02155     Returns:    An approprite hinting value for use. This will default to 2 (555 hint) if a
02156                 better hint can't be found.
02157 
02158     Purpose:    Determines, from the given inputs, what number should be passed to Gavin
02159                 routines SetSolidColour and SetUpBitmap (the BPP and BitmapFormat params)
02160                 in order to get the best possible result (and/or to ensure no dithering
02161                 occurs). Generally, this is only needed in 16bpp screen modes, but may
02162                 be called at any time, as it returns safe defaults if not in 16bpp.
02163 
02164 ********************************************************************************************/
02165 
02166 DWORD DIBUtil::GetGavinBlitFormat(DWORD ScreenBPP, DWORD BitmapBPP, BitmapConvertHint ScreenHint)
02167 {
02168     BOOL Transparent = (BitmapBPP == 32);
02169 
02170     if (Transparent)
02171     {
02172         // Otherwise, we use the ConvertHint value to determine a suitable Gavin Format value
02173         switch (ScreenHint)
02174         {
02175             case CONVHINT_FINAL565:
02176                 return(0);
02177 
02178             case CONVHINT_FINAL655:
02179                 return(1);
02180 
02181             case CONVHINT_FINAL555:
02182             case CONVHINT_FINAL16:      // Unknown 16 bit mode - default to 555 hint
02183                 return(2);
02184 
02185             case CONVHINT_FINAL664:
02186                 return(3);
02187 
02188             case CONVHINT_SCREEN4:
02189             case CONVHINT_SCREEN8:
02190             case CONVHINT_FINAL24:
02191             case CONVHINT_NONE:
02192             default:
02193                 // Drop through to the default return value (2)
02194                 break;
02195         }
02196     }
02197 
02198     return(2);
02199 }
02200 
02201 
02202 
02203 /********************************************************************************************
02204 
02205 >   static BOOL DIBUtil::MakeTransparentBitmap ( LPBITMAPINFO   pPseudoColourInfo,
02206                                                  LPBYTE         pPseudoColourBits,
02207                                                  LPBITMAPINFO   pMonochromeInfo,
02208                                                  LPBYTE         pMonochromeBits,
02209                                                  const BYTE     TransColour )
02210 
02211     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> (from Alex code)
02212     Created:    22/5/96
02213     Inputs:     pPseudoColourInfo   The info header for the image we're applying the mask to.
02214                 pPseudoColourBits   The bits for the image we want to apply the mask to.
02215                 pMonochromeInfo     The info header for the mask image.
02216                 pMonochromeBits     The bits for the image mask.
02217                 TransColour         The index of the transparent colour.
02218     Returns:    TRUE/FALSE for success/failure.
02219     Purpose:    Applies the monochrome bitmap as a mask to a bitmap, setting pixels in the
02220                 to the image to the TransColour if the equivelent pixel in the mask is not
02221                 set.
02222     SeeAlso:    -
02223     Scope:      Static
02224 
02225 ********************************************************************************************/
02226 
02227 BOOL DIBUtil::MakeTransparentBitmap ( LPBITMAPINFO  pPseudoColourInfo,
02228                                       LPBYTE        pPseudoColourBits,
02229                                       LPBITMAPINFO  pMonochromeInfo,
02230                                       LPBYTE        pMonochromeBits,
02231                                       const BYTE    TransColour )
02232 {
02233     // Get the number of transparent colours used from the bitmap preview dialogue.
02234 PORTNOTE("dialog","Removed BmapPrevDlg usage")
02235 #ifndef EXCLUDE_FROM_XARALX
02236     INT32 NumberOfTransparentColours = BmapPrevDlg::GetNumberOfTransparentColours();
02237 #endif
02238     // Do we want to make the background transparent?
02239     BOOL bHaveBackground = FALSE;
02240 
02241     // If there is a transparent colour, then set the flag to indicate that there's
02242     // a transparent background used.
02243 PORTNOTE("dialog","Removed BmapPrevDlg usage")
02244 #ifndef EXCLUDE_FROM_XARALX
02245     for ( INT32 j=0; j < NumberOfTransparentColours; j++ )
02246     {
02247         if ( BmapPrevDlg::GetTransparentColour ( j ) == TransColour )
02248         {
02249             bHaveBackground = TRUE;
02250             break;
02251         }
02252     }
02253 #endif
02254 
02255     // Parameter checks
02256     ERROR2IF ( pPseudoColourInfo == NULL || pPseudoColourBits == NULL, FALSE,
02257                "DIBUtil::MakeTransparentBitmap missing psuedo colour bitmap" );
02258     ERROR2IF ( pMonochromeInfo   == NULL || pMonochromeBits   == NULL, FALSE,
02259                "DIBUtil::MakeTransparentBitmap missing monochrome bitmap" );
02260     
02261     BITMAPINFOHEADER* pImageBMI = &( pPseudoColourInfo->bmiHeader );
02262     BITMAPINFOHEADER* pMaskBMI  = &( pMonochromeInfo->bmiHeader );
02263 
02264     ERROR2IF ( pMaskBMI->biBitCount != 1, FALSE,
02265                "DIBUtil::MakeTransparentBitmap Monochrome not 1BPP");
02266     ERROR2IF ( ( pImageBMI->biWidth != pMaskBMI->biWidth ) ||
02267                ( pImageBMI->biHeight != pMaskBMI->biHeight ), FALSE,
02268                "DIBUtil::MakeTransparentBitmap hasn't been passed identical bitmaps." );
02269     
02270     BYTE* pImagePixel   = pPseudoColourBits;
02271     BYTE* pMaskPixel    = pMonochromeBits;
02272 
02273     switch (pImageBMI->biBitCount)
02274     {
02275     case 8:
02276         {
02277             // Pixels in the image are one per byte
02278             for (INT32 y = 0; y < pImageBMI->biHeight; y++)
02279             {
02280                 // The monochrome bitmap uses one bit per pixel to store the mask data,
02281                 // and bbit is used to extract the bit representing the current pixel.
02282                 INT32 bbit = 7;
02283 
02284                 for (INT32 x = 0; x < pImageBMI->biWidth; x++)
02285                 {
02286                     // If the mask contains a bit corresponding to the current pixel,
02287                     // the mask is set for this point, so set the current colour to
02288                     // match the transparent colour.
02289                     if( bHaveBackground && ( ( *pMaskPixel ) & ( 1 << bbit ) ) )
02290                     {
02291                         *pImagePixel = TransColour;
02292                     }
02293 
02294                     // Otherwise compare the pixel to the transparent colours. If
02295                     // they're the same then replace the colour's index with the
02296                     // transparency index.
02297                     else
02298                     {
02299 PORTNOTE("dialog","Removed BmapPrevDlg usage")
02300 #ifndef EXCLUDE_FROM_XARALX
02301                         for ( INT32 i=0; i < NumberOfTransparentColours; i++ )
02302                         {
02303                             if ( *pImagePixel == BmapPrevDlg::GetTransparentColour ( i ) )
02304                             {
02305                                 *pImagePixel = TransColour;
02306 
02307                                 // Finished looking for this pixel.
02308                                 break;
02309                             }
02310                         }
02311 #endif
02312                     }
02313 
02314                     // Increment the image pointer.
02315                     pImagePixel++;
02316 
02317                     // Increment the mask pointer.
02318                     if (!(bbit--))
02319                     {
02320                         pMaskPixel++;
02321                         bbit = 7;
02322                     }
02323                 }
02324 
02325                 // Each scanline is word-aligned so adjust the pointers.
02326                 pImagePixel = reinterpret_cast<LPBYTE> ( ( reinterpret_cast<DWORD_PTR>
02327                               ( pImagePixel ) + 3 ) & ~3 );
02328                 pMaskPixel  = reinterpret_cast<LPBYTE> ( ( reinterpret_cast<DWORD_PTR>
02329                               ( pMaskPixel ) + ( ( bbit==7 ) ? 3 : 4 ) ) & ~3 );
02330             }
02331         }
02332 
02333         ERROR3IF ( static_cast<DWORD> ( pImagePixel - pPseudoColourBits )
02334                    != pImageBMI->biSizeImage,
02335                    "Missed image pixels");
02336 
02337         break;
02338 
02339     case 4 :
02340         {
02341             // Pixels in the image are two per byte
02342             ERROR3IF(TransColour > 15, "Trans Colour was out of the 4bpp range");
02343             const BYTE RealTransColour = min( TransColour, BYTE(15) );
02344             const INT32 ScanlineWidth = DIBUtil::ScanlineSize(pImageBMI->biWidth, 4);
02345 
02346             for (INT32 y = 0; y < pImageBMI->biHeight; y++)
02347             {
02348                 INT32 bbit = 7;
02349                 BYTE* ScanLineStart = pImagePixel;
02350                 for (INT32 x = 0; x < pImageBMI->biWidth; x++)
02351                 {
02352                     // pixel is in either lower or upper nibble
02353                     BYTE UpperNibble = (*pImagePixel) >> 4;
02354                     BYTE LowerNibble = (*pImagePixel) & 0xF;
02355 //                  BYTE Pixel = (x%2 == 0) ? UpperNibble : LowerNibble;
02356                     if ((*pMaskPixel) & (1<<bbit))
02357                     {
02358                         if (x%2 == 0)
02359                             *pImagePixel = (RealTransColour << 4) | LowerNibble;
02360                         else
02361                             *pImagePixel = (UpperNibble << 4) | RealTransColour;
02362                     }
02363                     
02364 PORTNOTE("dialog","Removed BmapPrevDlg usage")
02365 #ifndef EXCLUDE_FROM_XARALX
02366                     for( INT32 i=0; i < NumberOfTransparentColours; i++ )
02367                     {
02368                         //  Go through all the transparent colours. If the bitmap is using one
02369                         //  of these colours, then change its value to the transparent colour.
02370                         if( Pixel == BmapPrevDlg::GetTransparentColour( i ) )
02371                         {
02372                             if (x%2 == 0)
02373                                 *pImagePixel = (RealTransColour << 4) | LowerNibble;
02374                             else
02375                                 *pImagePixel = (UpperNibble << 4) | RealTransColour;
02376                             //  Finished looking for this pixel.
02377                             i = NumberOfTransparentColours;
02378                         } 
02379                     }
02380 #endif
02381 
02382                     if (x%2==1)
02383                         pImagePixel++;
02384 
02385                     if (!(bbit--))
02386                     {
02387                         pMaskPixel++;
02388                         bbit = 7;
02389                     }
02390                 }
02391                 // Each scanline is word-aligned so adjust the pointers
02392                 pImagePixel = ScanLineStart+ScanlineWidth;
02393                 pMaskPixel = LPBYTE( ( (DWORD_PTR(pMaskPixel)) + ( ( bbit == 7 ) ? 3 : 4 ) ) & ~ 3 );
02394             }
02395         }
02396 
02397         ERROR3IF ( static_cast<DWORD> ( pImagePixel - pPseudoColourBits )
02398                    != pImageBMI->biSizeImage,
02399                    "Missed image pixels");
02400 
02401         break;
02402 
02403     case 1 :
02404         {
02405             const INT32 MonoScanlineWidth = DIBUtil::ScanlineSize ( pImageBMI->biWidth, 1 );
02406 
02407             // One pixel = one bit so we can apply the mask via bitwise operations
02408             for (INT32 loop = 0; loop < MonoScanlineWidth*pImageBMI->biHeight; loop++)
02409             {
02410                 //  Go through all the transparent colours. If the bitmap is using one
02411                 //  of these colours, then change its value to the transparent colour.
02412                 
02413 PORTNOTE("dialog","Removed BmapPrevDlg usage")
02414 #ifndef EXCLUDE_FROM_XARALX
02415                 if( NumberOfTransparentColours == 2 )
02416                 {
02417                     pPseudoColourBits[loop] = 0;
02418                 }
02419                 else if( NumberOfTransparentColours == 1 )
02420                 {
02421                     if( BmapPrevDlg::m_bIsOrderedDither )
02422                     {
02423                         if( BmapPrevDlg::GetTransparentColour( 0 ) == 1 )
02424                         {
02425                             pPseudoColourBits[loop] = pPseudoColourBits[loop];
02426                         }
02427                         else //  Colour #1 is the transparent one.
02428                         {
02429                             if( pPseudoColourBits[loop] > 0 )
02430                                 pPseudoColourBits[loop] = 255 - pPseudoColourBits[loop];
02431                             else
02432                                 pPseudoColourBits[loop] = 255;
02433                         }
02434                     }
02435                     else
02436                     {
02437                         if( BmapPrevDlg::GetTransparentColour( 0 ) == 0 )
02438                         {
02439                             pPseudoColourBits[loop] = pPseudoColourBits[loop];
02440                         }
02441                         else //  Colour #1 is the transparent one.
02442                         {
02443                             if( pPseudoColourBits[loop] > 0 )
02444                                 pPseudoColourBits[loop] = 255 - pPseudoColourBits[loop];
02445                             else
02446                                 pPseudoColourBits[loop] = 255;
02447                         }
02448                     }
02449                 }
02450 #endif
02451             }
02452         }
02453 
02454         break;
02455 
02456     default:
02457         ERROR2(FALSE, "DIBUtil::MakeTransparentBitmap PseudoColour bitmap not 8/4/1 BPP");
02458     }
02459 
02460     return TRUE;
02461 }
02462 
02463 
02464 
02465 /********************************************************************************************
02466 
02467 >   static BOOL DIBUtil::MakeBitmapMask(LPBITMAPINFO pPseudoColourInfo, LPBYTE pPseudoColourBits,
02468                                         LPBITMAPINFO pMonochromeInfo, LPBYTE pMonochromeBits)
02469 
02470     Author:     Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com>
02471     Created:    25/4/95
02472     Inputs:     pPseudoColourInfo   the info header for the image with transparent colour in
02473                 pPseudoColourBits   the bits for the image with transparent col in
02474                 pMonochromeColourInfo   the info header for the image to make into the mask
02475                 pMonochromeColourBits   the bits for the image to make into the mask
02476                 Transparency        the oclour to use for transparent
02477     Returns:    True if converted it ok.
02478     Purpose:    Makes the monochrome bitmap (created with) into a mask for displaying the
02479                 Pseudocolour bitmap.
02480                 The mask must be 8bpp instead of the implied of 1bpp as applying it as a
02481                 transparency requires this.
02482     SeeAlso:    -
02483     Scope:      Static
02484 
02485 ********************************************************************************************/
02486 
02487 BOOL DIBUtil::MakeBitmapMask(LPBITMAPINFO pPseudoColourInfo, LPBYTE pPseudoColourBits,
02488                              LPBITMAPINFO pMonochromeInfo, LPBYTE pMonochromeBits,
02489                              const BYTE TransCol)
02490 {
02491     //const BYTE TransCol = GIF_TRANS_COLOUR;
02492 
02493     ERROR2IF(pPseudoColourInfo==NULL || pPseudoColourBits==NULL, FALSE, "DIBUtil::MakeBitmapMask missing psuedo colour bitmap");
02494     ERROR2IF(pMonochromeInfo==NULL || pMonochromeBits==NULL, FALSE, "DIBUtil::MakeBitmapMask missing monochrome bitmap");
02495     
02496     BITMAPINFOHEADER * pABMI=&(pPseudoColourInfo->bmiHeader);
02497     BITMAPINFOHEADER * pBBMI=&(pMonochromeInfo->bmiHeader);
02498     LPBYTE pABytes=pPseudoColourBits;
02499     LPBYTE pBBytes=pMonochromeBits;
02500 
02501     ERROR2IF(pABMI->biBitCount != 8, FALSE, "DIBUtil::MakeBitmapMask PseudoColour bitmap not 8BPP");
02502     ERROR2IF(pBBMI->biBitCount != 8, FALSE, "DIBUtil::MakeBitmapMask Monochrome not 8BPP");
02503     ERROR2IF((pABMI->biWidth != pBBMI->biWidth) || (pABMI->biHeight != pBBMI->biHeight), FALSE,
02504                 "DIBUtil::MakeBitmapMask needs identically sized bitmaps and that's not what you've given it.");
02505     
02506     LPBYTE A=pABytes;
02507     LPBYTE B=pBBytes;
02508     //
02509     // Gavin: I've not tested the following code change, so if there are problems,
02510     // revert to the old code.
02511     //
02512 #if 1
02513     for (INT32 y = 0; y < pABMI->biHeight; y++)
02514     {
02515         for (INT32 x = 0; x < pABMI->biWidth; x++)
02516             B[x] = -(A[x]==TransCol) ;
02517         A += pABMI->biWidth ;
02518         B += pABMI->biWidth ;
02519         A = (LPBYTE)( (((DWORD_PTR)(A))+3) & ~ 3); // word align
02520         B = (LPBYTE)( (((DWORD_PTR)(B))+3) & ~ 3); // word align
02521     }
02522 #else
02523     memset(B, 0, pBBMI->biSizeImage); // blank the mask
02524     
02525     for (INT32 y = 0; y < pABMI->biHeight; y++)
02526     {
02527         //INT32 bbit = 7;
02528         for (INT32 x = 0; x < pABMI->biWidth; x++)
02529         {
02530             // Change == to != if the mask comes out the wrong way around.
02531             if ((*(A++))==TransCol)
02532                 (*B) = 0xFF;
02533 
02534             // Monochrome mask code
02535             //  (*B)|=1<<bbit;
02536             //if (!(bbit--))
02537             //{
02538             //  B++;
02539             //  bbit=7;
02540             //}
02541             B++;
02542         }
02543         A=(LPBYTE)( (((DWORD)(A))+3) & ~ 3); // word align
02544         B=(LPBYTE)( (((DWORD)(B))+3) & ~ 3); // word align
02545         //B=(LPBYTE)( (((DWORD)(B))+((bbit==7)?3:4)) & ~ 3); // word align
02546     }
02547 #endif
02548     ERROR3IF( (((DWORD_PTR)A-(DWORD_PTR)pABytes)!=pABMI->biSizeImage), "Alex got his other algorithm wrong in one way");
02549     ERROR3IF( (((DWORD_PTR)B-(DWORD_PTR)pBBytes)!=pBBMI->biSizeImage), "Alex got his other algorithm wrong in another way");
02550 
02551     // Bet noone has thought to give the mono bitmap a palette yet
02552     RGBQUAD * Palette= pMonochromeInfo->bmiColors;
02553 //  ERROR2IF((pBBMI->biClrUsed < 2), FALSE, "DIBUtil::MakeBitmapMask not passed a large enough mono palette");
02554 //  Palette[0].rgbRed=Palette[0].rgbBlue=Palette[0].rgbGreen=0;
02555 //  Palette[1].rgbRed=Palette[1].rgbBlue=Palette[1].rgbGreen=255;
02556 
02557     // Must ensure white is white and black is black!
02558     ERROR2IF((pBBMI->biClrUsed < 256), FALSE, "DIBUtil::MakeBitmapMask not passed a large enough mono palette");
02559     Palette[0].rgbRed=Palette[0].rgbBlue=Palette[0].rgbGreen=0;
02560     Palette[255].rgbRed=Palette[255].rgbBlue=Palette[255].rgbGreen=255;
02561 
02562     return TRUE;
02563 }
02564 
02565 /********************************************************************************************
02566 
02567 >   static BOOL DIBUtil::MakeBitmapSmaller(UINT32 OldWidth, UINT32 OldHeight, UINT32 BaseX, UINT32 BaseY, 
02568                                            UINT32 NewWidth, UINT32 NewHeight, UINT32 BPP, LPBYTE pBits)
02569 
02570     Author:     Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com>
02571     Created:    25/4/95
02572     Inputs:     OldWidth, OldHeight = the old height of the bitmap
02573                 BaseX, BaseY = the coordinates in the old bitmap that map to (0,0) in the new bitmap
02574                 NewWidth, NewHeight = the new height of the bitmap
02575                 BPP = bits per pixel (must be 8, 16 or 32)
02576     Outputs:    pBits altered
02577     Returns:    TRUE if converted it ok else FALSE & error set
02578     Purpose:    Resizes a bitmap
02579     SeeAlso:    -
02580     Scope:      Static
02581 
02582 This means that the rectangle (BaseX, BaseY) - (BaseX+NewWidth, BaseY+NewHeight) form the
02583 o/p bitmap. A ReAlloc can be performed after this call. The rect is inclusive/exclusive.
02584 
02585 ********************************************************************************************/
02586 
02587 
02588 BOOL DIBUtil::MakeBitmapSmaller(UINT32 OldWidth, UINT32 OldHeight, UINT32 BaseX, UINT32 BaseY, 
02589                                        UINT32 NewWidth, UINT32 NewHeight, UINT32 BPP, LPBYTE pBits)
02590 {
02591     ERROR2IF(!pBits, FALSE, "DIBUtil::MakeBitmapSmaller would really appreciate a bitmap");
02592     ERROR2IF((BPP!=8) && (BPP!=16) && (BPP!=32), FALSE, "DIBUtil::MakeBitmapSmaller passed invalid BPP");
02593     ERROR2IF(OldWidth<NewWidth, FALSE, "DIBUtil::MakeBitmapSmaller thinks you are making the bitmap wider");
02594     ERROR2IF(OldHeight<NewHeight, FALSE, "DIBUtil::MakeBitmapSmaller thinks you are making the bitmap taller");
02595 
02596     ERROR2IF((BaseX>OldWidth) || (BaseY>OldHeight), FALSE, "DIBUtil::MakeBitmapSmaller passed bad Base");
02597     ERROR2IF((BaseX+NewWidth>OldWidth) || (BaseY+NewHeight>OldHeight), FALSE, "DIBUtil::MakeBitmapSmaller passed bad rect");
02598     // as these are unsighned all we have to do is check against zero
02599     ERROR2IF(!OldWidth || !NewWidth || !OldHeight || !NewHeight, FALSE, "DIBUtil::MakeBitmapSmaller passed bad width/height");
02600 
02601     UINT32 OldWidthR=OldWidth;
02602     UINT32 NewWidthR=NewWidth; // with wastage values
02603     UINT32 BPPShift=2;
02604 
02605     switch (BPP)
02606     {
02607         case 8:
02608             OldWidthR=(OldWidth+3)&~3;
02609             NewWidthR=(NewWidth+3)&~3;
02610             BPPShift=0;
02611             break;
02612         case 16:
02613             OldWidthR=(OldWidth+1)&~1;
02614             NewWidthR=(NewWidth+1)&~1;
02615             BPPShift=1;
02616             break;
02617         case 32:
02618         default:
02619             break;
02620     }
02621 
02622 
02623     UINT32 NewByteW = DIBUtil::ScanlineSize(NewWidth, BPP); 
02624     UINT32 OldByteW = DIBUtil::ScanlineSize(OldWidth, BPP); 
02625 
02626     LPBYTE pSrc=pBits+OldByteW*BaseY+(BaseX<<BPPShift);
02627     LPBYTE pDest=pBits;
02628     
02629     for (UINT32 y=0; y<NewHeight; y++)
02630     {
02631         memcpy(pDest, pSrc, NewByteW);
02632         pDest+=NewByteW;
02633         pSrc+=OldByteW; 
02634     }
02635     return TRUE;
02636 }
02637 
02638 /********************************************************************************************
02639 
02640 >   static BOOL DIBUtil::Init()
02641 
02642     Author:     Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com>
02643     Created:    25/4/95
02644     Inputs:     None
02645     Outputs:    None
02646     Returns:    TRUE if worked ok else FALSE & error set
02647     Purpose:    Reads our prefs
02648     SeeAlso:    -
02649     Scope:      Static
02650 
02651 ********************************************************************************************/
02652 
02653 BOOL DIBUtil::Init()
02654 {
02655     return
02656         Camelot.DeclareSection( wxT("DisplayKludges"), 10)
02657         && Camelot.DeclarePref(NULL, wxT("RenderDirection4"),  &RenderDirection4, FALSE, TRUE )
02658         && Camelot.DeclarePref(NULL, wxT("RenderDirection8"),  &RenderDirection8, FALSE, TRUE )
02659         && Camelot.DeclarePref(NULL, wxT("RenderDirection16"), &RenderDirection16, FALSE, TRUE )
02660         && Camelot.DeclarePref(NULL, wxT("RenderDirection24"), &RenderDirection24, FALSE, TRUE )
02661         && Camelot.DeclarePref(NULL, wxT("SubbandConversionSize"), &SubbandConversionSize, 0x200, 0x1000000);
02662 }
02663 
02664 /***********************************************************************************************
02665 >   static UINT32 DIBUtil::CalcPaletteSize(UINT32 Depth, bool bUsingBitFields, UINT32 UsedColours = 0)
02666     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>/Richard - Fixed by Jonathan (I removed the code duplication and added the
02667                 bUsingBitFields flag)
02668     Created:    19/5/95 (& 12/2/2001)
02669     Inputs:     Depth           - The colour depth being used
02670                 bUsingBitFields - Are we using a bitfield (ie do we have a mask for true colour
02671                                 bitmaps - see docs for BITMAPINFOHEADER)
02672                 UsedColours     - The number of colours the bitmap uses or 0 if we do not have
02673                                 a limited palette
02674     Returns:    The size of the palette required for this bitmap depth
02675     Purpose:    Calculates the size of the 
02676     Notes:      Used to be in SGLibOil but moved 30/6/95 by Neville as required for 
02677                 transparent GIF import.
02678     SeeAlso:    DIBUtil::CopyKernelBitmap;
02679 ***********************************************************************************************/
02680 UINT32 DIBUtil::CalcPaletteSize(UINT32 Depth, bool bUsingBitFields, UINT32 UsedColours)
02681 {
02682     ERROR3IF((bUsingBitFields && (Depth != 16 || Depth != 32)), "Invalid use of DIBUtil::CalcPaletteSize()");
02683 
02684     // Calculate the size of the DIB data
02685     UINT32 extras = 0;
02686     switch (Depth)
02687     {
02688         case 1:
02689             if (UsedColours > 0 && UsedColours <= 2)
02690                 extras = UsedColours;
02691             else
02692                 extras = 2;
02693             break;
02694         case 4:
02695             if (UsedColours > 0 && UsedColours <= 16)
02696                 extras = UsedColours;
02697             else
02698                 extras = 16;
02699             break;
02700         case 8:
02701             if (UsedColours > 0 && UsedColours <= 256)
02702                 extras = UsedColours;
02703             else
02704                 extras = 256;
02705             break;
02706         case 16:
02707         case 32:
02708             if (bUsingBitFields)
02709                 extras = 3;
02710             break;
02711     }
02712     ERROR3IF(extras == 0 && Depth != 16 && Depth != 24 && Depth != 32, "Unsupported DIB depth!");
02713 
02714     return(extras * sizeof(RGBQUAD));
02715 }
02716 
02717 
02718 /***********************************************************************************************
02719 
02720 >   static BOOL DIBUtil::CopyBitmap(LPBITMAPINFO pSourceInfo, LPBYTE pSourceBits,
02721                                     LPBITMAPINFO *pDestInfo, LPBYTE *pDestBits)
02722                       
02723     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
02724     Created:    18/9/95
02725 
02726     Inputs:     pSourceInfo     - A information header for the bitmap to be copied
02727                 pSourceBits     - the actual bits for the bitmap to be copied
02728     Outputs:    pDestInfo       - pointer to the copied information block
02729                 pDestBits       - pointer ot the copied bits data
02730     
02731     Returns:    True if copied ok, false otherwise
02732     
02733     Purpose:    Allocates a new DIB information header block and bits data and copies the source
02734                 bitmap data across to the new bitmap.
02735                 At present, just copies the actual bits data, the header will be the defaults
02736                 plus width, height and colour depth. Not interested in the palette and other
02737                 information stored in the bitmap info header.
02738 
02739     SeeAlso:    TI_GIFFilter::RenderTransparencyMask
02740                 
02741 ***********************************************************************************************/
02742 
02743 //#ifdef _DEBUG
02744 void DebugMemCopy(LPBYTE pDest, LPBYTE pSrc, UINT32 size)
02745 {
02746     memcpy(pDest, pSrc, size);
02747 }
02748 //#endif
02749 
02750 BOOL DIBUtil::CopyBitmap(LPBITMAPINFO pSourceInfo, LPBYTE pSourceBits,
02751                          LPBITMAPINFO *pDestInfo, LPBYTE *pDestBits)
02752 {
02753     // In case of early set these return pointers to NULL
02754     *pDestInfo = NULL;
02755     *pDestBits = NULL;
02756 
02757     ERROR2IF(pSourceInfo == NULL || pSourceBits == NULL, FALSE, "DIBUtil::CopyBitmap bad source bitmap");
02758 
02759     // Get a pointer to the useful bitmap header information for things like the size of the
02760     // bitmap and colour depth. 
02761     LPBITMAPINFOHEADER pSourceInfoHeader = &(pSourceInfo->bmiHeader); 
02762     DWORD biCompression = pSourceInfoHeader->biCompression;
02763 
02764     // Try and allocate the detsination bitmap to be the same size and colour depth as the source
02765     *pDestInfo = AllocDIB( pSourceInfoHeader->biWidth, pSourceInfoHeader->biHeight,
02766                            pSourceInfoHeader->biBitCount,
02767                            pDestBits );
02768 
02769     (*pDestInfo)->bmiHeader.biCompression = biCompression;
02770 
02771     // failed to allocate the bitmap so return false.
02772     if (*pDestInfo == NULL || *pDestBits == NULL )
02773         return FALSE;
02774     
02775     // Now copy the data from the source to the destination
02776     DWORD BitmapSize = pSourceInfo->bmiHeader.biSizeImage;
02777 #ifdef _DEBUG
02778     DebugMemCopy(*pDestBits, pSourceBits, BitmapSize);
02779 #else
02780     memcpy(*pDestBits, pSourceBits, BitmapSize);
02781 #endif
02782 
02783 
02784 //  LPBYTE A = pDestBMBytes;
02785 //  LPBYTE B = pBMBytes;
02786 //  for (INT32 y = 0; y < pBMInfoHeader->biHeight; y++)
02787 //  {
02788 //      for (INT32 x = 0; x < pBMInfoHeader->biWidth; x++)
02789 //      {
02790 //          *(A++) = *(B++);
02791 //      }
02792 //      A=(LPBYTE)( (((DWORD)(A))+3) & ~ 3); // word align
02793 //      B=(LPBYTE)( (((DWORD)(B))+3) & ~ 3); // word align
02794 //  }
02795 
02796     return TRUE;
02797 }   
02798 
02799 /***********************************************************************************************
02800 
02801 >   static BOOL DIBUtil::CopyEntireBitmap(LPBITMAPINFO pSourceInfo, LPBYTE pSourceBits,
02802                                           LPBITMAPINFO *pDestInfo, LPBYTE *pDestBits)
02803                       
02804     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
02805     Created:    18/12/96
02806 
02807     Inputs:     pSourceInfo     - A information header for the bitmap to be copied
02808                 pSourceBits     - the actual bits for the bitmap to be copied
02809     Outputs:    pDestInfo       - pointer to the copied information block
02810                 pDestBits       - pointer ot the copied bits data
02811     
02812     Returns:    True if copied ok, false otherwise
02813     
02814     Purpose:    Allocates a new DIB information header block and bits data and copies the source
02815                 bitmap data across to the new bitmap.
02816                 At present, just copies the actual bits data, the header will be the defaults
02817                 plus width, height and colour depth. Not interested in the palette and other
02818                 information stored in the bitmap info header.
02819                 Same as CopyBitmap but actually copies the rest of the data as well. This includes:-
02820                     Palette information
02821                     Header information
02822                     Bits information
02823 
02824     SeeAlso:    DIBUtil::CopyBitmap; PhotoShopPlugIn::Apply;
02825                 
02826 ***********************************************************************************************/
02827 
02828 BOOL DIBUtil::CopyEntireBitmap(LPBITMAPINFO pSourceInfo, LPBYTE pSourceBits,
02829                                LPBITMAPINFO *pDestInfo, LPBYTE *pDestBits)
02830 {
02831     // In case of early set these return pointers to NULL
02832     *pDestInfo = NULL;
02833     *pDestBits = NULL;
02834 
02835     ERROR2IF(pSourceInfo == NULL || pSourceBits == NULL, FALSE, "DIBUtil::CopyBitmap bad source bitmap");
02836 
02837     // Get a pointer to the useful bitmap header information for things like the size of the
02838     // bitmap and colour depth. 
02839     LPBITMAPINFOHEADER pSourceInfoHeader = &(pSourceInfo->bmiHeader); 
02840 
02841     // Try and allocate the detsination bitmap to be the same size and colour depth as the source
02842     *pDestInfo = AllocDIB( pSourceInfoHeader->biWidth, pSourceInfoHeader->biHeight,
02843                            pSourceInfoHeader->biBitCount,
02844                            pDestBits );
02845 
02846     // failed to allocate the bitmap so return false.
02847     if (*pDestInfo == NULL || *pDestBits == NULL )
02848         return FALSE;
02849     
02850     // Now copy the data from the source to the destination
02851     DWORD BitmapSize = pSourceInfo->bmiHeader.biSizeImage;
02852     memcpy(*pDestBits, pSourceBits, BitmapSize);
02853 
02854     // The older slower way of doing that
02855 //  LPBYTE A = *pDestBits;
02856 //  LPBYTE B = pSourceBits;
02857 //  for (INT32 y = 0; y < pSourceInfoHeader->biHeight; y++)
02858 //  {
02859 //      for (INT32 x = 0; x < pSourceInfoHeader->biWidth; x++)
02860 //      {
02861 //          *(A++) = *(B++);
02862 //      }
02863 //      A=(LPBYTE)( (((DWORD)(A))+3) & ~ 3); // word align
02864 //      B=(LPBYTE)( (((DWORD)(B))+3) & ~ 3); // word align
02865 //  }
02866 
02867     // Ensure remaining info header entries are correct
02868     LPBITMAPINFOHEADER pDestInfoHeader = &((*pDestInfo)->bmiHeader); 
02869     pDestInfoHeader->biPlanes           = pSourceInfoHeader->biPlanes;
02870     pDestInfoHeader->biCompression      = pSourceInfoHeader->biCompression;
02871     pDestInfoHeader->biXPelsPerMeter    = pSourceInfoHeader->biXPelsPerMeter;
02872     pDestInfoHeader->biYPelsPerMeter    = pSourceInfoHeader->biYPelsPerMeter;
02873     pDestInfoHeader->biClrImportant     = pSourceInfoHeader->biClrImportant;
02874     pDestInfoHeader->biClrUsed          = pSourceInfoHeader->biClrUsed;
02875 
02876     LPRGBQUAD pSourcePalette = &(pSourceInfo->bmiColors[0]);
02877     LPRGBQUAD pDestPalette = &((*pDestInfo)->bmiColors[0]);
02878     UINT32 NumberOfColours = pSourceInfoHeader->biClrUsed;
02879     // If we have zero colours on a bitmap which is 8bpp or less then this is bad.
02880     // This should be translated as the maximum number of colours allowed
02881     if (pSourceInfoHeader->biBitCount <= 8 && NumberOfColours == 0)
02882         NumberOfColours = 1 << pSourceInfoHeader->biBitCount;
02883     CopyPalette(pSourcePalette, pDestPalette, NumberOfColours);
02884 
02885     return TRUE;
02886 }   
02887 
02888 /***********************************************************************************************
02889 
02890 >   static BOOL DIBUtil::CopyPalette(LPRGBQUAD pSourcePalette, LPRGBQUAD pDestPalette, UINT32 NumberOfColours)
02891                       
02892     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
02893     Created:    18/12/96
02894     Inputs:     pSourcePalette  - the source palette in RGBQUAD form
02895                 pDestPalette    - the destination palette in RGBQUAD form
02896                 NumberOfColours - number of palette entries to copy
02897     Returns:    True if copied correctly, False otherwise.
02898     Purpose:    Copy a palette from a bitmap which has been duplicated and so has the same colour
02899                 depth and number of palette entries, to a destination bitmap. Assumes palettes
02900                 already allocated as part of the duplication process.
02901     SeeAlso:    DIBUtil::CopyEntireBitmap;
02902 
02903 ***********************************************************************************************/
02904 
02905 BOOL DIBUtil::CopyPalette(LPRGBQUAD pSourcePalette, LPRGBQUAD pDestPalette, UINT32 NumberOfColours)
02906 {
02907     // Check if there is any palette information to copy, if not just return
02908     if (pSourcePalette == NULL || pDestPalette == NULL || NumberOfColours == 0)
02909         return TRUE;
02910 
02911     for (UINT32 i = 0; i < NumberOfColours; i++)
02912     {
02913         pDestPalette->rgbBlue       = pSourcePalette->rgbBlue;
02914         pDestPalette->rgbGreen      = pSourcePalette->rgbGreen;
02915         pDestPalette->rgbRed        = pSourcePalette->rgbRed;
02916         pDestPalette->rgbReserved   = pSourcePalette->rgbReserved;
02917         pDestPalette++;
02918         pSourcePalette++;
02919     }
02920 
02921     return TRUE;
02922 }
02923 
02924 /***********************************************************************************************
02925 
02926 >   static KernelBitmap *DIBUtil::CopyKernelBitmap(KernelBitmap *pKernelBitmap, BOOL IsTemp = FALSE)
02927 
02928     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
02929     Created:    19/5/95
02930 
02931     Inputs:     pKernelBitmap   - A kernel bitmap to copy
02932                 IsTemp          - TRUE means only create the bitmap as temporary and hence
02933                                   don't show in bitmap gallery
02934                                   FALSE means create properly and show in bitmap gallery (default)
02935     Outputs:    -
02936     Returns:    Pointer to newly allocated KernelBitmap structure
02937     
02938     Purpose:    Allocates a new CWxBitmap and KernelBitmap pointing to it.
02939                 Note these are completely new versions containing the same data as the
02940                 old ones.
02941 
02942                 Deleting the KernelBitmap will handle the other stuff ok...
02943                 
02944     Notes:      Most of the code in camelot assumes that the OILBitmap is always in
02945                 memory, so creating a new kernelbitmap would just pop in a pointer
02946                 to the OILBitmap. This is bad when thumbnails come into the equation
02947                 since these come and go like no tomorrow...
02948 
02949                 This should really be popped in dibutils at some point in the 'I want a 
02950                 big rebuild'ing future...
02951                 Used to be in SGLibOil but moved 30/6/95 by Neville as required for 
02952                 transparent GIF import.
02953 
02954 ***********************************************************************************************/
02955 
02956 KernelBitmap *DIBUtil::CopyKernelBitmap(KernelBitmap *pKernelBitmap, BOOL IsTemp)
02957 {
02958     OILBitmap *pOilBitmap = pKernelBitmap->ActualBitmap;
02959     ERROR3IF(pOilBitmap == NULL, "Unattached kernel bitmap found!");
02960     CWxBitmap* pWBitmap = (CWxBitmap*)pOilBitmap;
02961     LPBITMAPINFO Info = pWBitmap->BMInfo;
02962     LPBYTE Bytes = pWBitmap->BMBytes;
02963     ERROR3IF(Info == NULL, "Bitmap info is null - oh god !");
02964     ERROR3IF(Info->bmiHeader.biSizeImage == 0, "Bitmap data size is zero - I'm about to screw up");
02965 
02966     LPBITMAPINFO NewInfo = NULL;
02967 
02968     LPBYTE NewBytes = NULL;
02969     NewInfo = AllocDIB(Info->bmiHeader.biWidth, Info->bmiHeader.biHeight, Info->bmiHeader.biBitCount, &NewBytes);
02970 
02971     if (NewInfo == NULL || NewBytes == NULL)
02972     {
02973         ERROR3("Couldn't allocate enough memory for new CWxBitmap");
02974         return(NULL);
02975     }
02976 
02977     UINT32 PalSize = CalcPaletteSize(pWBitmap->GetBPP(), Info->bmiHeader.biCompression == BI_BITFIELDS);
02978     DWORD HeaderSize = Info->bmiHeader.biSize + PalSize;
02979     DWORD BitmapSize = Info->bmiHeader.biSizeImage;
02980 
02981     // Copy the DIB into the block of memory (copy the header and body separately as they
02982     // may not lie in contiguous memory)
02983     memcpy(NewInfo, Info, HeaderSize);
02984     memcpy(NewBytes, Bytes, BitmapSize);
02985 
02986     CWxBitmap *NewCWxBitmap = new CWxBitmap(NewInfo, NewBytes);
02987     ERROR3IF(NewCWxBitmap == NULL, "NULL CWxBitmap created");
02988 
02989     // Create the associated kernel object to go with the oil object
02990     KernelBitmap *TheKBToReturn = new KernelBitmap((OILBitmap *)NewCWxBitmap, IsTemp);
02991 
02992     return TheKBToReturn;
02993 }
02994 
02995 /***********************************************************************************************
02996 
02997 >   static BOOL DIBUtil::CopyBitmapSection(LPBITMAPINFO pSourceInfo, LPBYTE pSourceBits,
02998                                           LPBITMAPINFO *pDestInfo, LPBYTE *pDestBits
02999                                           INT32 SourceTop, INT32 SourceLeft)
03000                       
03001     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03002                 Altered by Phil to clip sensibly 13/05/2004
03003     Created:    24/11/99
03004 
03005     Inputs:     pSourceInfo     - A information header for the bitmap to be copied
03006                 pSourceBits     - the actual bits for the bitmap to be copied
03007                 pDestInfo       - An information header for the bitmap to be copied to
03008                 pDestBits       - An initialised bitmap to be copied into
03009                 SourceTop       - the y value of the the top left part of the section to be copied
03010                 SourceLeft      - the x value of the top left part of the section to be copied
03011     Outputs:    pDestInfo       - pointer to the copied information block
03012                 pDestBits       - pointer ot the copied bits data
03013 
03014     
03015     Returns:    True if copied ok, false otherwise
03016     
03017     Purpose:    To copy a section of the source bitmap to the destination. Note that unlike the
03018                 other copy functions in this file the destination header must in not allocated so  
03019                 you must do it yourself. Likewise palette info.
03020 
03021     SeeAlso:    DIBUtil::CopyBitmap; PhotoShopPlugIn::Apply;
03022                 
03023 ***********************************************************************************************/
03024 
03025 
03026 BOOL DIBUtil::CopyBitmapSection(LPBITMAPINFO pSourceInfo, LPBYTE pSourceBits,
03027                                   LPBITMAPINFO pDestInfo,   LPBYTE pDestBits,
03028                                   INT32 SourceTop, INT32 SourceLeft)
03029 {
03030 //TRACEUSER( "Phil", _T("CopyBitmapSection Source %d, %d, Dest %d %d\n"), pSourceInfo->bmiHeader.biWidth, pSourceInfo->bmiHeader.biHeight, pDestInfo->bmiHeader.biWidth, pDestInfo->bmiHeader.biHeight);
03031 //TRACEUSER( "Phil", _T("CopyBitmapSection Source Compression %x\n"), pSourceInfo->bmiHeader.biCompression);
03032     if (pSourceInfo == NULL || pSourceBits == NULL || 
03033         pDestInfo == NULL || pDestBits == NULL)
03034     {
03035         ERROR3("One of the input pointers is NULL");
03036         return FALSE;
03037     }
03038 
03039     if (pSourceInfo->bmiHeader.biBitCount<8 || pDestInfo->bmiHeader.biBitCount<8)
03040     {
03041         ERROR3("This routine can't handle bit depths < 1 byte per pixel (no masking)");
03042         return FALSE;
03043     }
03044 
03045     if (pSourceInfo->bmiHeader.biBitCount != pDestInfo->bmiHeader.biBitCount)
03046     {
03047         ERROR3("This routine can't handle differing src and dest bit depths");
03048         return FALSE;
03049     }
03050 
03051     // Clip the dest rectangle against the source rectangle
03052     INT32 CopyWidth = pDestInfo->bmiHeader.biWidth;
03053     INT32 CopyHeight = pDestInfo->bmiHeader.biHeight;
03054     LPBYTE pDest = pDestBits;
03055     if (SourceLeft<0)
03056     {
03057         CopyWidth += SourceLeft;    // Subtract left offset from width to copy
03058         pDest += ScanlineBytes(-SourceLeft, pDestInfo->bmiHeader.biBitCount);
03059         SourceLeft = 0;
03060     }
03061     if (SourceTop<0)
03062     {
03063         CopyHeight += SourceTop;    // Subtract top offset from height to copy
03064         pDest += ScanlineSize(pDestInfo->bmiHeader.biWidth, pDestInfo->bmiHeader.biBitCount) * -SourceTop;
03065         SourceTop = 0;
03066     }
03067     if ((SourceLeft+CopyWidth) > pSourceInfo->bmiHeader.biWidth)
03068     {
03069         CopyWidth = (pSourceInfo->bmiHeader.biWidth - SourceLeft);
03070     }
03071     if ((SourceTop+CopyHeight) > pSourceInfo->bmiHeader.biHeight)
03072     {
03073         CopyHeight = (pSourceInfo->bmiHeader.biHeight - SourceTop);
03074     }
03075 
03076     // Check whether the clipping has left anything worth rendering...
03077     if (CopyWidth<=0 || CopyHeight<=0)
03078     {
03079         TRACEUSER("Phil", wxT("CopyBitmapSection clipped to NULL rectangle\n") );
03080         return TRUE;
03081     }
03082     
03083     // first move the source pointer to the correct location
03084     INT32 LeftOffset = ScanlineBytes(SourceLeft, pSourceInfo->bmiHeader.biBitCount);
03085     INT32 SourceScanlineBytes = ScanlineSize(pSourceInfo->bmiHeader.biWidth, pSourceInfo->bmiHeader.biBitCount);
03086 
03087     LPBYTE pSource = pSourceBits + LeftOffset;
03088     pSource += SourceScanlineBytes * SourceTop;
03089 
03090     // we are going to have to iterate through the sourcebitmap scanline by scanline and copy the
03091     // section that we want.  First work out how many bytes we want per scanline
03092 
03093     INT32 DestScanlineBytes = ScanlineSize(pDestInfo->bmiHeader.biWidth, pDestInfo->bmiHeader.biBitCount);
03094     INT32 CopyBytes = ScanlineBytes(CopyWidth, pSourceInfo->bmiHeader.biBitCount);
03095     for (INT32 Count = 0; Count < CopyHeight; Count++)
03096     {
03097         memcpy(pDest, pSource, CopyBytes);
03098 
03099         // move the destination pointer up by one scanline
03100         pDest += DestScanlineBytes;
03101         pSource += SourceScanlineBytes;
03102     }
03103 
03104     // If we have a 24-bit bitmap, no alpha channel, make sure we haven't inadvertently blitted
03105     // in a bunch of alpha values
03106     // Das ist eine Uber-bodge...
03107     if (pDestInfo->bmiHeader.biCompression == BI_RGB && pDestInfo->bmiHeader.biBitCount==32)
03108     {
03109         LPDWORD pBits = (LPDWORD) pDestBits;
03110         for (UINT32 i=0; i<pDestInfo->bmiHeader.biSizeImage; i+=sizeof(DWORD))
03111         {
03112             *pBits &= 0x00FFFFFF;
03113             pBits++;
03114         }
03115     }
03116     
03117     // if we have an 8 bit bitmap then copy the palette also
03118     if (pDestInfo->bmiHeader.biBitCount == 8 &&
03119         pSourceInfo->bmiHeader.biBitCount == 8)
03120     {
03121         for (INT32 i = 0; i < 256; i++)
03122             pDestInfo->bmiColors[i] = pSourceInfo->bmiColors[i];
03123     }
03124 
03125     return TRUE;
03126 }
03127 
03128 /***********************************************************************************************
03129 >   static BOOL DIBUtil::CountColoursUsed(BITMAPINFO* pInfo, BYTE* pBits, UINT32** pResultsArray)
03130                       
03131     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03132     Created:    4/6/96
03133     Inputs:     pInfo   Pointer to a BITMAPINFO describing the bitmap
03134                 pBits   Pointer to the bitmap bits
03135     Outputs:    pResultsArray   Allocated and filled in with results
03136     Returns:    TRUE/FALSE for success/failure
03137     Purpose:    Counts the usage for each palette index in the bitmap.
03138                 NOTE: Caller is responsible for CCFreeing the results array.
03139 ***********************************************************************************************/
03140 BOOL DIBUtil::CountColoursUsed(BITMAPINFO* pInfo, BYTE* pBits, UINT32** pResultsArray)
03141 {
03142     ERROR2IF(pInfo==NULL || pBits==NULL, FALSE, "NULL entry param");
03143     ERROR3IF(*pResultsArray != NULL, "pResultsArray was not NULL (are you leaking memory?)");
03144 
03145     // Claim and initalise the results array.
03146     const UINT32 NumColours = 1 << pInfo->bmiHeader.biBitCount;
03147     ERROR2IF(NumColours>256, FALSE, "DIBUtil::CountColoursUsed only handles palletted DIBs");
03148     *pResultsArray = (UINT32*) CCMalloc(NumColours*sizeof(UINT32));
03149     if (*pResultsArray == NULL)
03150         return FALSE;
03151     memset(*pResultsArray, 0, NumColours*sizeof(UINT32));
03152 
03153     // Calculate the length of a scanline in bytes as they are word aligned.
03154     UINT32 ScanLineLength = 0;
03155     switch (pInfo->bmiHeader.biBitCount)
03156     {
03157         case 8:
03158             ScanLineLength = ((pInfo->bmiHeader.biWidth+3)/4)*4;
03159             break;
03160         case 4:
03161             ScanLineLength = ((pInfo->bmiHeader.biWidth+7)/8)*4;
03162             break;
03163         case 1:
03164             ScanLineLength = ((pInfo->bmiHeader.biWidth+31)/32)*4;
03165             break;
03166         default:
03167             ERROR2(FALSE, "Unknown depth");
03168     }
03169 
03170     // Run through the pixels, incrementing the counters
03171     for (INT32 y = 0; y < pInfo->bmiHeader.biHeight; y++)
03172     {
03173         BYTE* pCurrentPixel = pBits + y*ScanLineLength;
03174         BYTE CurrentBitMask = 0x80;
03175 
03176         for (INT32 x = 0; x < pInfo->bmiHeader.biWidth; x++)
03177         {
03178             switch (pInfo->bmiHeader.biBitCount)
03179             {
03180                 case 8:
03181                     // simple - one pixel per byte
03182                     (*pResultsArray)[(*pCurrentPixel)]++;
03183                     pCurrentPixel++;
03184                     break;
03185 
03186                 case 4:
03187                     // Two pixels per byte
03188                     if (x%2 == 0)
03189                     {
03190                         (*pResultsArray)[((*pCurrentPixel) >> 4)]++;
03191                     }
03192                     else
03193                     {
03194                         (*pResultsArray)[((*pCurrentPixel) & 0xF)]++;
03195                         pCurrentPixel++;
03196                     }
03197                     break;
03198 
03199                 case 1:
03200                     // Tricker - one pixel per bit.
03201                     if ((*pCurrentPixel) & CurrentBitMask)
03202                         (*pResultsArray)[1]++;
03203                     else
03204                         (*pResultsArray)[0]++;
03205 
03206                     if (CurrentBitMask == 1)
03207                     {
03208                         CurrentBitMask = 0x80;
03209                         pCurrentPixel++;
03210                     }
03211                     else
03212                         CurrentBitMask = CurrentBitMask >> 1;
03213                     break;
03214 
03215                 default:
03216                     ERROR2(FALSE, "Unknown depth");
03217             }
03218         }
03219     }
03220 
03221     return TRUE;
03222 }
03223 
03224 /***********************************************************************************************
03225 
03226   > static INT32 DIBUtil::FindLeastUsedColour(BITMAPINFO* pInfo, UINT32* pResultsArray)
03227                       
03228     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> from Will code
03229     Created:    19/8/97
03230     Inputs:     pInfo           Pointer to a BITMAPINFO describing the bitmap
03231                 pResultsArray   filled in with results from CountColoursUsed
03232     Returns:    The index of the transparent colour to use
03233     Purpose:    Takes the results from DIBUtil::CountColoursUsed and works out which colour is
03234                 the best one to use as a transparent colour by finding the least used. 
03235                 NOTE: Caller is responsible for CCFreeing the results array.
03236 
03237 ***********************************************************************************************/
03238 
03239 INT32 DIBUtil::FindLeastUsedColour(BITMAPINFO* pInfo, UINT32* pResultsArray)
03240 {
03241     ERROR2IF(pInfo == NULL || pResultsArray == NULL, -1, "NULL entry param");
03242     INT32 TransIndex = -1;
03243 
03244     INT32 MinIndex = 0;
03245 
03246     // Attempt to find an unused colour in the results array
03247     INT32 Bpp = pInfo->bmiHeader.biBitCount;
03248     INT32 MaxColours = 1 << Bpp;
03249     for (INT32 loop = 0; loop < MaxColours; loop++)
03250     {
03251         if (pResultsArray[loop] == 0 && TransIndex == -1)   // For consistancy use the first available index
03252             TransIndex = loop;
03253         if (pResultsArray[loop] < pResultsArray[MinIndex])
03254             MinIndex = loop;
03255     }
03256 
03257     if (TransIndex == -1)
03258     {
03259         // Make white transparent for 1bpp images
03260         if (Bpp == 1)
03261             TransIndex = 1;
03262         else
03263             TransIndex = MinIndex;
03264     }
03265 
03266     return TransIndex;
03267 }
03268 
03269 #if !defined(EXCLUDE_FROM_RALPH)
03270 
03271 /***********************************************************************************************
03272 
03273 >   static size_t DIBUtil::GetOptimalPaletteWorkspaceSize()
03274 
03275                       
03276     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
03277     Created:    9/5/96
03278 
03279     Inputs:     -
03280     Outputs:    -
03281     
03282     Returns:    Size of workspace required
03283     
03284     Purpose:    Returns size of workspace required by optimal palette routines.
03285 
03286                 This function just calls gavins C code in 'winoil\gpalopt.cpp'.
03287 
03288     SeeAlso:    DIBUtil::OptimalPaletteInitialise
03289                 
03290 ***********************************************************************************************/
03291 
03292 size_t DIBUtil::GetOptimalPaletteWorkspaceSize()
03293 {
03294 //  return ::GetOptimalPaletteWorkspaceSize();
03295     ASSERT(FALSE);
03296     return 0;
03297 }
03298 
03299 /***********************************************************************************************
03300 
03301 >   static BOOL DIBUtil::OptimalPaletteInitialise( INT32* Stats )
03302 
03303                       
03304     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
03305     Created:    9/5/96
03306 
03307     Inputs:     Stats, pointer to stats table to initialise
03308                 Use GetOptimalPaletteWorkspaceSize() to create this pointer
03309 
03310     Outputs:    Memory pointed to be 'Stats' is initialised
03311     
03312     Returns:    TRUE if all ok
03313     
03314     Purpose:    Initialises workspace required by optimal palette routines.
03315                 Stats should have INT32 size of GetOptimalPaletteWorkspaceSize()
03316 
03317                 This function just calls gavins C code in 'winoil\gpalopt.cpp'.
03318 
03319     SeeAlso:    DIBUtil::GetOptimalPaletteWorkspaceSize
03320                 
03321 ***********************************************************************************************/
03322 
03323 BOOL DIBUtil::OptimalPaletteInitialise( void* Stats )
03324 {
03325     ERROR3IF(Stats == NULL, "NULL pointer passed to DIBUtil::OptimalPaletteInitialise");
03326     if (Stats == NULL)
03327         return FALSE;
03328 
03329 //  ::OptimalPaletteInitialise( Stats );
03330     
03331     ASSERT(FALSE);
03332     return TRUE;
03333 }
03334 
03335 
03336 BOOL DIBUtil::ExactPaletteInitialise( LPLOGPALETTE pExactPalette )
03337 {
03338     ERROR3IF(pExactPalette == NULL, "NULL pointer passed to DIBUtil::ExactPaletteInitialise");
03339     if (pExactPalette == NULL)
03340         return FALSE;
03341 
03342 //  ::ExactPaletteInitialise( pExactPalette );  
03343 //  return TRUE;
03344     ASSERT(0);
03345     return FALSE;
03346 
03347 }
03348 
03349 
03350 /***********************************************************************************************
03351 
03352 >   static BOOL DIBUtil::GenOptimalPaletteStats( INT32* Stats, RGBQUAD* pBitmap, size_t Size )
03353 
03354                       
03355     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
03356     Created:    9/5/96
03357 
03358     Inputs:     Stats should have INT32 size of GetOptimalPaletteWorkspaceSize() and should
03359                 have been initialised by a previous call to OptimalPaletteInitialise.
03360 
03361                 pBitmap points to an RGB bitmap of length Size.
03362                                 
03363     Outputs:    Stats table is updated to reflect the colours in the bitmap given
03364     
03365     Returns:    TRUE if all ok
03366     
03367     Purpose:    The purpose of this function is to build a table of statistics about one
03368                 or more bitmaps prior to calling GenOptimalPalette.
03369 
03370                 One or more bitmaps can be processed a strip at a time by multple calls to
03371                 this function, or each bitmap may be processed by a single call.
03372 
03373                 This function just calls gavins C code in 'winoil\gpalopt.cpp'.
03374 
03375     SeeAlso:    DIBUtil::GenOptimalPalette
03376                 
03377 ***********************************************************************************************/
03378 
03379 BOOL DIBUtil::GenOptimalPaletteStats( void* Stats, RGBQUAD* pBitmap, size_t Size )
03380 {
03381     ERROR3IF(Stats == NULL, "NULL Stats pointer passed to DIBUtil::GenOptimalPaletteStats");
03382     if (Stats == NULL)
03383         return FALSE;
03384 
03385     ERROR3IF(pBitmap == NULL, "NULL Bitmap pointer passed to DIBUtil::GenOptimalPaletteStats");
03386     if (pBitmap == NULL)
03387         return FALSE;
03388 
03389     ERROR3IF(Size == 0, "Bad size passed to DIBUtil::GenOptimalPaletteStats");
03390     if (Size == 0)
03391         return FALSE;
03392 
03393 //  ::GenOptimalPaletteStats( Stats, pBitmap, Size );
03394     ASSERT(FALSE);
03395 
03396     return TRUE;
03397 }
03398 
03399 
03400 
03401 
03402 
03403 
03404 /***********************************************************************************************
03405 
03406 >   static BOOL DIBUtil::GenOptimalPalette( void* Stats, PLOGPALETTE pPalette, const size_t MaxColours )
03407 
03408                       
03409     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
03410     Created:    9/5/96
03411 
03412     Inputs:     Stats should have size of GetOptimal8bppPaletteWorkspaceSize() and should
03413                 have been initialised by a previous call to Optimal8bppPaletteInitialise
03414                 and then setup by one or more calls to GenOptimal8bppPaletteStats.
03415 
03416                 pPalette should point at a logical palette. If the number of entries is
03417                 greater than MaxColours then the remaining palette entries will be cleared
03418                 to black.
03419 
03420                 MaxColours is the maximum number of colours to place into the palette.
03421                 Note that the remaining colours are cleared to black. Sensible values
03422                 would be
03423     
03424                         256 - Full 8bpp palette
03425                         255 - Allow room for a transparency colour
03426                         252 - Allow room for the four windows colours
03427                         251 - Allow room for a transparency colour and the four windows
03428                               colours.
03429 
03430                          16 - Full 4bpp palette
03431                          15 - Allow room for a transparency colour
03432 
03433                           2 - 1bpp palette
03434                           1 - 1bpp palette with transparency
03435 
03436                 Note also that if more than 236 colours are added to the 8bpp palette
03437                 then windows will not be able to correct display the palette on an 8bpp
03438                 display since it will not be able to realize all the palette entries.
03439                             
03440     Outputs:    An optimal palette is generated using the Stats provided
03441     
03442     Returns:    TRUE if all ok
03443     
03444     Purpose:    The purpose of this function is to generate an optimal palette suitable
03445                 for the bitmaps for which statistics have previously been generated.
03446 
03447                 This function just calls gavins C code in 'winoil\gpalopt.cpp'.
03448 
03449     SeeAlso:    DIBUtil::GenOptimalPaletteStats
03450                 
03451 ***********************************************************************************************/
03452 
03453 BOOL DIBUtil::GenOptimalPalette( void* Stats, PLOGPALETTE pPalette, const size_t MaxColours )
03454 {
03455     ERROR3IF(Stats == NULL, "NULL Stats pointer passed to DIBUtil::GenOptimalPalette");
03456     if (Stats == NULL)
03457         return FALSE;
03458 
03459     ERROR3IF(pPalette == NULL, "NULL Palette pointer passed to DIBUtil::GenOptimalPalette");
03460     if (pPalette == NULL)
03461         return FALSE;
03462 
03463     // the old call
03464     //::GenOptimalPalette( Stats, pPalette, MaxColours );
03465     // used to do this in one go.
03466     // The new call bellow splits this into two functions where the later one can be called
03467     // agian on its own later to reduce the number of colours
03468     //::GenOptimalPalette( Stats );
03469     //::GetOptimalPalette( pPalette, MaxColours );
03470     ASSERT(FALSE);
03471 
03472     return TRUE;
03473 }
03474 
03475 
03476 BOOL DIBUtil::CalculateNumberOfColoursInBitmap( LPLOGPALETTE pExactPalette, RGBQUAD* pBitmap, size_t Size )
03477 {
03478     ERROR3IF(pExactPalette == NULL, "NULL palette pointer passed to DIBUtil::CalculateNumberOfColoursInBitmap");
03479     if (pExactPalette == NULL)
03480         return FALSE;
03481 
03482     ERROR3IF(pBitmap == NULL, "NULL Bitmap pointer passed to DIBUtil::CalculateNumberOfColoursInBitmap");
03483     if (pBitmap == NULL)
03484         return FALSE;
03485 
03486     ERROR3IF(Size == 0, "Bad size passed to DIBUtil::CalculateNumberOfColoursInBitmap");
03487     if (Size == 0)
03488         return FALSE;
03489 
03490 //  return ::CalculateNumberOfColoursInBitmap( pExactPalette, pBitmap, Size );
03491     ASSERT(0);
03492     return FALSE;
03493 }
03494 
03495 
03496 
03497 BOOL DIBUtil::Optimal4bppPaletteInitialise_1stPass()
03498 {
03499 //  ::Optimal4bppPaletteInitialise_1stPass();
03500 
03501     return TRUE;
03502 }
03503 
03504 BOOL DIBUtil::Optimal4bppPaletteInitialise_2ndPass()
03505 {
03506 //  ::Optimal4bppPaletteInitialise_2ndPass();
03507 
03508     return TRUE;
03509 }
03510 
03511 BOOL DIBUtil::GenOptimal4bppPaletteStats_1stPass( RGBQUAD* pBitmap, size_t Size )
03512 {
03513 //  ::GenOptimal4bppPaletteStats_1stPass( pBitmap, Size );
03514 
03515     return TRUE;
03516 }
03517 
03518 BOOL DIBUtil::GenOptimal4bppPaletteStats_2ndPass( RGBQUAD* pBitmap, size_t Size )
03519 {
03520 //  ::GenOptimal4bppPaletteStats_2ndPass( pBitmap, Size );
03521 
03522     return TRUE;
03523 }
03524 
03525 BOOL DIBUtil::GenOptimal4bppPalette( PLOGPALETTE pPalette, const size_t MaxColours )
03526 {
03527 //  ::GenOptimal4bppPalette( pPalette, MaxColours );
03528 
03529     return TRUE;
03530 }
03531 
03532 
03533 size_t DIBUtil::GetOptimal8bppPaletteWorkspaceSize()
03534 {
03535 //  return ::GetOptimal8bppPaletteWorkspaceSize();
03536     ASSERT(FALSE);
03537     return 0;
03538 }
03539 
03540 BOOL DIBUtil::Optimal8bppPaletteInitialise( INT32* Stats )
03541 {
03542     ERROR3IF(Stats == NULL, "NULL pointer passed to DIBUtil::OptimalPaletteInitialise");
03543     if (Stats == NULL)
03544         return FALSE;
03545 
03546 //  ::Optimal8bppPaletteInitialise( Stats );
03547     ASSERT(FALSE);
03548 
03549     return TRUE;
03550 }
03551 
03552 BOOL DIBUtil::GenOptimal8bppPaletteStats( INT32* Stats, RGBQUAD* pBitmap, size_t Size )
03553 {
03554 //  ::GenOptimal8bppPaletteStats( Stats,  pBitmap, Size );
03555     ASSERT(FALSE);
03556 
03557     return TRUE;
03558 }
03559 
03560 BOOL DIBUtil::GenOptimal8bppPalette( INT32* Stats, PLOGPALETTE pPalette, const size_t MaxColours )
03561 {
03562 //  ::GenOptimal8bppPalette( Stats, pPalette, MaxColours );
03563     ASSERT(FALSE);
03564 
03565     return TRUE;
03566 }
03567 
03568 #endif // EXCLUDE_FROM_RALPH
03569 
03570 
03571 /********************************************************************************************
03572 
03573 >   static BOOL DIBUtil::GenGreyscalePalette(LPRGBQUAD lpPalette, const size_t PaletteSize)
03574 
03575     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
03576     Created:    13/05/96
03577     Inputs:     PaletteSize     number of palette entries that need generating
03578                 lpPalette       pointer to the palette defined in the DIB
03579                 
03580     Returns:    True if worked ok, False otherwise.
03581     Purpose:    Generate a greyscale palette for a greyscale DIB.
03582 
03583 ********************************************************************************************/
03584 
03585 BOOL DIBUtil::GenGreyscalePalette(LPRGBQUAD lpPalette, const size_t PaletteSize)
03586 {
03587     ERROR2IF(lpPalette == NULL,FALSE,"PNGUtil::GenerateGreyPalette no lpPalette present");
03588     ERROR2IF(PaletteSize <= 0,FALSE,"PNGUtil::GenerateGreyPalette no PNG palette entries present");
03589 
03590     // Work out the value we require per step so on a:-
03591     //  256 colour palette we can have 256 steps of 1
03592     //  16 colour palette we have 16 steps of 16 (16 * 16 = 256)
03593     INT32                   inc = INT32(256 / PaletteSize);
03594     INT32                   value = 0;
03595     for( size_t i = 0; i < PaletteSize; i++ )
03596     {
03597         lpPalette->rgbBlue = value;
03598         lpPalette->rgbGreen = value;
03599         lpPalette->rgbRed = value;
03600         lpPalette->rgbReserved = 0;
03601         lpPalette++;
03602         value += inc;
03603         if (value > 255)
03604             value = 255;
03605     }
03606     
03607     return TRUE;
03608 }
03609 
03610 /********************************************************************************************
03611 
03612 >   static BOOL DIBUtil::GenGreyscalePaletteTriple(RGBTRIPLE *pPalette, const size_t PaletteSize)
03613 
03614     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03615     Created:    29/1/97
03616     Inputs:     PaletteSize     number of palette entries that need generating
03617                 pPalette        pointer to the palette defined in the DIB
03618                 
03619     Returns:    True if worked ok, False otherwise.
03620     Purpose:    Generate a packed greyscale palette for a greyscale DIB.
03621 
03622                 Based on Neville's routine DIBUtil::GenGreyscalePalette
03623                 WEBSTER - markn 29/1/97
03624 
03625 ********************************************************************************************/
03626 
03627 BOOL DIBUtil::GenGreyscalePaletteTriple(RGBTRIPLE* pPalette, const size_t PaletteSize)
03628 {
03629     ERROR2IF(pPalette == NULL,FALSE,"PNGUtil::GenerateGreyPalette no pPalette present");
03630     ERROR2IF(PaletteSize <= 0,FALSE,"PNGUtil::GenerateGreyPalette no PNG palette entries present");
03631 
03632     // Work out the value we require per step so on a:-
03633     //  256 colour palette we can have 256 steps of 1
03634     //  16 colour palette we have 16 steps of 16 (16 * 16 = 256)
03635     INT32 inc = INT32(256/PaletteSize);
03636     INT32 value = 0;
03637     for (size_t i = 0; i < PaletteSize; i++ )
03638     {
03639         pPalette->rgbtBlue = value;
03640         pPalette->rgbtGreen = value;
03641         pPalette->rgbtRed = value;
03642         pPalette++;
03643         value += inc;
03644         if (value > 255)
03645             value = 255;
03646     }
03647     
03648     return TRUE;
03649 }
03650 
03651 /********************************************************************************************
03652 
03653 >   static BOOL DIBUtil::Convert24to8(LPBITMAPINFO pSourceInfo, LPBYTE pSourceBits,
03654                                       LPBITMAPINFO *pDestInfo, LPBYTE *pDestBits)
03655 
03656     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
03657     Created:    4/9/96
03658     Inputs:     pSourceInfo     - A information header for the bitmap to be copied
03659                 pSourceBits     - the actual bits for the bitmap to be copied
03660                 pPalette    - pointer to the palette in RGBTIPLE format to use when converting
03661                 NumberOfPaletteEntries - entries in this palette 
03662 
03663     Outputs:    pDestInfo       - pointer to the copied information block
03664                 pDestBits       - pointer ot the copied bits data
03665     
03666     Returns:    True if copied ok, false otherwise
03667     Purpose:    Generate an 8 bit form of a bitmap from a 24 bit form using the given palette.
03668 
03669 ********************************************************************************************/
03670 
03671 BOOL DIBUtil::Convert24to8( LPBITMAPINFO pSourceInfo, LPBYTE pSourceBits,
03672                             LPBITMAPINFO *pDestInfo, LPBYTE *pDestBits,
03673                             RGBTRIPLE *pPalette, UINT32 NumberOfPaletteEntries )
03674 {
03675     // In case of early set these return pointers to NULL
03676     *pDestInfo = NULL;
03677     *pDestBits = NULL;
03678 
03679     ERROR2IF(pSourceInfo == NULL || pSourceBits == NULL, FALSE, "DIBUtil::Convert24to8 bad source bitmap");
03680     ERROR2IF(pPalette == NULL || NumberOfPaletteEntries == 0, FALSE, "DIBUtil::Convert24to8 bad palette info");
03681 
03682     // Get a pointer to the useful bitmap header information for things like the size of the
03683     // bitmap and colour depth. 
03684     LPBITMAPINFOHEADER pSourceInfoHeader = &(pSourceInfo->bmiHeader); 
03685 
03686     ERROR2IF(pSourceInfoHeader->biBitCount != 24,FALSE,"DIBUtil::Convert24to8 bad source depth");
03687 
03688     // Try and allocate the detsination bitmap to be the same size and colour depth as the source
03689     *pDestInfo = AllocDIB( pSourceInfoHeader->biWidth, pSourceInfoHeader->biHeight,
03690                            8, pDestBits );
03691 
03692     // failed to allocate the bitmap so return false.
03693     if (*pDestInfo == NULL || *pDestBits == NULL )
03694         return FALSE;
03695 
03696     LPBITMAPINFOHEADER pDestInfoHeader = &((*pDestInfo)->bmiHeader); 
03697     
03698     // We will need the palette in LOGPALETTE for use in the conversion
03699     // We must allocate the palette to be the maximum size as otherwise people like Gavin
03700     // blow up
03701     LPLOGPALETTE pLogPalette = NULL;
03702     const UINT32 MaxColours = 256;
03703     pLogPalette = DIBUtil::AllocateLogPalette(MaxColours);
03704     if (pLogPalette == NULL)
03705         return FALSE;
03706 
03707     // Now copy the RGBTRIPLE palette into this and into the destination bitmap
03708     // Get a pointer to the palette in the destination bitmap
03709     LPRGBQUAD lpPalette = NULL;
03710     lpPalette = &((*pDestInfo)->bmiColors[0]);  // pointer to colours table
03711     //pLogPalette->palVersion = 0x300;
03712     pLogPalette->palNumEntries = NumberOfPaletteEntries;
03713     RGBTRIPLE *pPal = pPalette;
03714     for (UINT32 i = 0; i < NumberOfPaletteEntries; i++)
03715     {
03716         lpPalette->rgbRed = pPal->rgbtRed;
03717         pLogPalette->palPalEntry[i].peRed = pPal->rgbtRed;
03718         lpPalette->rgbGreen = pPal->rgbtGreen;
03719         pLogPalette->palPalEntry[i].peGreen = pPal->rgbtGreen;
03720         lpPalette->rgbBlue = pPal->rgbtBlue;
03721         pLogPalette->palPalEntry[i].peBlue = pPal->rgbtBlue;
03722         pLogPalette->palPalEntry[i].peFlags = 0x00;
03723         lpPalette->rgbReserved = 0x00;
03724         lpPalette++;
03725         pPal++;
03726     }
03727     // Fill in all other entries as black and do not use
03728     for (UINT32 i = NumberOfPaletteEntries; i < MaxColours; i++)
03729     {
03730         pLogPalette->palPalEntry[i].peRed   = 0x00;
03731         pLogPalette->palPalEntry[i].peGreen = 0x00;
03732         pLogPalette->palPalEntry[i].peBlue  = 0x00;
03733         pLogPalette->palPalEntry[i].peFlags = 0xFF;     // mark as do not use
03734         lpPalette->rgbRed       = 0x00;
03735         lpPalette->rgbGreen     = 0x00;
03736         lpPalette->rgbBlue      = 0x00;
03737         lpPalette->rgbReserved  = 0xFF; // mark as do not use
03738         lpPalette++;
03739     }
03740 
03741     UINT32 DitherType = XARADITHER_NONE;    // request no dithering
03742     DIBConvert *pDoConvert = NULL;      // the convert DIB
03743 
03744     // Do some conversion using the DIBConvert class
03745     pDoConvert = DIBConvert::Create( pSourceInfoHeader->biBitCount, pDestInfoHeader->biBitCount,
03746                                      pSourceInfoHeader->biWidth, pLogPalette,  DitherType);
03747     // If this fails then exit now
03748     if (pDoConvert == NULL)
03749     {
03750         if (pLogPalette)
03751             CCFree(pLogPalette);
03752         return FALSE;
03753     }
03754     
03755     // Do the actual conversion process
03756     INT32 ChunkHeight = 16;     // We will do the conversion in chunks, in case we ask for dithering
03757     INT32 Height = pSourceInfoHeader->biHeight;
03758     INT32 SourceWidth = DIBUtil::ScanlineSize( pSourceInfoHeader->biWidth, pSourceInfoHeader->biBitCount ) * ChunkHeight;
03759     INT32 DestWidth = DIBUtil::ScanlineSize( pDestInfoHeader->biWidth, pDestInfoHeader->biBitCount ) * ChunkHeight;
03760     BOOL IsFirstStrip = TRUE;           // Whether we are on the first strip or not
03761     INT32 CurrentYPos = 0;              // current line number
03762     LPBYTE SourceData = pSourceBits;    // pointer to the source data
03763     LPBYTE DestData = *pDestBits;       // pointer to the destination data
03764     while (CurrentYPos < Height)
03765     { 
03766         // Work out the size of the export chunk left, normally ExportChunkHeight but
03767         // if at the end of export may be a small strip left.
03768         const UINT32 ThisBit = min( UINT32(Height - CurrentYPos), (UINT32)ChunkHeight );
03769         if (!pDoConvert->Convert( SourceData, DestData, ThisBit, IsFirstStrip ))
03770             return FALSE;                           // stop if conversion failed
03771 
03772         IsFirstStrip = FALSE;               // Done first strip
03773         SourceData  += SourceWidth;         // Move on by a lines worth
03774         DestData    += DestWidth;           // Move on by a lines worth
03775         CurrentYPos += INT32(ThisBit);      // Move down by a strips worth
03776     }
03777     
03778     // Put back the recommended palette by destructing the convert function.
03779     if (pDoConvert)
03780     {
03781         delete pDoConvert;
03782         pDoConvert = NULL;
03783     }   
03784 
03785     if (pLogPalette)
03786     {
03787         CCFree(pLogPalette);
03788         pLogPalette = NULL;
03789     }
03790 
03791     // If we got this far then more than likely we have waht we want
03792     return TRUE;
03793 }
03794 
03795 
03796 
03797 /********************************************************************************************
03798 
03799 >   static BOOL DIBUtil::Convert32to8(LPBITMAPINFO pSourceInfo, LPBYTE pSourceBits,
03800                                       LPBITMAPINFO *pDestInfo, LPBYTE *pDestBits)
03801 
03802     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
03803     Created:    02/08/2005
03804     Inputs:     pSourceInfo     - A information header for the bitmap to be copied
03805                 pSourceBits     - the actual bits for the bitmap to be copied
03806                 pPalette    - pointer to the palette in RGBTIPLE format to use when converting
03807                 NumberOfPaletteEntries - entries in this palette 
03808 
03809     Outputs:    pDestInfo       - pointer to the copied information block
03810                 pDestBits       - pointer ot the copied bits data
03811     
03812     Returns:    True if copied ok, false otherwise
03813     Purpose:    Generate an 8 bit form of a bitmap from a 32 bit form using the given palette.
03814 
03815 ********************************************************************************************/
03816 
03817 BOOL DIBUtil::Convert32to8( LPBITMAPINFO pSourceInfo, LPBYTE pSourceBits,
03818                             LPBITMAPINFO *pDestInfo, LPBYTE *pDestBits,
03819                             RGBTRIPLE *pPalette, UINT32 NumberOfPaletteEntries )
03820 {
03821     // In case of early set these return pointers to NULL
03822     *pDestInfo = NULL;
03823     *pDestBits = NULL;
03824 
03825     ERROR2IF(pSourceInfo == NULL || pSourceBits == NULL, FALSE, "DIBUtil::Convert32to8 bad source bitmap");
03826     ERROR2IF(pPalette == NULL || NumberOfPaletteEntries == 0, FALSE, "DIBUtil::Convert32to8 bad palette info");
03827 
03828     // Get a pointer to the useful bitmap header information for things like the size of the
03829     // bitmap and colour depth. 
03830     LPBITMAPINFOHEADER pSourceInfoHeader = &(pSourceInfo->bmiHeader); 
03831 
03832     ERROR2IF(pSourceInfoHeader->biBitCount != 32,FALSE,"DIBUtil::Convert32to8 bad source depth");
03833 
03834     // Try and allocate the detsination bitmap to be the same size and colour depth as the source
03835     *pDestInfo = AllocDIB( pSourceInfoHeader->biWidth, pSourceInfoHeader->biHeight,
03836                            8, pDestBits );
03837 
03838     // failed to allocate the bitmap so return false.
03839     if (*pDestInfo == NULL || *pDestBits == NULL )
03840         return FALSE;
03841 
03842     LPBITMAPINFOHEADER pDestInfoHeader = &((*pDestInfo)->bmiHeader); 
03843     
03844     // We will need the palette in LOGPALETTE for use in the conversion
03845     // We must allocate the palette to be the maximum size as otherwise people like Gavin
03846     // blow up
03847     LPLOGPALETTE pLogPalette = NULL;
03848     const UINT32 MaxColours = 256;
03849     pLogPalette = DIBUtil::AllocateLogPalette(MaxColours);
03850     if (pLogPalette == NULL)
03851         return FALSE;
03852 
03853     // Now copy the RGBTRIPLE palette into this and into the destination bitmap
03854     // Get a pointer to the palette in the destination bitmap
03855     LPRGBQUAD lpPalette = NULL;
03856     lpPalette = &((*pDestInfo)->bmiColors[0]);  // pointer to colours table
03857     //pLogPalette->palVersion = 0x300;
03858     pLogPalette->palNumEntries = NumberOfPaletteEntries;
03859     RGBTRIPLE *pPal = pPalette;
03860     for (UINT32 i = 0; i < NumberOfPaletteEntries; i++)
03861     {
03862         lpPalette->rgbRed = pPal->rgbtRed;
03863         pLogPalette->palPalEntry[i].peRed = pPal->rgbtRed;
03864         lpPalette->rgbGreen = pPal->rgbtGreen;
03865         pLogPalette->palPalEntry[i].peGreen = pPal->rgbtGreen;
03866         lpPalette->rgbBlue = pPal->rgbtBlue;
03867         pLogPalette->palPalEntry[i].peBlue = pPal->rgbtBlue;
03868         pLogPalette->palPalEntry[i].peFlags = 0x00;
03869         lpPalette->rgbReserved = 0x00;
03870         lpPalette++;
03871         pPal++;
03872     }
03873     // Fill in all other entries as black and do not use
03874     for (UINT32 i = NumberOfPaletteEntries; i < MaxColours; i++)
03875     {
03876         pLogPalette->palPalEntry[i].peRed   = 0x00;
03877         pLogPalette->palPalEntry[i].peGreen = 0x00;
03878         pLogPalette->palPalEntry[i].peBlue  = 0x00;
03879         pLogPalette->palPalEntry[i].peFlags = 0xFF;     // mark as do not use
03880         lpPalette->rgbRed       = 0x00;
03881         lpPalette->rgbGreen     = 0x00;
03882         lpPalette->rgbBlue      = 0x00;
03883         lpPalette->rgbReserved  = 0xFF; // mark as do not use
03884         lpPalette++;
03885     }
03886 
03887     UINT32 DitherType = XARADITHER_NONE;    // request no dithering
03888     DIBConvert *pDoConvert = NULL;      // the convert DIB
03889 
03890     // Do some conversion using the DIBConvert class
03891     pDoConvert = DIBConvert::Create( pSourceInfoHeader->biBitCount, pDestInfoHeader->biBitCount,
03892                                      pSourceInfoHeader->biWidth, pLogPalette,  DitherType);
03893     // If this fails then exit now
03894     if (pDoConvert == NULL)
03895     {
03896         if (pLogPalette)
03897             CCFree(pLogPalette);
03898         return FALSE;
03899     }
03900     
03901     // Do the actual conversion process
03902     INT32 ChunkHeight = 16;     // We will do the conversion in chunks, in case we ask for dithering
03903     INT32 Height = pSourceInfoHeader->biHeight;
03904     INT32 SourceWidth = DIBUtil::ScanlineSize( pSourceInfoHeader->biWidth, pSourceInfoHeader->biBitCount ) * ChunkHeight;
03905     INT32 DestWidth = DIBUtil::ScanlineSize( pDestInfoHeader->biWidth, pDestInfoHeader->biBitCount ) * ChunkHeight;
03906     BOOL IsFirstStrip = TRUE;           // Whether we are on the first strip or not
03907     INT32 CurrentYPos = 0;              // current line number
03908     LPBYTE SourceData = pSourceBits;    // pointer to the source data
03909     LPBYTE DestData = *pDestBits;       // pointer to the destination data
03910     while (CurrentYPos < Height)
03911     { 
03912         // Work out the size of the export chunk left, normally ExportChunkHeight but
03913         // if at the end of export may be a small strip left.
03914         const UINT32 ThisBit = min( UINT32(Height - CurrentYPos), (UINT32)ChunkHeight );
03915         if (!pDoConvert->Convert( SourceData, DestData, ThisBit, IsFirstStrip ))
03916             return FALSE;                           // stop if conversion failed
03917 
03918         IsFirstStrip = FALSE;               // Done first strip
03919         SourceData  += SourceWidth;         // Move on by a lines worth
03920         DestData    += DestWidth;           // Move on by a lines worth
03921         CurrentYPos += INT32(ThisBit);      // Move down by a strips worth
03922     }
03923     
03924     // Put back the recommended palette by destructing the convert function.
03925     if (pDoConvert)
03926     {
03927         delete pDoConvert;
03928         pDoConvert = NULL;
03929     }   
03930 
03931     if (pLogPalette)
03932     {
03933         CCFree(pLogPalette);
03934         pLogPalette = NULL;
03935     }
03936 
03937     // If we got this far then more than likely we have waht we want
03938     return TRUE;
03939 }
03940 
03941 
03942 
03943 /********************************************************************************************
03944 
03945 >   static BOOL DIBUtil::Convert8to32(LPBITMAPINFO pSourceInfo, LPBYTE pSourceBits, LPQUAD pPalette
03946                                       LPBITMAPINFO *pDestInfo, LPBYTE *pDestBits)
03947 
03948     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03949     Created:    14/2/2000
03950     Inputs:     pSourceInfo     - A information header for the bitmap to be copied
03951                 pSourceBits     - the actual bits for the bitmap to be copied
03952                 pPalette        - pointer to the palette 
03953                 pDestInfo       - pointer to an ALLOCATED bitmapinfo structure 
03954                 pDestBits       - pointer to an ALLOCATED 32bit bitmap
03955 
03956     Outputs:    pDestInfo       - pointer to the copied information block
03957                 pDestBits       - pointer ot the copied bits data
03958                 
03959     
03960     Returns:    True if copied ok, false otherwise
03961     Purpose:    Generates a 32bit form of the input 8bit bitmap, note that the destination 
03962                 bitmapinfo and bitmap must be allocated prior to this function
03963 
03964 ********************************************************************************************/
03965 
03966 BOOL DIBUtil::Convert8to32(LPBITMAPINFO pSourceInfo, LPBYTE pSourceBits, RGBQUAD* pPalette,
03967                                       LPBITMAPINFO pDestInfo, LPBYTE pDestBits)
03968 {
03969     ERROR2IF(pSourceBits == NULL, FALSE, "NULL source bitmap");
03970     ERROR2IF(pSourceInfo == NULL, FALSE, "NULL source info");
03971     ERROR2IF(pDestInfo == NULL, FALSE, "NULL destination info");
03972     ERROR2IF(pDestBits == NULL, FALSE, "Null destination bitmap");
03973     
03974     // most info will be the same so memcpy is the quickest way
03975     //memcpy(pSourceInfo, pDestInfo, sizeof(BITMAPINFO));
03976 
03977     // these will all be the same
03978     pDestInfo->bmiHeader.biSize          = sizeof(BITMAPINFOHEADER);
03979     pDestInfo->bmiHeader.biWidth         = pSourceInfo->bmiHeader.biWidth;
03980     pDestInfo->bmiHeader.biHeight        = pSourceInfo->bmiHeader.biHeight;
03981     pDestInfo->bmiHeader.biPlanes        = pSourceInfo->bmiHeader.biPlanes;
03982     pDestInfo->bmiHeader.biCompression   = pSourceInfo->bmiHeader.biCompression;
03983     pDestInfo->bmiHeader.biXPelsPerMeter = pSourceInfo->bmiHeader.biXPelsPerMeter;
03984     pDestInfo->bmiHeader.biYPelsPerMeter = pSourceInfo->bmiHeader.biYPelsPerMeter;
03985     pDestInfo->bmiHeader.biClrImportant  = 0;
03986 
03987     // get the size of the new bitmap
03988     INT32 size = pDestInfo->bmiHeader.biWidth *  pDestInfo->bmiHeader.biHeight * 4;
03989     
03990     //these will be different from source
03991     pDestInfo->bmiHeader.biBitCount         = 32;
03992     pDestInfo->bmiHeader.biSizeImage        = size;
03993     pDestInfo->bmiHeader.biClrUsed          = 0;
03994 
03995 
03996     // convert from 8 bit to 32 bit
03997     INT32 bmpsize = pSourceInfo->bmiHeader.biWidth * pSourceInfo->bmiHeader.biHeight;
03998     INT32 padding = pSourceInfo->bmiHeader.biWidth % 4;
03999     if (padding)
04000         padding = 4 - padding;
04001 
04002     LPBYTE pSource = pSourceBits;
04003     LPBYTE pDest = pDestBits;
04004     for (INT32 i = 0; i < bmpsize; i ++)
04005     {
04006         if (i && i % pSourceInfo->bmiHeader.biWidth == 0)
04007             pSource += padding;
04008         *pDest = pPalette[*pSource].rgbBlue; 
04009         pDest++;
04010         *pDest = pPalette[*pSource].rgbGreen; 
04011         pDest++;
04012         *pDest = pPalette[*pSource].rgbRed; 
04013         pDest++;
04014         *pDest = pPalette[*pSource].rgbReserved;
04015         pDest++;
04016         pSource++;
04017     }
04018     return TRUE;
04019 
04020 }
04021 
04022 /********************************************************************************************
04023 
04024 > static BOOL DIBUtil::ConvertTo8Greyscale(LPBITMAPINFO pSourceInfo,LPBYTE pSourceBits,
04025                               LPBITMAPINFO *ppDestInfo, LPBYTE *ppDestBits)
04026 
04027     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
04028     Created:    30/1/97
04029     Inputs:     pSourceInfo     - A information header for the bitmap to be copied
04030                 pSourceBits     - the actual bits for the bitmap to be copied
04031     Outputs:    pDestInfo       - pointer to the 8bpp greyscale information block
04032                 pDestBits       - pointer ot the 8bpp greyscale bits data
04033     
04034     Returns:    True if copied ok, false otherwise
04035     Purpose:    Generates an 8bpp greyscale bitmap from the given 1bpp, 4bpp or 8bpp bitmap
04036 
04037 ********************************************************************************************/
04038 
04039 BOOL DIBUtil::ConvertTo8Greyscale(LPBITMAPINFO pSourceInfo,LPBYTE pSourceBits,
04040                               LPBITMAPINFO *ppDestInfo, LPBYTE *ppDestBits)
04041 {
04042     if (pSourceInfo == NULL || pSourceBits == NULL || ppDestInfo == NULL || ppDestBits == NULL)
04043     {
04044         ERROR3("Null parameters");
04045         return FALSE;
04046     }
04047 
04048     // Get useful source bitmap info
04049     UINT32 Width   = pSourceInfo->bmiHeader.biWidth;
04050     UINT32 Height  = pSourceInfo->bmiHeader.biHeight;
04051     UINT32 Depth     = pSourceInfo->bmiHeader.biBitCount;
04052 
04053     // Calc number of colours in the palette
04054     UINT32 NumCols = 0;
04055     switch (Depth)
04056     {
04057         case 1: NumCols = 2;  break;
04058         case 4: NumCols = 16; break;
04059         case 8: NumCols = 256; break;
04060         case 16: break;
04061         case 24: break;
04062         case 32: break;
04063         default:
04064             ERROR3("Routine can't cope");
04065             return FALSE;
04066             break;
04067     }
04068 
04069     // Create the destination 8bpp bitmap, & check it all worked
04070     *ppDestInfo = AllocDIB(Width,Height, 8, ppDestBits);
04071     if (*ppDestInfo == NULL || *ppDestBits == NULL)
04072         return FALSE;
04073 
04074     // We need a lookup table that maps the give bitmap's palette to the 256 greyscale palette
04075     BYTE LookUp[256];
04076 
04077     if (NumCols > 0)
04078     {
04079         // Generate the greyscale lookup table.
04080         for (UINT32 i=0;i < NumCols;i++)
04081         {
04082             // Get the RGB components of this palette entry
04083             double R = pSourceInfo->bmiColors[i].rgbRed;
04084             double G = pSourceInfo->bmiColors[i].rgbGreen;
04085             double B = pSourceInfo->bmiColors[i].rgbBlue;
04086 
04087             // Calculate the intensity of the palette entry - this maps onto a greyscale palette entry
04088             BYTE C = BYTE((R * 0.305) + (G * 0.586) + (B * 0.109));
04089 
04090             // For each pixel that references palette entry 'i', map it onto greyscale palette entry 'C'
04091             LookUp[i] = C;
04092         }
04093     }
04094 
04095     // Calc number of bytes in each scan line
04096     UINT32 SourceScanLineLength = DIBUtil::ScanlineSize(Width,Depth);
04097     UINT32 DestScanLineLength   = DIBUtil::ScanlineSize(Width,8);
04098 
04099     // Run through the pixels of the source, and create the pixels of the destination
04100     UINT32 x,y ;
04101     BYTE* pSourcePixel = pSourceBits ;
04102     BYTE*   pDestPixel = *ppDestBits ;
04103     switch (Depth)
04104     {
04105     case 1:
04106         for ( y = 0; y < Height; y++ )
04107         {
04108             BYTE* pSource = pSourcePixel ;
04109             BYTE Pixel;
04110             BYTE SourceBitMask = 0x80;
04111             for ( x = 0; x < Width; x++ )
04112             {
04113                 // If the current bit is set, the pixel is 1, else 0
04114                 if (*pSource & SourceBitMask)
04115                     Pixel = 1;
04116                 else
04117                     Pixel = 0;
04118                 // Look up the greyscale byte value for the 'Pixel' entry in the source palette
04119                 pDestPixel[x] = LookUp[Pixel];
04120                 SourceBitMask >>= 1;        // Shift mask for next bit
04121                 if (SourceBitMask==0)
04122                 {
04123                     // Got last bit out of that byte, so reset mask and inc ptr to next byte
04124                     SourceBitMask = 0x80;
04125                     pSource++;
04126                 }
04127             }
04128             pSourcePixel += SourceScanLineLength ;
04129               pDestPixel +=   DestScanLineLength ;
04130         }
04131         break ;
04132 
04133     case 4:
04134         for ( y = 0; y < Height; y++ )
04135         {
04136             BYTE* pSource = pSourcePixel ;
04137             for ( x=0 ; x<Width ; x+=2 )
04138             {
04139                 // Look up the greyscale byte value for the pixel entries in the source palette
04140                 pDestPixel[x  ] = LookUp[*pSource >> 4] ;
04141                 pDestPixel[x+1] = LookUp[*pSource & 0xF] ;
04142                 pSource++;
04143             }
04144             pSourcePixel += SourceScanLineLength ;
04145               pDestPixel +=   DestScanLineLength ;
04146         }
04147         break ;
04148 
04149     case 8:
04150         for ( y=0 ; y<Height ; y++ )
04151         {
04152             // Look up the greyscale byte values for the pixel entries in the source palette
04153             for ( x=0 ; x<Width ; x++ )
04154                 pDestPixel[x] = LookUp[pSourcePixel[x]];
04155             pSourcePixel += SourceScanLineLength ;
04156               pDestPixel +=   DestScanLineLength ;
04157         }
04158         break ;
04159 
04160     case 16:
04161         for ( y=0 ; y<Height ; y++ )
04162         {
04163             WORD* pSrc = (WORD*)pSourcePixel;
04164             // Convert the pixel to greyscale and store
04165             for ( x=0 ; x<Width ; x++ )
04166             {
04167                 // 16bpp pixel value is pSrc[x]
04168                 BYTE Grey = 0xFF;
04169                 pDestPixel[x] = Grey;
04170                 pSrc++;
04171             }
04172             pSourcePixel += SourceScanLineLength ;
04173               pDestPixel +=   DestScanLineLength ;
04174         }
04175         break;
04176 
04177     case 24:
04178         for ( y=0 ; y<Height ; y++ )
04179         {
04180             BYTE* pSrc = pSourcePixel;
04181             // Convert the pixel to greyscale and store
04182             for ( x=0 ; x<Width ; x++ )
04183             {
04184                 // 24bpp pixel is 
04185                 BYTE Grey = (pSrc[2] * 78 + pSrc[1] * 150 + pSrc[0] * 28) >> 8;
04186                 pDestPixel[x] = Grey;
04187                 pSrc += 3;
04188             }
04189             pSourcePixel += SourceScanLineLength ;
04190               pDestPixel +=   DestScanLineLength ;
04191         }
04192         break;
04193 
04194     case 32:
04195         for ( y=0 ; y<Height ; y++ )
04196         {
04197             // Convert the pixels to greyscale as if they are rendered on a white 
04198             // background and store
04199             BGRT* pSrc = (BGRT*)pSourcePixel;
04200             for ( x=0 ; x<Width ; x++ )
04201             {
04202                 const BYTE Trans = pSrc->Transparency;
04203                 const BYTE Alpha = 255 - Trans;
04204                 BYTE Grey = (pSrc->Red * 78 + pSrc->Green * 150 + pSrc->Blue * 28) >> 8;
04205                 pDestPixel[x] = ((Grey * Alpha) + (255 * Trans)) / 255;
04206                 pSrc++;
04207             }
04208             pSourcePixel += SourceScanLineLength ;
04209               pDestPixel +=   DestScanLineLength ;
04210         }
04211         break;
04212     }
04213 
04214 //  BOOL ok = GenGreyscalePalette((*ppDestInfo)->bmiColors,256);
04215 
04216     return TRUE;
04217 }
04218 
04219 
04220 /********************************************************************************************
04221 
04222 >   static OILBitmap* DIBUtil::Create8bppGreyscaleBitmap(KernelBitmap* pSrcBitmap)
04223 
04224     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
04225     Created:    29/1/97
04226     Inputs:     pSrcBitmap = ptr to a kernel bitmap
04227     Returns:    ptr to an Oil bitmap containing an 8bpp greyscale image
04228     Purpose:    Designed to be used to create an 8bpp greyscale bitmap from a 24bpp, 4bpp or 1bpp bitmaps
04229 
04230                 It will do nothing if the bitmap is already an 8bpp bitmap.
04231                 In this case you should copy the kernel bitmap and call GenerateGreyscaleTable() on
04232                 the copy.
04233 
04234 ********************************************************************************************/
04235 
04236 OILBitmap* DIBUtil::Create8bppGreyscaleBitmap(KernelBitmap* pSrcBitmap)
04237 {
04238     OILBitmap* pOilBitmap = pSrcBitmap->GetActualBitmap();
04239     ERROR2IF(pOilBitmap == NULL,NULL,"null OIL bitmap present!");
04240 
04241     // Try to import bitmap as usual binary BMP file.
04242     CWxBitmap* pCWxBitmap = (CWxBitmap*)pOilBitmap;
04243     ERROR2IF(pCWxBitmap == NULL,NULL,"null WINOIL bitmap present!");
04244     
04245     LPBITMAPINFO pSourceInfo    = pCWxBitmap->BMInfo;
04246     LPBYTE pSourceBits          = pCWxBitmap->BMBytes;
04247     
04248     LPBITMAPINFO pDestInfo      = NULL;
04249     LPBYTE pDestBits            = NULL;
04250 
04251     BOOL ok = FALSE;
04252 
04253     switch (pSrcBitmap->GetBPP())
04254     {
04255         case 1:
04256         case 4:
04257         case 8:
04258         case 24:
04259         case 32:
04260             ok = ConvertTo8Greyscale(pSourceInfo, pSourceBits, &pDestInfo, &pDestBits);
04261             break;
04262 
04263         default:
04264             ERROR3("How many bits? No chance mate");
04265             return NULL;
04266             break;
04267     }
04268 
04269     OILBitmap* pResultBitmap = NULL;
04270 
04271     if (ok)
04272     {
04273         // Create a new CWxBitmap to contain this data
04274         pResultBitmap = (OILBitmap*) new CWxBitmap(pDestInfo, pDestBits);
04275         if (pResultBitmap == NULL)
04276             FreeDIB( pDestInfo, pDestBits );
04277     }
04278 
04279     return pResultBitmap;
04280 }
04281 
04282 
04283 /********************************************************************************************
04284 
04285 >   static BOOL DIBUtil::GenerateDifferenceBitmap(LPBITMAPINFO pPreviousInfo,LPBYTE pPreviousBits,
04286                                                   LPBITMAPINFO pCurrentInfo,LPBYTE pCurrentBits,
04287                                                   LPBITMAPINFO *ppDestInfo, LPBYTE *ppDestBits,
04288                                                   INT32 TransColour,
04289                                                   BOOL * pFoundBadOverlay = NULL)
04290     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
04291     Created:    12/5/97
04292     Inputs:     pPreviousInfo   - A information header for the bitmap of the previous frame
04293                 pPreviousBits   - the actual bits for the bitmap of the previous frame
04294                 pCurrentInfo    - pointer to the information block for the present frame
04295                 pCurrentBits    - pointer to the bits data for the present frame
04296     Outputs:    pDestInfo       - pointer to the information block for the differenced frame
04297                 pDestBits       - pointer to the bits data for the differenced frame
04298                 pFoundBadOverlay - True if we cannot overlay the previous frame 
04299     Returns:    True if copied ok, false otherwise
04300     Purpose:    We need to work out the smallest possible bitmap that needs to be output.
04301                 Therefore, assuming that the previous bitmap or frame is the one given and
04302                 given the present frame, then work out the differences between the two and 
04303                 replace data which is the same with the specified transparent colour. This
04304                 means these similar bits should compress well.
04305     Note:       This will return a new destination bitmap which is the difference between the
04306                 two input bitmaps. It will be up to the caller to free up this data.
04307 
04308 ********************************************************************************************/
04309 
04310 BOOL DIBUtil::GenerateDifferenceBitmap(LPBITMAPINFO pPreviousInfo,LPBYTE pPreviousBits,
04311                                        LPBITMAPINFO pCurrentInfo,LPBYTE pCurrentBits,
04312                                        LPBITMAPINFO *ppDestInfo, LPBYTE *ppDestBits, INT32 TransColour,
04313                                        BOOL * pFoundBadOverlay)
04314 {
04315     ERROR2IF(pPreviousInfo == NULL || pPreviousBits == NULL,FALSE,"GenerateDifferenceBitmap Bad previous pointers!" );
04316     ERROR2IF(pCurrentInfo == NULL || pCurrentBits == NULL,FALSE,"GenerateDifferenceBitmap Bad current pointers!" );
04317     ERROR2IF(ppDestInfo == NULL || ppDestBits == NULL,FALSE,"GenerateDifferenceBitmap Bad destination pointers!" );
04318 
04319     if (TransColour < 0 || TransColour > 256)
04320     {
04321         TRACEUSER( "Neville", wxT("GenerateDifferenceBitmap Bad transparent colour\n") );
04322         // return TRUE so that we do not fail
04323         return TRUE;
04324     }
04325 
04326     // Get useful source bitmap info
04327     UINT32 Width   = pPreviousInfo->bmiHeader.biWidth;
04328     UINT32 Height  = pPreviousInfo->bmiHeader.biHeight;
04329     UINT32 Depth     = pPreviousInfo->bmiHeader.biBitCount;
04330 
04331     // Get useful destination bitmap info
04332     UINT32 CurrentWidth   = pCurrentInfo->bmiHeader.biWidth;
04333     UINT32 CurrentHeight  = pCurrentInfo->bmiHeader.biHeight;
04334     UINT32 CurrentDepth  = pCurrentInfo->bmiHeader.biBitCount;
04335 
04336     // We can only check bitmaps that are the same size and colour depth
04337     if (Width != CurrentWidth || Height != CurrentHeight || Depth != CurrentDepth)
04338     {
04339         TRACEUSER("Neville", wxT("GenerateDifferenceBitmap Source and destination bitmaps different sizes and/or depths\n") );
04340         // return TRUE so that we do not fail
04341         return TRUE;
04342     }
04343 
04344     // At present, can only check bitmaps that are 8bpp
04345     if (Depth != 8)
04346     { 
04347         TRACEUSER( "Neville", wxT("GenerateDifferenceBitmap Bitmap colour depth is not supported\n") );
04348         // return TRUE so that we do not fail
04349         return TRUE;
04350     }
04351 
04352     // We need to allocate the destination bitmap, so go and do that now
04353     // The easiest way is to produce an exact copy of the present bitmap
04354     BOOL ok = DIBUtil::CopyEntireBitmap(pCurrentInfo, pCurrentBits, ppDestInfo, ppDestBits);
04355     // If this failed then get out now
04356     if (!ok || *ppDestInfo == NULL || *ppDestBits == NULL)
04357         return FALSE;
04358 
04359     UINT32 ScanLineSize     = DIBUtil::ScanlineSize( Width, Depth );
04360     LPBYTE pPreviousData    = pPreviousBits;
04361     LPBYTE pCurrentData     = pCurrentBits;
04362     LPBYTE pDestData        = *ppDestBits;
04363     BOOL BadOverlay         = FALSE;
04364     for (UINT32 y = 0; y < Height && !BadOverlay; y++)
04365     {
04366         for (UINT32 x = 0; x < Width && !BadOverlay; x++)
04367         {
04368             // If the source and destination pixels are the same then
04369             // set the destination pixel to be the transparent colour
04370             if (pPreviousData[x] == pCurrentData[x])
04371                 pDestData[x] = TransColour & 0xFF;
04372             // If the current frame has a transparent pixel and we have a 
04373             // non-transparent pixel in the previous frame then we must
04374             // stop and use a replace background type
04375             else if (pCurrentData[x] == (TransColour & 0xFF))
04376             {
04377                 BadOverlay = TRUE;
04378                 break;
04379             }
04380         }
04381 
04382         // move onto the next scanline in each bitmap
04383         pPreviousData   += ScanLineSize;
04384         pCurrentData    += ScanLineSize;
04385         pDestData       += ScanLineSize;
04386     }
04387 
04388     // return the state of the bad overlay to the caller if they required it
04389     if (pFoundBadOverlay)
04390     {
04391         *pFoundBadOverlay = BadOverlay;
04392         
04393         if (BadOverlay)
04394         {
04395             // remove the diff bitmap
04396             if (*ppDestInfo && *ppDestBits)
04397             {
04398                 FreeDIB(*ppDestInfo, *ppDestBits);
04399                 *ppDestInfo = NULL;
04400                 *ppDestBits = NULL;
04401             }
04402         }
04403     }
04404 
04405     // everything went ok
04406     return TRUE;
04407 }
04408 
04409 /********************************************************************************************
04410 
04411 >   static BOOL DIBUtil::GenerateSubRegionBitmap(LPBITMAPINFO pSourceInfo,LPBYTE pSourceBits,
04412                                                  LPBITMAPINFO *ppDestInfo, LPBYTE *ppDestBits, INT32 TransColour,
04413                                                  UINT32 *pLeftOffset, UINT32 *pTopOffset)
04414     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
04415     Created:    12/5/97
04416     Inputs:     pSourceInfo     - A information header for the bitmap of the previous frame
04417                 pSourceBits     - the actual bits for the bitmap of the previous frame
04418                 pDestInfo       - pointer to the information block for the present frame
04419                 pDestBits       - pointer to the bits data for the present frame
04420     Outputs:    pDestInfo       - pointer to the information block for the differenced frame
04421                 pDestBits       - pointer to the bits data for the differenced frame
04422                 pLeftOffset     - the amount of whole columns we stripped from the left hand side
04423                 pTopOffset      - the amount of whole rows we stripped from the top
04424     Returns:    True if copied ok, false otherwise
04425     Purpose:    We need to work out the smallest possible bitmap that needs to be output.
04426                 Therefore, given the present frame or bitmap, then work out the smallest
04427                 possible bitmap that we can output which will be bordered on all four sides
04428                 by the given transparent colour i.e. can we strip complete left hand side
04429                 columns off the bitmap as they are all the transparent colour? Can we do the
04430                 same for the furthest right hand side columns and the top most and bottom
04431                 most rows.
04432 
04433 ********************************************************************************************/
04434 
04435 BOOL DIBUtil::GenerateSubRegionBitmap(LPBITMAPINFO pSourceInfo,LPBYTE pSourceBits,
04436                                       LPBITMAPINFO *ppDestInfo, LPBYTE *ppDestBits, INT32 TransColour,
04437                                       UINT32 *pLeftOffset, UINT32 *pTopOffset)
04438 {
04439     ERROR2IF(pSourceInfo == NULL || pSourceBits == NULL,FALSE,"GenerateSubRegionBitmap Bad source pointers!" );
04440     ERROR2IF(ppDestInfo == NULL || ppDestBits == NULL,FALSE,"GenerateSubRegionBitmap Bad destination pointers!" );
04441     ERROR2IF(pLeftOffset == NULL || pTopOffset == NULL,FALSE,"GenerateSubRegionBitmap Bad offset pointers!" );
04442 
04443     if (TransColour < 0 || TransColour > 255)
04444     {
04445         TRACEUSER( "Neville", wxT("GenerateSubRegionBitmap Bad transparent colour\n") );
04446         // return TRUE so that we do not fail
04447         return TRUE;
04448     }
04449 
04450     // Get useful source bitmap info
04451     UINT32 Width   = pSourceInfo->bmiHeader.biWidth;
04452     UINT32 Height  = pSourceInfo->bmiHeader.biHeight;
04453     UINT32 Depth     = pSourceInfo->bmiHeader.biBitCount;
04454 
04455     // At present, can only check bitmaps that are 8bpp
04456     if (Depth != 8)
04457     {
04458         TRACEUSER( "Neville", wxT("GenerateSubRegionBitmap Bitmap colour depth is not supported\n") );
04459         // return TRUE so that we do not fail
04460         return TRUE;
04461     }
04462 
04463     UINT32 ScanLineSize     = DIBUtil::ScanlineSize( Width, Depth );
04464 
04465     //-------------
04466     // Scan through from the left hand side finding any columns that we can remove
04467     // Start in an illegal position so we can note any changes
04468     INT32 LeftMostData = -1;
04469     LPBYTE pSourceData  = pSourceBits;
04470     LPBYTE pPixel = NULL;
04471     BOOL FoundClearColumn = TRUE;
04472     for (UINT32 x = 0; x < Width; x++)
04473     {
04474         for (UINT32 y = 0; y < Height; y++)
04475         {
04476             // Check the next pixel in sequence
04477             pPixel = pSourceData + y * ScanLineSize + x;
04478             // If the pixel is not transparent then stop the search now
04479             if (*pPixel != (TransColour & 0xFF))
04480             {
04481                 FoundClearColumn = FALSE;
04482                 break;
04483             }
04484         }
04485         
04486         // If we found a full clear column then note this as a new left hand position
04487         // and move onto the next
04488         if (FoundClearColumn)
04489             LeftMostData = x;
04490         else
04491             break;
04492     }
04493 
04494     //-------------
04495     // Scan through from the right hand side finding any columns that we can remove
04496     // Start in an illegal position so we can note any changes
04497     UINT32 RightMostData = Width;
04498     pSourceData = pSourceBits;
04499     FoundClearColumn = TRUE;
04500     for( UINT32 x = Width - 1; x >= 0 ; x-- )
04501     {
04502         for (UINT32 y = 0; y < Height; y++)
04503         {
04504             // Check the next pixel in sequence
04505             pPixel = pSourceData + y * ScanLineSize + x;
04506             // If the pixel is not transparent then stop the search now
04507             if (*pPixel != (TransColour & 0xFF))
04508             {
04509                 FoundClearColumn = FALSE;
04510                 break;
04511             }
04512         }
04513         
04514         // If we found a full clear column then note this as a new right hand position
04515         // and move onto the next
04516         if (FoundClearColumn)
04517             RightMostData = x;
04518         else
04519             break;
04520     }
04521 
04522     //-------------
04523     // Scan through from the top finding any rows that we can remove
04524     // Start in an illegal position so we can note any changes
04525     // REMEMBER bitmaps are stored from bottom line downwards in memory 
04526     INT32 TopMostData = -1;
04527     pSourceData = pSourceBits + (Height - 1) * ScanLineSize;
04528     BOOL FoundClearRow = TRUE;
04529     for (UINT32 y = 0; y < Height; y++)
04530     {
04531         for (UINT32 x = 0; x < Width; x++)
04532         {
04533             // If the pixel is not transparent then stop the search now
04534             if (pSourceData[x] != (TransColour & 0xFF))
04535             {
04536                 FoundClearRow = FALSE;
04537                 break;
04538             }
04539         }
04540 
04541         // If we found a full clear column then note this as a new top position
04542         // and move onto the next
04543         if (FoundClearRow)
04544             TopMostData = y;
04545         else
04546             break;
04547 
04548         // move onto the next scanline in each bitmap
04549         pSourceData -= ScanLineSize;
04550     }
04551 
04552     //-------------
04553     // Scan through from the bottom finding any rows that we can remove
04554     // Start in an illegal position so we can note any changes
04555     UINT32 BottomMostData = Height;
04556     pSourceData = pSourceBits;
04557     FoundClearRow = TRUE;
04558     for (UINT32 y = Height - 1; y >= 0; y--)
04559     {
04560         for (UINT32 x = 0; x < Width; x++)
04561         {
04562             // If the pixel is not transparent then stop the search now
04563             if (pSourceData[x] != (TransColour & 0xFF))
04564             {
04565                 FoundClearRow = FALSE;
04566                 break;
04567             }
04568         }
04569 
04570         // If we found a full clear row then note this as a new bottom hand position
04571         // and move onto the next
04572         if (FoundClearRow)
04573             BottomMostData = y;
04574         else
04575             break;
04576 
04577         // move onto the next scanline in each bitmap
04578         pSourceData += ScanLineSize;
04579     }
04580 
04581     TRACEUSER("Neville", wxT("width = %d, left offset = %d, right offset = %d\n"), Width, LeftMostData,RightMostData);
04582     TRACEUSER("Neville", wxT("height = %d, top offset = %d, bottom offset = %d\n"), Height, TopMostData,BottomMostData);
04583 
04584     // We have detected that we can sub-region this bitmap
04585     if (LeftMostData >= 0 || RightMostData < Width || TopMostData >= 0 || BottomMostData < Height)
04586     {
04587         UINT32 LeftOffset = 0;
04588         if (LeftMostData > 0)
04589             LeftOffset = LeftMostData;
04590         UINT32 RightOffset = Width - 1;
04591         if (RightMostData < Width - 1)
04592             RightOffset = RightMostData;
04593         // sanity check to see if the offsets are crossed over
04594         if (RightOffset < LeftOffset)
04595             RightOffset = LeftOffset;
04596 
04597         UINT32 TopOffset = 0;
04598         if (TopMostData > 0)
04599             TopOffset = TopMostData;
04600         UINT32 BottomOffset = Height - 1;
04601         if (BottomMostData < Height - 1)
04602             BottomOffset = BottomMostData;
04603         // sanity check to see if the offsets are crossed over
04604         if (BottomOffset < TopOffset)
04605             BottomOffset = TopOffset;
04606 
04607         UINT32 NewWidth = RightOffset - LeftOffset + 1;
04608         UINT32 NewHeight = BottomOffset - TopOffset + 1;
04609 
04610         TRACEUSER("Neville", wxT("Creating sub-region bitmap new height = %d, new width = %d\n"), NewWidth,NewHeight);
04611 
04612         // Create the new sized bitmap && check it all worked
04613         LPBYTE pBits = NULL;
04614         LPBITMAPINFO pInfo = AllocDIB(NewWidth, NewHeight, Depth, &pBits);
04615         if (pInfo == NULL || pBits == NULL)
04616             return FALSE;
04617 
04618         // Ensure remaining info header entries are correct
04619         LPBITMAPINFOHEADER pSourceInfoHeader = &(pSourceInfo->bmiHeader);
04620         LPBITMAPINFOHEADER pDestInfoHeader  = &(pInfo->bmiHeader); 
04621         pDestInfoHeader->biPlanes           = pSourceInfoHeader->biPlanes;
04622         pDestInfoHeader->biCompression      = pSourceInfoHeader->biCompression;
04623         pDestInfoHeader->biXPelsPerMeter    = pSourceInfoHeader->biXPelsPerMeter;
04624         pDestInfoHeader->biYPelsPerMeter    = pSourceInfoHeader->biYPelsPerMeter;
04625         pDestInfoHeader->biClrImportant     = pSourceInfoHeader->biClrImportant;
04626         pDestInfoHeader->biClrUsed          = pSourceInfoHeader->biClrUsed;
04627 
04628         // Ensure that the palette information is copied across
04629         LPRGBQUAD pSourcePalette = &(pSourceInfo->bmiColors[0]);
04630         LPRGBQUAD pDestPalette = &(pInfo->bmiColors[0]);
04631         UINT32 NumberOfColours = pSourceInfoHeader->biClrUsed; 
04632         // If we have zero colours on a bitmap which is 8bpp or less then this is bad.
04633         // This should be translated as the maximum number of colours allowed
04634         if (pSourceInfoHeader->biBitCount <= 8 && NumberOfColours == 0)
04635             NumberOfColours = 1 << pSourceInfoHeader->biBitCount;
04636         CopyPalette(pSourcePalette, pDestPalette, NumberOfColours);
04637 
04638         // Now copy the bitmap data across to the new bitmap
04639         UINT32 DestScanLineSize = DIBUtil::ScanlineSize(NewWidth, Depth);
04640         // Move the pointers to the top of the bitmaps in memory
04641         LPBYTE pSourceData = pSourceBits + (Height - 1) * ScanLineSize;
04642         LPBYTE pDestData = pBits + (NewHeight - 1) * DestScanLineSize;
04643         for (UINT32 y = TopOffset; y <= BottomOffset; y++)
04644         {
04645             LPBYTE pThisSourceData  = pSourceData - (y * ScanLineSize) + LeftOffset;
04646             LPBYTE pThisDestData    = pDestData - ((y - TopOffset) * DestScanLineSize);
04647             memcpy(pThisDestData, pThisSourceData, NewWidth);
04648         }
04649 
04650         // remove the old bitmap
04651         if (*ppDestInfo && *ppDestBits)
04652             FreeDIB(*ppDestInfo, *ppDestBits);
04653         
04654         // return the new bitmap to the caller
04655         *ppDestInfo = pInfo;
04656         *ppDestBits = pBits;
04657 
04658         // return the left and top most positions to the caller
04659         *pLeftOffset = LeftOffset;
04660         *pTopOffset = TopOffset;
04661         TRACEUSER( "Neville",wxT("Creating sub-region bitmap left offset = %d, top offset = %d\n"),LeftOffset,TopOffset);
04662     }
04663     
04664     return TRUE;
04665 }
04666 
04667 
04668 /********************************************************************************************
04669 
04670 >   static LPLOGPALETTE DIBUtil::AllocateLogPalette(const UINT32 PaletteSize)
04671 
04672     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
04673     Created:    03/07/97
04674     Inputs:     The number of entries in the palette
04675     Returns:    A pointer to the allocated LOGPALETTE or null.
04676     Purpose:    To allocate a LOGPALETTE ready for use.
04677                 The caller is responsible for cleaning up the memmory allocation
04678 
04679 ********************************************************************************************/
04680 
04681 LPLOGPALETTE DIBUtil::AllocateLogPalette(const UINT32 PaletteSize)
04682 {
04683     ERROR2IF(PaletteSize == 0 || PaletteSize > 256,NULL,"AllocateLogPalette Bad PaletteSize");
04684 
04685     LPLOGPALETTE pPalette = NULL;
04686     const size_t TotalPal = sizeof(LOGPALETTE) + ( sizeof(PALETTEENTRY) * PaletteSize );
04687     pPalette = (LPLOGPALETTE)CCMalloc( TotalPal );
04688     if (pPalette == NULL)
04689         return NULL;
04690 
04691     pPalette->palNumEntries     = PaletteSize;
04692     pPalette->palVersion        = 0x300;
04693     return pPalette;
04694 }
04695 
04696 /********************************************************************************************
04697 
04698 >   static LPLOGPALETTE DIBUtil::CopyBitmapPaletteIntoLogPalette(KernelBitmap * pBitmap)
04699 
04700     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
04701     Created:    09/07/97
04702     Inputs:     The bitmap to copy the palette from
04703     Returns:    A pointer to the allocated LOGPALETTE or null.
04704     Purpose:    To allocate a LOGPALETTE and then copy the palette from inside the bitmap
04705                 across to the LOGPALETTE.
04706                 The caller is responsible for cleaning up the memmory allocation
04707 
04708 ********************************************************************************************/
04709 
04710 LPLOGPALETTE DIBUtil::CopyBitmapPaletteIntoLogPalette(KernelBitmap * pBitmap)
04711 {
04712     ERROR2IF(pBitmap == NULL,NULL,"CopyBitmapPaletteIntoLogPalette Bad bitmap");
04713 
04714     LPRGBQUAD       pPal    = pBitmap->GetPaletteForBitmap();
04715     UINT32          Bpp     = pBitmap->GetBPP();
04716     UINT32          PaletteSize = 1U<<Bpp;
04717     LPLOGPALETTE    pLogPal = NULL;
04718 
04719     // Bitmaps with more than 256 colours in usually do not require a palette
04720     if (Bpp > 8 || pPal == NULL)
04721     {
04722         ERROR2(NULL,"CopyBitmapPaletteIntoLogPalette bitmap has no palette");
04723         //return NULL;
04724     }
04725 
04726     pLogPal = DIBUtil::AllocateLogPalette(PaletteSize);
04727     if (pLogPal == NULL)
04728         return NULL;
04729     
04730     UINT32          ColoursInPal    = pBitmap->GetNumPaletteEntries();
04731     UINT32          ColoursInLogPal = pLogPal->palNumEntries;
04732     PALETTEENTRY*   pPaletteEntry   = pLogPal->palPalEntry;
04733     for (UINT32 i = 0; i < ColoursInLogPal; i++)
04734     {
04735         if (i > ColoursInPal)
04736         {
04737             // Force any unused colours to be do not use black
04738             pPaletteEntry[i].peBlue     = 0;
04739             pPaletteEntry[i].peGreen    = 0;
04740             pPaletteEntry[i].peRed      = 0;
04741 
04742             pPaletteEntry[i].peFlags    = 0xFF;
04743         }
04744         else
04745         {
04746             pPaletteEntry[i].peBlue     = pPal[i].rgbBlue;
04747             pPaletteEntry[i].peGreen    = pPal[i].rgbGreen;
04748             pPaletteEntry[i].peRed      = pPal[i].rgbRed;
04749 
04750             pPaletteEntry[i].peFlags    = 0x00;
04751         }
04752     }
04753 
04754     // Now fill in the actually number of palette entries
04755     // We must allocate the palette to be full sized as otherwise GDraw/CDraw will
04756     // more than likely fall over.
04757     pLogPal->palNumEntries = ColoursInPal;
04758 
04759     return pLogPal;
04760 }
04761 
04762 /********************************************************************************************
04763 
04764 >   static BOOL DIBUtil::IsGreyscaleBitmap(KernelBitmap * pKB);
04765                     
04766     Author:     Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com>
04767     Created:    28/01/95
04768     Inputs:     pKB the bitmap to operate on
04769     Outputs:    None
04770     Returns:    TRUE if a 8bit GS bitmap else FALSE
04771     Purpose:    Determines whether or not a bitmap is 32bpp
04772     Errors:     None
04773     Scope:      Public
04774     SeeAlso:    BfxALU::MakeGreyscale, BFXALU::MakeGreyscale32to8
04775     Note:       Transferred from bfxalu 10/11/97 Neville
04776 
04777 This routine returns false if the bitmap is not a correctly formed 8 bpp bitmap. It does
04778 not return or set errors
04779 
04780 ********************************************************************************************/
04781 
04782 BOOL DIBUtil::IsGreyscaleBitmap(KernelBitmap * pKB)
04783 {
04784     if ( (!pKB) || (!pKB->ActualBitmap) )
04785         return FALSE;
04786 
04787     return IsGreyscaleBitmap(pKB->ActualBitmap);
04788 }
04789 
04790 /********************************************************************************************
04791 
04792 >   static BOOL DIBUtil::IsGreyscaleBitmap(OILBitmap * pKB);
04793                     
04794     Author:     Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com>
04795     Created:    28/01/95
04796     Inputs:     pKB the bitmap to operate on
04797     Outputs:    None
04798     Returns:    TRUE if a 8bit GS bitmap else FALSE
04799     Purpose:    Determines whether or not a bitmap is 32bpp
04800     Errors:     None
04801     Scope:      Public
04802     SeeAlso:    BfxALU::MakeGreyscale, BFXALU::MakeGreyscale32to8
04803     Note:       Transferred from bfxalu 10/11/97 Neville
04804 
04805 This routine returns false if the bitmap is not a correctly formed 8 bpp bitmap. It does
04806 not return or set errors
04807 
04808 ********************************************************************************************/
04809 
04810 BOOL DIBUtil::IsGreyscaleBitmap(OILBitmap * pOilBmp)
04811 {
04812     if ( (!pOilBmp) || (!pOilBmp->IsKindOf(CC_RUNTIME_CLASS(CWxBitmap))) )
04813         return FALSE;
04814 
04815     BITMAPINFOHEADER * pBMI=&(((CWxBitmap *)pOilBmp)->BMInfo->bmiHeader);
04816     if ((pBMI->biBitCount!=8) || (pBMI->biClrUsed!=0x100)) return FALSE;
04817     DWORD * pPal = (DWORD *)(void *)(pBMI +1 /*ptr arith*/);
04818     for (DWORD x=0; x<0x100; x++) if ((pPal[x]&0x00ffffff) != (x|(x<<8)|(x<<16))) return FALSE;
04819     return TRUE;
04820 }
04821 
04822 
04823 /********************************************************************************************
04824 
04825 >   static void DIBUtil::InvertAlpha ( LPBITMAPINFO lpBitmapInfo,
04826                                           LPBYTE        lpBits )
04827 
04828     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
04829     Created:    27/6/00 (moved here by Phil 06/02/2004)
04830     Purpose:    Camelot uses a different transparency scheme to the rest of the world, in
04831                 that 255 is clear, and 0 is opaque. Until the rest of the world catches up,
04832                 it's necessary to invert the alpha channel to make exported files compatible
04833                 with other programs.
04834 
04835 ********************************************************************************************/
04836 
04837 void DIBUtil::InvertAlpha(LPBITMAPINFO lpBitmapInfo, LPBYTE lpBits)
04838 {
04839     // Only 32 bpp bitmaps have an alpha channel.
04840     if ( lpBitmapInfo->bmiHeader.biBitCount == 32 )
04841     {
04842         // Cast the pointer into a DWORD.
04843         DWORD *lpRGBA = reinterpret_cast<DWORD*> ( lpBits );
04844 
04845         // If we`re exporting a 32Bit BMP then we need to make sure that we convert the
04846         // Alpha channel to Transparency! i.e. invert it!
04847         for ( UINT32 i = 0; i < lpBitmapInfo->bmiHeader.biSizeImage; i+=4 )
04848         {
04849             // XORing the bitmap's RGBA values with Oxff000000 will invert the alpha channel
04850             // bits.
04851             *lpRGBA ^= 0xff000000;
04852             lpRGBA ++;
04853         }
04854     }
04855 }
04856 
04857 /********************************************************************************************
04858 
04859 >   static void DIBUtil::MakeAlphaIntoGreyscale ( LPBITMAPINFO  lpBitmapInfo,
04860                                           LPBYTE        lpBits )
04861 
04862     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
04863     Created:    27/6/00 (moved here by Phil 06/02/2004)
04864     Purpose:    Camelot uses a different transparency scheme to the rest of the world, in
04865                 that 255 is clear, and 0 is opaque. Until the rest of the world catches up,
04866                 it's necessary to invert the alpha channel to make exported files compatible
04867                 with other programs.
04868 
04869 ********************************************************************************************/
04870 
04871 void DIBUtil::MakeAlphaIntoGreyscale(LPBITMAPINFO lpBitmapInfo, LPBYTE lpBits)
04872 {
04873     // Only 32 bpp bitmaps have an alpha channel.
04874     if ( lpBitmapInfo->bmiHeader.biBitCount == 32 )
04875     {
04876         // Cast the pointer into a DWORD.
04877         DWORD *lpRGBA = reinterpret_cast<DWORD*> ( lpBits );
04878 
04879         // If we`re exporting a 32Bit BMP then we need to make sure that we convert the
04880         // Alpha channel to Transparency! i.e. invert it!
04881         for ( UINT32 i = 0; i < lpBitmapInfo->bmiHeader.biSizeImage; i+=4 )
04882         {
04883             // Multiply the alpha value by 0x010101 puts it in each of R, G and B
04884             *lpRGBA = 0x010101 * (*lpRGBA>>24);
04885             lpRGBA ++;
04886         }
04887     }
04888 }
04889 
04890 
04891 #ifdef _DEBUG
04892 void DIBUtil::FillColour24(LPBITMAPINFO lpBitmapInfo, LPBYTE lpBits)
04893 {
04894     srand((unsigned)time(NULL));
04895     DWORD colour = (rand() % 0xff)<<16 | (rand() % 0xff)<<8 | (rand() % 0xff)<<0;
04896 
04897     // Only 32 bpp bitmaps have an alpha channel.
04898     if ( lpBitmapInfo->bmiHeader.biBitCount == 32 )
04899     {
04900         // Cast the pointer into a DWORD.
04901         DWORD *lpRGBA = reinterpret_cast<DWORD*> ( lpBits );
04902 
04903         for ( UINT32 i = 0; i < lpBitmapInfo->bmiHeader.biSizeImage; i+=4 )
04904         {
04905             if ((*lpRGBA & 0xffffff) == 0xffffff)
04906                 *lpRGBA = colour;
04907             lpRGBA ++;
04908         }
04909     }
04910 }
04911 #endif

Generated on Sat Nov 10 03:48:20 2007 for Camelot by  doxygen 1.4.4