oilbitmap.cpp

Go to the documentation of this file.
00001 // $Id: oilbitmap.cpp 1464 2006-07-18 12:32:26Z gerry $
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 // Windows bitmap class
00100 
00101 /*
00102 */
00103 
00104 #include "camtypes.h"
00105 
00106 #include "cartprov.h"
00107 #include "oilbitmap.h"
00108 //#include "ccfile.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 //#include "dibutil.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00110 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00111 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00112 #include "camelot.h"
00113 #include "bitmpinf.h"
00114 //#include "rndrgn.h"
00115 #include "nativeps.h"       // The old style EPS native filter, used in v1.1
00116 #include "saveeps.h"
00117 #include "cameleps.h"
00118 //#include "bmpfiltr.h"
00119 //#include "giffiltr.h" // TI_GIFFilter
00120 //#include "gifutil.h"
00121 //#include "oilfiles.h"
00122 //#include "andy.h"
00123 //#include "extfilts.h" // Accusoft filters (load that bitmap!)
00124 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00125 #include "prdlgctl.h"
00126 #include "printctl.h"
00127 //#include "richard2.h"
00128 //#include "view.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00129 #include "colcontx.h"
00130 #include "colormgr.h"
00131 #include "colplate.h"
00132 
00133 #include "bitfilt.h"    // BaseBitmapFilter
00134 //#include "camfiltr.h" // BaseCamelotFilter - in camtypes.h [AUTOMATICALLY REMOVED]
00135 
00136 // for CMX export
00137 //#include "cmxrendr.h"
00138 //#include "cmxexdc.h"
00139 //#include "cmxform.h"
00140 
00141 CC_IMPLEMENT_DYNAMIC( CWxBitmap, OILBitmap )
00142 
00143 // Declare smart memory handling in Debug builds
00144 #define new CAM_DEBUG_NEW
00145 
00146 
00147 // firstly the bits of the OILBitmap class that get implemented in the OIL layer
00148 
00149 
00150 /********************************************************************************************
00151 
00152 >   BOOL OILBitmap::Init()
00153 
00154     Author:     Andy_Pennell (Xara Group Ltd) <camelotdev@xara.com>
00155     Created:    ?/9/94
00156     Returns:    TRUE always. Cannot fail.
00157     Purpose:    Reads the default fill pattern, either from a file or internally from a resource.
00158     Scope:      Static
00159 
00160 ********************************************************************************************/
00161 
00162 BOOL OILBitmap::Init()
00163 {
00164     static String_256 FillBitmapName;                       //  must be static as a Preference
00165 
00166     CamResource BitmapResource;
00167     BOOL ShouldDeleteFileObject=TRUE;
00168 
00169     CCLexFile *File = NULL;
00170 
00171     if (!Camelot.DeclareSection( wxT("Attributes"), 10))
00172         return TRUE;
00173 
00174     Camelot.DeclarePref( NULL, wxT("FillBitmap"), &FillBitmapName );
00175 
00176     if (!FillBitmapName.IsEmpty())
00177     {
00178         // name given so try and open disk file
00179         CCDiskFile *DiskFile = new CCDiskFile(16384);       // buffering makes a BIG difference
00180 
00181         // Check if the constructor failed
00182         if (DiskFile)
00183         {
00184             if ( DiskFile->IsInited() )
00185             {
00186                 PathName WhichFile( FillBitmapName );
00187 
00188                 // Check that the pathname supplied is valid as far as we are concerned
00189                 if ( WhichFile.IsValid(FillBitmapName) )
00190                 {
00191                     if (!DiskFile->open( WhichFile, ios::in | ios::binary ))
00192                     {
00193                         delete DiskFile;
00194                         DiskFile = NULL;
00195                     }
00196                 }
00197             }
00198             else
00199             {
00200                 delete DiskFile;
00201                 DiskFile = NULL;
00202             }
00203 
00204             if (DiskFile==NULL)
00205                 InformError();
00206             else
00207                 File = DiskFile;                                    // read from bitmap file
00208         }
00209     }
00210 
00211     BOOL ReadHeader = TRUE;
00212 
00213     if( File == NULL )
00214     {
00215         File = BitmapResource.Open(_R(IDB_DEFAULTFILL));
00216         ShouldDeleteFileObject=FALSE;
00217     }
00218 
00219     // whatever file we opened, lets read the bitmap from it
00220 
00221     if (File)
00222     {
00223         LPBITMAPINFO Info;
00224         LPBYTE Bytes;
00225 
00226         File->SetReportErrors(FALSE);
00227 
00228         if ( DIBUtil::ReadFromFile( File, &Info, &Bytes, ReadHeader ) )
00229         {
00230             // if this fails, it won't be fatal, we just won't have any default bitmap fills
00231             OILBitmap::Default = new CWxBitmap( Info, Bytes );
00232 
00233             if (!OILBitmap::Default)
00234                 FreeDIB( Info, Bytes );                             // free up if failed
00235             else
00236             {
00237                 Info->bmiHeader.biXPelsPerMeter = 3780;
00238                 Info->bmiHeader.biYPelsPerMeter = 3780;
00239 
00240                 String_256 Str = _R(IDS_WBITMAP_DEFAULT);               // "Default"
00241                 OILBitmap::Default->SetName(Str);
00242                 OILBitmap::Attach( OILBitmap::Default );            // set usage count to 1
00243             }
00244         }
00245         else
00246             InformError();
00247 
00248         // close file regardless
00249         if (File->isOpen())
00250             File->close();
00251 
00252         // and maybe, just maybe, delete it (that's the object, not the file) as well!!!
00253         if (ShouldDeleteFileObject) delete File;
00254     }
00255 
00256     return TRUE;
00257 }
00258 
00259 /********************************************************************************************
00260 
00261 >   void OILBitmap::Deinit()
00262 
00263     Author:     Andy_Pennell (Xara Group Ltd) <camelotdev@xara.com>
00264     Created:    ?/9/94
00265     Purpose:    Cleans up the OIL bitmap class, designed to be called once on exit.
00266     Scope:      Static
00267 
00268 ********************************************************************************************/
00269 
00270 void OILBitmap::Deinit()
00271 {
00272     delete OILBitmap::Default;
00273     OILBitmap::Default = NULL;
00274 
00275     // perhaps should go through list at some point making sure everything is tidy?
00276 }
00277 
00278 /********************************************************************************************
00279 
00280 >   OILBitmap *OILBitmap::Create()
00281 
00282     Author:     Andy_Pennell (Xara Group Ltd) <camelotdev@xara.com>
00283     Created:    ?/9/94
00284     Returns:    A new OILBitmap.
00285     Purpose:    Creates a lovely fresh OILBitmap. Some data needs putting into it before it
00286                 will work.
00287     Scope:      Static
00288 
00289 ********************************************************************************************/
00290 
00291 OILBitmap *OILBitmap::Create()
00292 {
00293     // Create a new CWxBitmap object.
00294     return new CWxBitmap;
00295 }
00296 
00297 
00298 /********************************************************************************************
00299 
00300 >   OILBitmap *OILBitmap::Create( UINT32 Width, UINT32 Height, UINT32 Depth, UINT32 dpi )
00301 
00302     Author:     Andy_Pennell (Xara Group Ltd) <camelotdev@xara.com>
00303     Created:    ?/9/94
00304     Input:      Pixel width, height and depth, and the dpi of the required bitmap.
00305     Returns:    A new OILBitmap (contents undefined), or NULL if failed.
00306     Purpose:    Creates a lovely fresh OILBitmap. Some data needs putting into it before it
00307                 will work.
00308     Errors:     SetError will be called.
00309     Scope:      Static protected
00310 
00311 ********************************************************************************************/
00312 
00313 OILBitmap *OILBitmap::Create( UINT32 Width, UINT32 Height, UINT32 Depth, UINT32 dpi )
00314 {
00315     LPBITMAPINFO bmInfo;
00316     LPBYTE bmBytes;
00317 
00318     bmInfo = AllocDIB( Width, Height, Depth, &bmBytes );
00319     if (bmInfo)
00320     {
00321         //bmInfo->bmiHeader.biXPelsPerMeter = Mul32Div32( dpi, 100*100, 254 );
00322         double xppm = ((double)dpi * 10000.0)/254.0;
00323         bmInfo->bmiHeader.biXPelsPerMeter = (INT32)(xppm + 0.5);
00324         bmInfo->bmiHeader.biYPelsPerMeter = bmInfo->bmiHeader.biXPelsPerMeter;
00325         CWxBitmap *WinBM = new CWxBitmap( bmInfo, bmBytes );
00326         if (WinBM)
00327             return WinBM;
00328         else
00329             FreeDIB( bmInfo, bmBytes );
00330     }
00331     return NULL;
00332 }
00333 
00334 // now the actual CWxBitmap class
00335 
00336 
00337 /********************************************************************************************
00338 
00339 >   CWxBitmap::CWxBitmap()
00340 
00341     Author:     Andy_Pennell (Xara Group Ltd) <camelotdev@xara.com>
00342     Created:    ?/9/94
00343     Purpose:    Constructor.
00344 
00345 ********************************************************************************************/
00346 
00347 CWxBitmap::CWxBitmap()
00348 {
00349     BMInfo = NULL;
00350     BMBytes = NULL;
00351 
00352     // Set up things for plotting
00353     ScanLineByteWidth = 0;
00354     BitmapSize = 0; // in bytes
00355 
00356     CacheGeometry();
00357 }
00358 
00359 /********************************************************************************************
00360 
00361 >   CWxBitmap::CWxBitmap(LPBITMAPINFO Info, LPBYTE Bytes)
00362 
00363     Author:     Andy_Pennell (Xara Group Ltd) <camelotdev@xara.com>
00364     Created:    ?/9/94
00365     Input:      Windows bitmap pointers to an existing bitmap. Sets up the CWxBitmap to
00366                 contain said bitmap.
00367     Purpose:    Constructor. This must NOT be called from Kernel code.
00368 
00369 ********************************************************************************************/
00370 
00371 CWxBitmap::CWxBitmap(LPBITMAPINFO Info, LPBYTE Bytes)
00372 {
00373     BMInfo = Info;
00374     BMBytes = Bytes;
00375 
00376     ScanLineByteWidth = 0;
00377     BitmapSize = 0; // in bytes
00378 
00379     CacheGeometry();
00380 }
00381 
00382 
00383 
00384 /********************************************************************************************
00385 
00386 >   CWxBitmap::~CWxBitmap()
00387 
00388     Author:     Andy_Pennell (Xara Group Ltd) <camelotdev@xara.com>
00389     Created:    ?/9/94
00390     Purpose:    Destructor. Frees up Windows resources for the bitmap.
00391 
00392 ********************************************************************************************/
00393 
00394 CWxBitmap::~CWxBitmap()
00395 {
00396     if (!HasBeenDeleted())
00397     {
00398         if (BMInfo != NULL && BMBytes != NULL)
00399         {
00400             FreeDIB( BMInfo, BMBytes );
00401             BMInfo = NULL;
00402             BMBytes = NULL;
00403         }
00404     }
00405 
00406     if (m_pGreyscaleTable)
00407         delete m_pGreyscaleTable;
00408 }
00409 
00410 // number of millipoints in a metre
00411 // this is 100*72000/2.54 (approx)
00412 #define MILLIS_PER_METRE    2834646L
00413 // Should be using M_MP_VAL defined in units.h to be more consistent
00414 
00415 // many bitmaps have zero in the X/YPelsPerMeter field, so we default to a common value
00416 // based on 96dpi (96*100/2.54) (96 comes from iPhotoPlus)
00417 #define DEFAULT_PIXEL_SIZE  3780
00418 
00419 
00420 
00421 /********************************************************************************************
00422 
00423 >   virtual BOOL CWxBitmap::GetInfo(BitmapInfo *Info, RenderRegion *pRegion = NULL) const
00424 
00425     Author:     Andy_Pennell (Xara Group Ltd) <camelotdev@xara.com>
00426     Created:    ?/9/94
00427 
00428     Inputs:     pRegion - NULL to get the real BPP of this bitmap
00429                 else points to the render region which will be rendering the bitmap - if
00430                 the region is colour-separating, then the returned BPP will be set to
00431                 the actual export BPP that will/should be used (i.e. deep colour bitmaps
00432                 are generally colour separated to an 8bpp greyscale bitmap)
00433 
00434     Output:     *Info gets updated.
00435 
00436     Returns:    TRUE if worked, FALSE if failed (e.g. no attached bitmap).
00437 
00438     Purpose:    Kernel code can call this to obtain information about the bitmap in a platform-
00439                 independent way. This function is implemented differently on different OIL
00440                 layers.
00441 
00442                 If you only need width/height/bpp/paletteentries, then see SeeAlso
00443 
00444     Errors:     SetError NOT called.
00445     Scope:      Public
00446 
00447     SeeAlso:    CWxBitmap::GetWidth; CWxBitmap::GetHeight; CWxBitmap::GetBPP;
00448                 CWxBitmap::GetNumPaletteEntries
00449 
00450 ********************************************************************************************/
00451 
00452 BOOL CWxBitmap::GetInfo(BitmapInfo *Info, RenderRegion *pRegion)
00453 {
00454     ERROR3IF(Info == NULL, "Illegal NULL param");
00455 RebuildXPEBitmap();
00456 
00457     if (BMInfo && BMBytes && !m_bNeedsXPERebuild)
00458     {
00459         Info->PixelWidth        = GetWidth();
00460         Info->PixelHeight       = GetHeight();
00461         Info->PixelDepth        = GetBPP(pRegion);
00462         Info->NumPaletteEntries = GetNumPaletteEntries();
00463 
00464         INT32 PelW = BMInfo->bmiHeader.biXPelsPerMeter;
00465         if (PelW==0)
00466             PelW = DEFAULT_PIXEL_SIZE;
00467 
00468         INT32 PelH = BMInfo->bmiHeader.biYPelsPerMeter;
00469         if (PelH==0)
00470             PelH = DEFAULT_PIXEL_SIZE;
00471 
00472         if ( (PelW<0) || (PelH<0) )
00473         {
00474             ERROR3("Bad pixel size");
00475             return FALSE;
00476         }
00477 
00478         // Karim 27/07/2000
00479         // If PelW and PelH is 3780, then we take that to mean 96 pix-per-inch,
00480         // which equates to 750 mp-per-pix.
00481         // This means that
00482         if (PelW == 3780 && PelH == 3780)
00483         {
00484             Info->RecommendedWidth  = Info->PixelWidth * 750;
00485             Info->RecommendedHeight = Info->PixelHeight * 750;
00486         }
00487 
00488         // otherwise, use our non-special-case calculations.
00489         else
00490         {
00491             //Info->RecommendedWidth = Mul32Div32( Width,  MILLIS_PER_METRE, PelW );
00492             //Info->RecommendedHeight= Mul32Div32( Height, MILLIS_PER_METRE, PelH );
00493             // Try and round the value up or down rather than always rounding down which
00494             // gives problem on repeated loading/saving and potentially on the dpi calculation 
00495             double RecWidth = ((double)Info->PixelWidth * M_MP_VAL)/(double)PelW;
00496             double RecHeight = ((double)Info->PixelHeight * M_MP_VAL)/(double)PelH;
00497             Info->RecommendedWidth = (INT32)(RecWidth + 0.5);
00498             Info->RecommendedHeight= (INT32)(RecHeight + 0.5);
00499         }
00500 
00501         // this figure should probably include the BMInfo structure, but its size
00502         // is not easily obtained
00503         Info->MemoryUsed = BMInfo->bmiHeader.biSizeImage;
00504 
00505         return TRUE;
00506     }
00507 
00508     return FALSE;
00509 }
00510 
00511 
00512 
00513 /********************************************************************************************
00514 
00515 >   virtual UINT32 CWxBitmap::GetWidth() const
00516 
00517     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00518     Created:    1/7/96
00519     Returns:    The Pixel Width of this bitmap
00520 
00521     Purpose:    Retrieve information on this bitmap
00522 
00523     SeeAlso:    CWxBitmap::GetInfo
00524 
00525 ********************************************************************************************/
00526 
00527 UINT32 CWxBitmap::GetWidth()
00528 {
00529 RebuildXPEBitmap();
00530     if (BMInfo == NULL)
00531         return(0);
00532 
00533     return(BMInfo->bmiHeader.biWidth);
00534 }
00535 
00536 
00537 
00538 /********************************************************************************************
00539 
00540 >   virtual UINT32 CWxBitmap::GetHeight() const
00541 
00542     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00543     Created:    1/7/96
00544     Returns:    The Pixel Height of this bitmap
00545 
00546     Purpose:    Retrieve information on this bitmap
00547 
00548     SeeAlso:    CWxBitmap::GetInfo
00549 
00550 ********************************************************************************************/
00551 
00552 UINT32 CWxBitmap::GetHeight()
00553 {
00554 RebuildXPEBitmap();
00555     if (BMInfo == NULL)
00556         return(0);
00557 
00558     return(BMInfo->bmiHeader.biHeight);
00559 }
00560 
00561 /********************************************************************************************
00562 
00563 >   virtual UINT32 CWxBitmap::GetHorizontalDPI() const
00564 
00565     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00566     Created:    17/6/97
00567     Returns:    The Horizontal DPI of this bitmap
00568     Purpose:    Retrieve information on this bitmap
00569     SeeAlso:    CWxBitmap::GetInfo
00570 
00571 ********************************************************************************************/
00572 
00573 UINT32 CWxBitmap::GetHorizontalDPI()
00574 {
00575 RebuildXPEBitmap();
00576     if (BMInfo == NULL)
00577         return 96;
00578 
00579     INT32 PelW = BMInfo->bmiHeader.biXPelsPerMeter;
00580     if (PelW <= 0)
00581         PelW = DEFAULT_PIXEL_SIZE;
00582 
00583     UINT32 dpi = (UINT32)((((double)PelW * 254.0)/10000.0) + 0.5); // round up the result
00584     return dpi;
00585 }
00586 
00587 /********************************************************************************************
00588 
00589 >   virtual UINT32 CWxBitmap::GetVerticalDPI() const
00590 
00591     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00592     Created:    17/6/97
00593     Returns:    The Vertical DPI of this bitmap
00594     Purpose:    Retrieve information on this bitmap
00595     SeeAlso:    CWxBitmap::GetInfo
00596 
00597 ********************************************************************************************/
00598 
00599 UINT32 CWxBitmap::GetVerticalDPI()
00600 {
00601 RebuildXPEBitmap();
00602     if (BMInfo == NULL)
00603         return(0);
00604 
00605     INT32 PelH = BMInfo->bmiHeader.biYPelsPerMeter;
00606     if (PelH <= 0)
00607         PelH = DEFAULT_PIXEL_SIZE;
00608 
00609     UINT32 dpi = (UINT32)((((double)PelH * 254.0)/10000.0) + 0.5); // round up the result
00610     return dpi;
00611 }
00612 
00613 
00614 /********************************************************************************************
00615 
00616 >   virtual UINT32 CWxBitmap::GetBPP(RenderRegion *pRegion = NULL) const
00617                     
00618     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
00619     Created:    12/1/95
00620 
00621     Inputs:     pRegion - NULL to get the real BPP of this bitmap
00622                 else points to the render region which will be rendering the bitmap - if
00623                 the region is colour-separating, then the returned BPP will be set to
00624                 the actual export BPP that will/should be used (i.e. deep colour bitmaps
00625                 are generally colour separated to an 8bpp greyscale bitmap)
00626 
00627     Returns:    The number of Bits per pixel of this bitmap
00628 
00629     Purpose:    Finds the colour resolution of this bitmap (or, if PRegion is specified,
00630                 the colour resolution at which this bitmap should be output)
00631 
00632     Errors:     -
00633     SeeAlso:    -
00634 
00635 ********************************************************************************************/
00636 
00637 UINT32 CWxBitmap::GetBPP(RenderRegion *pRegion)
00638 {
00639 RebuildXPEBitmap();
00640     // Currently, we colour-separate to the same number of BPP as the source bitmap,
00641     // so we always return the same value.
00642 
00643     if (BMInfo == NULL)
00644         return 0;
00645 
00646     return BMInfo->bmiHeader.biBitCount;
00647 }
00648 
00649 /********************************************************************************************
00650 
00651 >   BOOL CWxBitmap::SetTransparencyIndex(INT32 Index)
00652                 
00653     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
00654     Created:    5/6/96
00655     Returns:    TRUE if the Index was set, FALSE if there is no transparent index
00656     Purpose:    Finds the Transparent index colour of a bitmap if one exists
00657 
00658 ********************************************************************************************/
00659 
00660 BOOL CWxBitmap::SetTransparencyIndex(INT32 Index)
00661 {
00662 RebuildXPEBitmap();
00663     ERROR3IF(BMInfo == NULL, "SetTransparencyIndex called when BMInfo is NULL");
00664     if (BMInfo == NULL)
00665         return FALSE;
00666 
00667     INT32 NumCols = 0;
00668 
00669     switch (GetBPP())
00670     {
00671         case 1:
00672             NumCols = 2;
00673             break;
00674 
00675         case 4:
00676             NumCols = 16;
00677             break;
00678 
00679         case 8:
00680             NumCols = 256;
00681             break;
00682 
00683         default:
00684             ERROR3("Bad colour depth in SetTransparencyIndex");
00685             break;
00686     }
00687 
00688     RGBQUAD* pCols = BMInfo->bmiColors;
00689 
00690     // Set the specified Index to be transparent
00691     for (INT32 i=0; i<NumCols; i++)
00692     {
00693         if (i == Index)
00694             pCols[i].rgbReserved = 0xFF;
00695         else
00696             pCols[i].rgbReserved = 0;
00697     }
00698 
00699     return TRUE;
00700 }
00701 
00702 /********************************************************************************************
00703 
00704 >   BOOL CWxBitmap::GetTransparencyIndex(INT32* pIndex)
00705                 
00706     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
00707     Created:    5/6/96
00708     Returns:    TRUE if the Index was set, FALSE if there is no transparent index
00709     Purpose:    Finds the Transparent index colour of a bitmap if one exists
00710 
00711 ********************************************************************************************/
00712 
00713 BOOL CWxBitmap::GetTransparencyIndex(INT32* pIndex)
00714 {
00715     ERROR3IF(pIndex == NULL, "GetTransparencyIndex called with NULL index pointer");
00716     if (pIndex == NULL)
00717         return FALSE;
00718 
00719 RebuildXPEBitmap();
00720     ERROR3IF(BMInfo == NULL, "GetTransparencyIndex called when BMInfo is NULL");
00721     if (BMInfo == NULL)
00722         return FALSE;
00723 
00724     INT32 NumCols = 0;
00725 
00726     switch (GetBPP())
00727     {
00728         case 1:
00729             NumCols = 2;
00730             break;
00731 
00732         case 4:
00733             NumCols = 16;
00734             break;
00735 
00736         case 8:
00737             NumCols = 256;
00738             break;
00739 
00740         default:
00741             ERROR3("Bad colour depth in GetTransparencyIndex");
00742             break;
00743     }
00744 
00745     RGBQUAD* pCols = BMInfo->bmiColors;
00746 
00747     *pIndex = -1;
00748 
00749     // Look through the Colour table for an entry that has the T channel set to 255
00750     for (INT32 i=0; i<NumCols; i++)
00751     {
00752         if (pCols[i].rgbReserved == 0xFF)
00753         {
00754             *pIndex = i;
00755         //  break;
00756         }
00757     }
00758 
00759     return ((*pIndex) >= 0);
00760 }
00761 
00762 
00763 /********************************************************************************************
00764 
00765 >   BOOL CWxBitmap::IsTransparent()
00766                 
00767     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
00768     Created:    16/03/2004
00769     Returns:    TRUE if the bitmap has any non-opaque pixels
00770     Purpose:    Determines if a bitmap is not totally opaque
00771 
00772 ********************************************************************************************/
00773 
00774 BOOL CWxBitmap::IsTransparent()
00775 {
00776     RebuildXPEBitmap();
00777     ERROR3IF(BMInfo == NULL, "IsTransparent called when BMInfo is NULL");
00778 
00779     if (BMInfo == NULL)
00780         return(FALSE);
00781 
00782     if (GetBPP() <= 8)
00783     {
00784         INT32 TranspIndex;
00785 
00786         // If the bitmap doesn't have a transparency index then it is opaque
00787         if (!GetTransparencyIndex(&TranspIndex))
00788             return(FALSE);
00789 
00790         switch (GetBPP())
00791         {
00792             case 1:
00793                 {
00794                     BYTE* pBits = (BYTE*)(GetBitmapBits());
00795                     UINT32 FullBytes = GetWidth() >> 3;
00796                     UINT32 Height = GetHeight();
00797                     UINT32 ScanLen = GetScanlineSize();
00798                     BYTE Mask = 0xFF >> (7-(GetWidth() - (FullBytes << 3)));
00799                     if (TranspIndex == 0)
00800                     {
00801                         for (UINT32 y = 0; y < Height; y++)
00802                         {
00803                             UINT32 x;
00804                             for (x = 0; x < FullBytes; x++)
00805                             {
00806                                 if (pBits[x] != 0xFF)   // If the 8 pixels are not all the opaque index
00807                                     return(TRUE);       // then we are transparent
00808                             }
00809                             if (Mask)
00810                             {
00811                                 if ((pBits[x] & Mask) != Mask)
00812                                     return(TRUE);
00813                             }
00814                             pBits += ScanLen;
00815                         }
00816                     }
00817                     else
00818                     {
00819                         for (UINT32 y = 0; y < Height; y++)
00820                         {
00821                             UINT32 x;
00822                             for( x = 0; x < FullBytes; x++)
00823                             {
00824                                 if (pBits[x] != 0x00)   // If the 8 pixels are not all the opaque index
00825                                     return(TRUE);       // then we are transparent
00826                             }
00827                             if (Mask)
00828                             {
00829                                 if ((pBits[x] & Mask) != 0x00)
00830                                 return(TRUE);
00831                             }
00832                             pBits += ScanLen;
00833                         }
00834                     }
00835                 }
00836                 break;
00837 
00838             case 4:
00839                 {
00840                     BYTE* pBits = (BYTE*)(GetBitmapBits());
00841                     UINT32 Width = GetWidth();
00842                     UINT32 ByteWidth = (Width + 1) >> 1;            // The number of used bytes in scanline
00843                     UINT32 Height = GetHeight();
00844                     UINT32 ScanLen = GetScanlineSize();
00845                     INT32 TranspIndexHigh = TranspIndex << 4;
00846                     for (UINT32 y = 0; y < Height; y++)
00847                     {
00848                         UINT32 x;
00849                         for( x = 0; x < ByteWidth; x++)
00850                         {
00851                             if ((pBits[x] & 0x0F) == TranspIndex)       // If the pixel is the transparent colour
00852                                 return(TRUE);                           // then we are transparent
00853                             if ((pBits[x] & 0xF0) == TranspIndexHigh)   // If the pixel is the transparent colour
00854                                 return(TRUE);                           // then we are transparent
00855                         }
00856                         if (Width % 2 == 1)                             // If we have an odd pixel then test it
00857                         {
00858                             if ((pBits[x] & 0x0F) == TranspIndex)       // If the pixel is the transparent colour
00859                                 return(TRUE);                           // then we are transparent
00860                         }
00861                         pBits += ScanLen;
00862                     }
00863                 }
00864                 break;
00865 
00866             case 8:
00867                 {
00868                     BYTE* pBits = (BYTE*)(GetBitmapBits());
00869                     UINT32 Width = GetWidth();
00870                     UINT32 Height = GetHeight();
00871                     UINT32 ScanLen = GetScanlineSize();
00872                     for (UINT32 y = 0; y < Height; y++)
00873                     {
00874                         for (UINT32 x = 0; x < Width; x++)
00875                         {
00876                             if (pBits[x] == TranspIndex)    // If the pixel is the transparent colour
00877                                 return(TRUE);               // then we are transparent
00878                         }
00879                         pBits += ScanLen;
00880                     }
00881                 }
00882                 break;
00883 
00884             default:
00885                 ERROR3("Bad colour depth in IsTransparent");
00886                 break;
00887         }
00888     }
00889     else if (GetBPP() == 32)
00890     {
00891         // if we have any non-opaque pixels then we must be complex
00892         DWORD* pBits = (DWORD*)(GetBitmapBits());
00893         UINT32 Width = GetWidth();
00894         UINT32 Height = GetHeight();
00895         DWORD* pEnd = pBits + (Width * Height);
00896         while (pBits < pEnd)
00897         {
00898             if (*pBits && 0xFF000000)       // If the pixel is not completely opaque
00899                 return(TRUE);               // then we are transparent
00900             pBits++;
00901         }
00902     }
00903 
00904     return(FALSE);
00905 }
00906 
00907 
00908 /********************************************************************************************
00909 
00910 >   INT32 CWxBitmap::GetRecommendedWidth()
00911                 
00912     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
00913     Created:    12/6/96
00914     Returns:    The current recommended width of the bitmap in Millipoints
00915     Purpose:    Finds the recommended width of the bitmap
00916 
00917 ********************************************************************************************/
00918 
00919 INT32 CWxBitmap::GetRecommendedWidth()
00920 {
00921 RebuildXPEBitmap();
00922     const UINT32 Width  = BMInfo->bmiHeader.biWidth;
00923 
00924     INT32 PelW = BMInfo->bmiHeader.biXPelsPerMeter;
00925     if (PelW==0)
00926         PelW = DEFAULT_PIXEL_SIZE;
00927 
00928     if ( (PelW<0) )
00929     {
00930         ERROR3IF(TRUE, "Bad pixel size");
00931         return 0;
00932     }
00933 
00934     double RecWidth = ((double)Width * M_MP_VAL)/(double)PelW;
00935 
00936     return (INT32)(RecWidth + 0.5);
00937 }
00938 
00939 /********************************************************************************************
00940 
00941 >   INT32 CWxBitmap::GetRecommendedHeight()
00942             
00943     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
00944     Created:    12/6/96
00945     Returns:    The current recommended height of the bitmap in Millipoints
00946     Purpose:    Finds the recommended height of the bitmap
00947 
00948 ********************************************************************************************/
00949 
00950 INT32 CWxBitmap::GetRecommendedHeight()
00951 {
00952 RebuildXPEBitmap();
00953     const UINT32 Height = BMInfo->bmiHeader.biHeight;
00954 
00955     INT32 PelH = BMInfo->bmiHeader.biYPelsPerMeter;
00956     if (PelH==0)
00957         PelH = DEFAULT_PIXEL_SIZE;
00958 
00959     if ( (PelH<0) )
00960     {
00961         ERROR3IF(TRUE, "Bad pixel size");
00962         return FALSE;
00963     }
00964 
00965     double RecHeight = ((double)Height * M_MP_VAL)/(double)PelH;
00966 
00967     return (INT32)(RecHeight + 0.5);
00968 }
00969 
00970 /********************************************************************************************
00971 
00972 >   void CWxBitmap::SetRecommendedWidth(INT32 NewWidth)
00973                 
00974     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
00975     Created:    12/6/96
00976     Inputs:     NewWidth, the new width of the bitmap in Millipoints
00977     Purpose:    Sets the recommended width of the bitmap
00978 
00979 ********************************************************************************************/
00980 
00981 void CWxBitmap::SetRecommendedWidth(INT32 NewWidth)
00982 {
00983 RebuildXPEBitmap();
00984     if (BMInfo)
00985     {   
00986         double PelW = DEFAULT_PIXEL_SIZE;
00987 
00988         if (NewWidth > 0)
00989         {
00990             const UINT32 Width = BMInfo->bmiHeader.biWidth;
00991             PelW = ((double)Width * M_MP_VAL)/(double)NewWidth;
00992         }
00993 
00994         BMInfo->bmiHeader.biXPelsPerMeter = (INT32)(PelW + 0.5);
00995     }
00996 }
00997 
00998 /********************************************************************************************
00999 
01000 >   void CWxBitmap::SetRecommendedHeight(INT32 NewHeight)
01001                 
01002     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
01003     Created:    12/6/96
01004     Inputs:     NewHeight, the new height of the bitmap in Millipoints
01005     Purpose:    Sets the recommended height of the bitmap
01006 
01007 ********************************************************************************************/
01008 
01009 void CWxBitmap::SetRecommendedHeight(INT32 NewHeight)
01010 {
01011 RebuildXPEBitmap();
01012     if (BMInfo)
01013     {   
01014         double PelH = DEFAULT_PIXEL_SIZE;
01015 
01016         if (NewHeight > 0)
01017         {
01018             const UINT32 Height = BMInfo->bmiHeader.biHeight;
01019             PelH = ((double)Height * M_MP_VAL)/(double)NewHeight;
01020         }
01021 
01022         BMInfo->bmiHeader.biYPelsPerMeter = (INT32)(PelH + 0.5);
01023     }
01024 }
01025 
01026 /********************************************************************************************
01027 
01028 >   CWxBitmap* CWxBitmap::MakeCopy() 
01029 
01030     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01031     Created:    15/3/2000
01032     Returns:    pointer to a copy of this bitmap, NULL if it fails
01033     Purpose:    To make an exact duplicate of this bitmap
01034 
01035 
01036 ********************************************************************************************/
01037 
01038 OILBitmap* CWxBitmap::MakeCopy()
01039 {
01040 RebuildXPEBitmap();
01041     // check to see that theres something to copy
01042     if (BMInfo == NULL || BMBytes == NULL)
01043     {
01044         ERROR3("This bitmap has no bits or info to copy!");
01045         return NULL;
01046     }
01047 
01048     LPBYTE pNewBits = NULL;
01049     LPBITMAPINFO pNewInfo = NULL;
01050 
01051     // call our handy utility function which does the work
01052     DIBUtil::CopyEntireBitmap(BMInfo, BMBytes, &pNewInfo, &pNewBits);
01053 
01054     if (pNewInfo == NULL || pNewBits == NULL)
01055     {
01056         ERROR3("Failed to allocate bitmap structures");
01057         return NULL;
01058     }
01059 
01060     CWxBitmap* pNewBitmap = new CWxBitmap(pNewInfo, pNewBits);
01061 
01062     if (pNewBitmap == NULL)
01063     {
01064         ERROR3("Failed to allocate new CWxBitmap");
01065         FreeDIB(pNewInfo, pNewBits);
01066     }
01067     return pNewBitmap;
01068 }
01069 
01070 /********************************************************************************************
01071 
01072 >   virtual UINT32 CWxBitmap::GetNumPaletteEntries() const
01073 
01074     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01075     Created:    1/7/96
01076     Returns:    The number of palette entries used by this bitmap
01077 
01078                 If this is a deep-colour bitmap (not paletted) will return 0
01079                 If this is a non-paletted (greyscale) bitmap, will return 0
01080 
01081     Purpose:    Retrieve information on this bitmap
01082 
01083     SeeAlso:    CWxBitmap::GetInfo
01084 
01085 ********************************************************************************************/
01086 
01087 UINT32 CWxBitmap::GetNumPaletteEntries()
01088 {
01089 RebuildXPEBitmap();
01090     if (BMInfo != NULL && BMInfo->bmiHeader.biBitCount <= 8)
01091     {
01092         // 8 bpp or less - can have a palette
01093         return(BMInfo->bmiHeader.biClrUsed);
01094     }
01095 
01096     // We've got a problem, or it has no palette - return 0
01097     return(0);
01098 }
01099 
01100 
01101 
01102 /********************************************************************************************
01103 
01104 >   UINT32 CWxBitmap::GetScanlineSize() const
01105 
01106     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01107     Created:    1/7/96
01108     Returns:    The size, in BYTES, of a scanline from this bitmap, including any padding
01109                 bytes that may be necessary to achieve platform-dependant formatting of
01110                 scanlines. (e.g. in Windows, scanlines are padded out to a word boundary)
01111 
01112                 i.e. it returns the byte offset from the start of one scanline to the
01113                 start of the next scanline.
01114 
01115     Purpose:    To determine the memory allocation needed to hold a single scanline of
01116                 this bitmap. This is a convenient interface onto DIBUtil::ScanlineSize
01117 
01118     SeeAlso:    DIBUtil::ScanlineSize
01119 
01120 ********************************************************************************************/
01121 
01122 UINT32 CWxBitmap::GetScanlineSize()
01123 {
01124 RebuildXPEBitmap();
01125     if (BMInfo == NULL)
01126         return(0);
01127 
01128     return(DIBUtil::ScanlineSize(GetWidth(), GetBPP()));
01129 }
01130 
01131 
01132 
01133 /********************************************************************************************
01134 
01135 >   virtual BOOL CWxBitmap::ExportBitmap(RenderRegion *pRegion) const
01136                     
01137     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01138     Created:    ?
01139     Returns:    TRUE for success
01140     Purpose:    Exports this bitmap to the given EPS RenderRegion
01141                 Just calls ExportBitmapPalette then ExportBitmapData
01142 
01143     Notes:      If you want colour separated output, see...
01144 
01145     SeeAlso:    CWxBitmap::ExportSeparatedPalette; CWxBitmap::ExportSeparatedData;
01146                 CWxBitmap::ExportBitmapPalette; CWxBitmap::ExportBitmapData
01147 
01148 ********************************************************************************************/
01149 
01150 #define CMXREDUCEBPPBUFFERSIZE  (1024 * 4)  // in pixels
01151 
01152 BOOL CWxBitmap::ExportBitmap(RenderRegion *pRegion)
01153 {
01154 #if !defined(EXCLUDE_FROM_RALPH)
01155 RebuildXPEBitmap();
01156     // Check the render region type
01157     if (pRegion->IsKindOf(CC_RUNTIME_CLASS(CamelotEPSRenderRegion)))
01158     {
01159         // It's Camelot EPS - export the bitmap.
01160         if (!ExportBitmapPalette(pRegion))
01161             // Error!
01162             return FALSE;
01163 
01164         if (!ExportBitmapData(pRegion))
01165             // Error!
01166             return FALSE;
01167     }
01168 PORTNOTE("cmx", "Disabled CMXRenderRegion")
01169 #ifndef EXCLUDE_FROM_XARALX
01170     else if (pRegion->IsKindOf(CC_RUNTIME_CLASS(CMXRenderRegion)))
01171     {
01172         // CMX render region... get the DC
01173         CMXExportDC *pDC = (CMXExportDC *) pRegion->GetRenderDC();
01174 
01175         // start the bitmap list thinguy
01176         if(!pDC->StartRIFFList(cmxRIFFLIST_ImageDesc))
01177             return FALSE;
01178 
01179         // start the bitmap info section
01180         if(!pDC->StartSection(CMXExportDC::CMXSECTION_IMAGINFO))
01181             return FALSE;
01182 
01183         // tag...
01184         if(!pDC->StartTag(cmxTAG_DescrSection_Image_ImageInfo))
01185             return FALSE;
01186 
01187         // non-palette flag
01188         BOOL NoPal = FALSE;
01189         if(BMInfo->bmiHeader.biBitCount >= 24)
01190             NoPal = TRUE;
01191 
01192         // 32 bit pixel flag -- needs to be squished into 24 bitness
01193         // and our bitmap size value
01194         BOOL eBitmapSize = BitmapSize;
01195         BOOL Is32Bit = FALSE;
01196         if(BMInfo->bmiHeader.biBitCount == 32)
01197         {
01198             Is32Bit = TRUE;
01199 
01200             // calculate a new eBitmapSize
01201             eBitmapSize = GetWidth() * 3;
01202             if((eBitmapSize & 0x3) != 0)
01203                 eBitmapSize = (eBitmapSize + 4) & ~0x3; // word align to 4 byte boundary
01204             eBitmapSize *= GetHeight();
01205         }
01206 
01207         // write header
01208         cmxImageInfo ii;
01209         cmxImageHeader ih;
01210         cmxRIMAGEHeader rh;
01211         cmxRIMAGEPaletteHeader ph;
01212 
01213         DWORD BitmapHeaderSize = sizeof(rh) + (NoPal?0:(sizeof(ph) + sizeof(cmxRIMAGEPaletteEntry) * BMInfo->bmiHeader.biClrUsed));
01214 
01215         ii.Type = cmxIMAGETYPE_RIMAGE;
01216         ii.Compression = 1;         // dunno what that'll do. Probably'll work.
01217         ii.Size = sizeof(ih) + BitmapHeaderSize + eBitmapSize;
01218         ii.CompressedSize = sizeof(ih) + BitmapHeaderSize + eBitmapSize;
01219 
01220         pDC->WriteData(&ii, sizeof(ii));
01221 
01222         // end tag
01223         if(!pDC->EndTag() || !pDC->WriteMinEndTag())
01224             return FALSE;
01225 
01226         // end the bitmap info section
01227         if(!pDC->EndSection())
01228             return FALSE;
01229 
01230         // start the bitmap data section
01231         if(!pDC->StartSection(CMXExportDC::CMXSECTION_IMAGDATA))
01232             return FALSE;
01233 
01234         // write the header -- we have to do the tag ourselves as it's got a 
01235         // 32 bit length value
01236         CMXFutureLength TagLen;
01237         if(pDC->IsThirtyTwoBit())
01238         {
01239             pDC->WriteByte(cmxTAG_DescrSection_Image_ImageData);
01240             DWORD len = 0;
01241             pDC->WriteData(&len, sizeof(len));
01242             TagLen.Init(pDC, - (INT32)sizeof(len), sizeof(len));
01243             TagLen.SetLengthStartPos(pDC, - (INT32)(sizeof(len) + sizeof(BYTE)));
01244         }   
01245 
01246         // do the image header
01247         ih.ImageType[0] = 'R';
01248         ih.ImageType[1] = 'I';
01249         ih.Size = eBitmapSize + sizeof(ih) + BitmapHeaderSize;
01250         ih.Reserved[0] = 0;
01251         ih.Reserved[1] = 0;
01252         ih.OffsetToPixels = sizeof(ih) + BitmapHeaderSize;
01253         
01254         if(!pDC->WriteData(&ih, sizeof(ih)))
01255             return FALSE;
01256 
01257         // make the bitmap header
01258         rh.Type = NoPal?cmxR_IMG_RGB:cmxR_IMG_PAL;
01259         rh.ComprType = 1;               // this probably means it's got no compression, but you never know
01260         rh.Width = GetWidth();
01261         rh.Height = GetHeight();
01262         rh.Planes = 1;                              // probably right
01263         rh.BitsPerPlane = NoPal?24:BMInfo->bmiHeader.biBitCount;
01264         rh.BytesPerLine = (rh.Width * rh.BitsPerPlane) / 8;
01265         if((rh.BytesPerLine & 0x3) != 0)
01266             rh.BytesPerLine = (rh.BytesPerLine + 4) & ~0x3; // word align to 4 byte boundary
01267         rh.BufSize = eBitmapSize;
01268         rh.ComprBufSize = 0;                        // probably as we're not compressing
01269         rh.XPelsPerKM = rh.YPelsPerKM = 0x3d400;    // random value nicked from a corel CMX file
01270         rh.PaletteOffset = NoPal?0:sizeof(rh);      // starts immediatly after this
01271         rh.DataOffset = BitmapHeaderSize;           //after the palette
01272         rh.StartBufOffset = 0;                      // no idea what this does
01273         rh.AlphaOffset = 0;                         // nope, haven't got one of those mate
01274         rh.MaskOffset = 0;                          // nor one of those
01275 
01276         if(rh.BitsPerPlane == 4 && !pDC->IsThirtyTwoBit())
01277         {
01278             rh.Type = cmxR_IMG_PAL4;
01279         }
01280 
01281         // write the bitmap header
01282         if(!pDC->WriteData(&rh, sizeof(rh)))
01283             return FALSE;
01284 
01285         if(!NoPal)
01286         {
01287             // is this contoned?
01288             CMXRenderRegion *pR = (CMXRenderRegion *)pRegion;
01289             RGBQUAD *pPal = pR->GetAreExportingContoneBitmap()
01290                 ?m_pContonePalette:BMInfo->bmiColors;
01291 
01292             // write the palette
01293             ph.Type = cmxR_PALETTE_RGB;
01294             ph.NumEntries = (WORD)BMInfo->bmiHeader.biClrUsed;
01295             if(!pDC->WriteData(&ph, sizeof(ph)))
01296                 return FALSE;
01297             // palette entries
01298             for(DWORD l = 0; l < BMInfo->bmiHeader.biClrUsed; l++)
01299             {
01300                 ERROR3IF(sizeof(cmxRIMAGEPaletteEntry) != 3, "wrong size of entry");
01301                 cmxRIMAGEPaletteEntry pi;
01302                 pi.b = pPal[l].rgbBlue;
01303                 pi.g = pPal[l].rgbGreen;
01304                 pi.r = pPal[l].rgbRed;
01305                 if(!pDC->WriteData(&pi, sizeof(pi)))
01306                     return FALSE;
01307             }
01308         }
01309 
01310         // should do it, I suppose.
01311 
01312         // write the bitmap data
01313         if(!Is32Bit)
01314         {
01315             // this isn't 32 bit pixels, so just slap everything to the file
01316             if(!pDC->WriteData(BMBytes, BitmapSize))
01317                 return FALSE;
01318         }
01319         else
01320         {
01321             // corel doesn't support 32 bit pixels, so we have to go through
01322             // the image data reducing it to 24 bit. Oh well.
01323             BYTE Buffer[CMXREDUCEBPPBUFFERSIZE * 3];
01324             INT32 BufLoc = 0;
01325             INT32 PixelsToGo = GetWidth() * GetHeight();
01326             INT32 PixelsToGoInLine = GetWidth();
01327             BYTE *Pixels = (BYTE *)BMBytes;
01328             INT32 Bytes = 0;
01329 
01330             while(PixelsToGo > 0)
01331             {
01332                 // bung a pixel in the buffer
01333                 Buffer[BufLoc++] = *(Pixels++);
01334                 Buffer[BufLoc++] = *(Pixels++);
01335                 Buffer[BufLoc++] = *(Pixels++);
01336                 Pixels++;
01337                 Bytes += 3;
01338 
01339                 // decrement counts
01340                 PixelsToGo--;
01341                 PixelsToGoInLine--;
01342 
01343                 // check to see if we're at the end of the line
01344                 if(PixelsToGoInLine <= 0)
01345                 {
01346                     // check to see if we need to word align here...
01347                     if((Bytes & 0x3) != 0)
01348                     {
01349                         INT32 Need = ((Bytes + 4) & ~0x3) - Bytes;
01350                         for(INT32 l = 0; l < Need; l++)
01351                         {
01352                             Buffer[BufLoc++] = 0;
01353                             Bytes++;
01354                         }
01355                     }
01356 
01357                     PixelsToGoInLine = GetWidth();  // reset counter
01358                 }
01359 
01360                 // test to see if we've done enough
01361                 if(BufLoc >= ((CMXREDUCEBPPBUFFERSIZE * 3) - 8))        // enough for another pixel or so
01362                 {
01363                     // write it to the file
01364                     pDC->WriteData(Buffer, BufLoc);
01365 
01366                     // reset counter
01367                     BufLoc = 0;
01368                 }
01369             }
01370 
01371             // write anything left to the file
01372             pDC->WriteData(Buffer, BufLoc);
01373         }
01374 
01375         // write the length
01376         if(pDC->IsThirtyTwoBit())
01377             TagLen.Write(pDC);
01378 
01379         // end tag...
01380         if(!pDC->WriteMinEndTag())
01381             return FALSE;
01382 
01383         // end the bitmap data section
01384         if(!pDC->EndSection())
01385             return FALSE;
01386 
01387         // end the bitmap list thingy
01388         if(!pDC->EndRIFFList())
01389             return FALSE;
01390 
01391         return TRUE;
01392     }
01393 #endif
01394 #endif
01395     // If we got here, no errors occured.
01396     return TRUE;
01397 }
01398 
01399 
01400 
01401 /********************************************************************************************
01402 
01403 >   BOOL CWxBitmap::ExportBitmapPaletteInternal(RenderRegion *pRegion) const
01404                     
01405     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> (Moved Tim code into this shared subroutine)
01406     Created:    1/7/96 (Original code date unknown)
01407 
01408     Returns:    TRUE for success
01409 
01410     Purpose:    Exports the given palette data to the given RenderRegion
01411                 Used as an internal shared function for ExportBitmapPalette and
01412                 ExportContonePalette.
01413 
01414                 The palette is exported twice - first as a greyscale CLUT, then as a
01415                 colour CLUT.
01416 
01417     Notes:      This function now handles colour separation and correction on export,
01418                 by using the RenderRegion's RenderView to find an appropriate RGB output
01419                 colour context to do the colour output for it.
01420 
01421                 IF (pSrcCLUT == ContonePalette), then a GLOBAL DEFAULT colour context
01422                 is used, so that the contone palette is NOT colour separated.
01423                 It is expected that you will build and discard the contone palette
01424                 very close to the ExportContonePalette call, so that it will be pre-
01425                 separated for the current output context.
01426 
01427 ********************************************************************************************/
01428 
01429 BOOL CWxBitmap::ExportBitmapPaletteInternal(RenderRegion *pRegion, INT32 NumColours, RGBQUAD *pSrcCLUT)
01430 {
01431 #if !defined(EXCLUDE_FROM_RALPH)
01432 RebuildXPEBitmap();
01433     // Sanity check
01434     ERROR3IF((BMInfo->bmiHeader.biBitCount != 1) &&
01435             (BMInfo->bmiHeader.biBitCount != 4) &&
01436             (BMInfo->bmiHeader.biBitCount != 8) &&
01437             (BMInfo->bmiHeader.biBitCount != 24) &&
01438             (BMInfo->bmiHeader.biBitCount != 32), "Bad bitmap depth in ExportBitmap!");
01439 
01440     ERROR3IF(pRegion == NULL || pSrcCLUT == NULL, "Illegal NULL params");
01441 
01442     const INT32 ClutSize = 256;
01443 
01444     // Allocate an array in which we can construct the clut.
01445     LPBYTE pCLUT = (LPBYTE) CCMalloc(ClutSize * 3);
01446     if (pCLUT == NULL)
01447     {
01448         // Out of memory
01449         ERROR3("No memory");
01450         return FALSE;
01451     }
01452 
01453     // Find the output DC
01454     KernelDC *pDC = (KernelDC *) CCDC::ConvertFromNativeDC(pRegion->GetRenderDC());
01455 
01456     // First, clear all entries to black
01457     memset(pCLUT, 0, ClutSize);
01458 
01459     // Find an RGB colour context to colour-separate the colours for us (if it's necessary)
01460     // (Note: If we're exporting the ContonePalette, then we assume that it is pre-separated,
01461     // and just get a simple (non-separating) RGB context instead, to avoid double-separating
01462     ColourContextRGBT *ccRGB = NULL;
01463     if (pSrcCLUT == m_pContonePalette)
01464         ccRGB = (ColourContextRGBT *) ColourManager::GetColourContext(COLOURMODEL_RGBT);
01465     else
01466         ccRGB = (ColourContextRGBT *) pRegion->GetRenderView()->GetColourContext(COLOURMODEL_RGBT);
01467     ERROR2IF(ccRGB == NULL, FALSE, "Can't get a ColourContextRGBT for EPS bitmap export");
01468 
01469     DocColour TempCol;
01470     // BLOCK
01471     {
01472         ColourRGBT RGB;
01473          
01474         // Build the greyscale CLUT first.
01475         for (INT32 i = 0; i < NumColours; i++)
01476         {
01477             TempCol.SetRGBValue(pSrcCLUT[i].rgbRed, pSrcCLUT[i].rgbGreen, pSrcCLUT[i].rgbBlue);
01478             ccRGB->ConvertColour(&TempCol, (ColourGeneric *) &RGB);
01479 
01480             double Grey =   (RGB.Red.MakeDouble()   * 0.305) +
01481                             (RGB.Green.MakeDouble() * 0.586) +
01482                             (RGB.Blue.MakeDouble()  * 0.109);
01483 
01484             pCLUT[i] = (BYTE) (Grey * 255.0);
01485         }
01486     }
01487 
01488     // Greyscale palette complete - output it as a hex string
01489     pDC->OutputNewLine();
01490     pDC->OutputToken(_T("<"));
01491     pDC->OutputRawBinary(pCLUT, ClutSize);
01492     pDC->OutputToken(_T(">"));
01493     pDC->OutputNewLine();
01494 
01495     // Ok, now do the colour palette.
01496     // First, clear all entries to black
01497     memset(pCLUT, 0, ClutSize * 3);
01498 
01499     // BLOCK
01500     {
01501         PColourRGBT RGB;
01502 
01503         for (INT32 i = 0; i < NumColours; i++)
01504         {
01505             TempCol.SetRGBValue(pSrcCLUT[i].rgbRed, pSrcCLUT[i].rgbGreen, pSrcCLUT[i].rgbBlue);
01506             ccRGB->ConvertColour(&TempCol, (ColourPacked *) &RGB);
01507             
01508             pCLUT[i * 3 + 0] = RGB.Red;
01509             pCLUT[i * 3 + 1] = RGB.Green;
01510             pCLUT[i * 3 + 2] = RGB.Blue;
01511         }
01512     }
01513 
01514     // RGB palette complete - output it as a hex string
01515     pDC->OutputNewLine();
01516     pDC->OutputToken(_T("<"));
01517     pDC->OutputRawBinary(pCLUT, ClutSize * 3);
01518     pDC->OutputToken(_T(">"));
01519     pDC->OutputNewLine();
01520 
01521     // Clean up
01522     CCFree(pCLUT);
01523 #endif
01524     // If we got here, no errors occured.
01525     return TRUE;
01526 }
01527 
01528 
01529 
01530 /********************************************************************************************
01531 
01532 >   virtual BOOL CWxBitmap::ExportBitmapPalette(RenderRegion *pRegion) const
01533                     
01534     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01535     Created:    ?
01536     Returns:    TRUE for success
01537     Purpose:    Exports this bitmap's palette to the given RenderRegion
01538 
01539     Notes:      This function outputs the data in 2 different ways, depending on
01540                 whether it thinks the RenderRegion is for Renderable postscript or not.
01541 
01542                 This function now handles colour separation and correction on export,
01543                 by using the RenderRegion's RenderView to find an appropriate RGB output
01544                 colour context to do the colour output for it.
01545 
01546     SeeAlso:    CWxBitmap::ExportBitmapPaletteInternal
01547 
01548 ********************************************************************************************/
01549 
01550 BOOL CWxBitmap::ExportBitmapPalette(RenderRegion *pRegion)
01551 {
01552 #if !defined(EXCLUDE_FROM_RALPH)
01553 RebuildXPEBitmap();
01554     // Check the render region type
01555     if (!pRegion->IsKindOf(CC_RUNTIME_CLASS(CamelotEPSRenderRegion)))
01556     {
01557         ERROR3("ExportBitmapPalette called by non-CamelotEPSRenderRegion class");
01558         return(TRUE);
01559     }
01560 
01561     // Sanity check. Note that we allow deep bitmaps here, as this function exports nothing
01562     // when the bitmap has no palette, including deep images.
01563     ERROR3IF((BMInfo->bmiHeader.biBitCount != 1) &&
01564             (BMInfo->bmiHeader.biBitCount != 4) &&
01565             (BMInfo->bmiHeader.biBitCount != 8) &&
01566             (BMInfo->bmiHeader.biBitCount != 24) &&
01567             (BMInfo->bmiHeader.biBitCount != 32), "Bad bitmap depth in ExportBitmap!");
01568 
01569     // If it's a depp bitmap or it has no palette, then we return TRUE immediately
01570     if (BMInfo->bmiHeader.biBitCount > 8 || BMInfo->bmiHeader.biClrUsed < 1)
01571         return(TRUE);
01572 
01573     // Find out if it needs to be renderable (proper Adobe EPS)
01574     BOOL Renderable = (IS_A(pRegion, CamelotEPSRenderRegion) || pRegion->IsPrinting());
01575 
01576     if (Renderable)     // Renderable postscript, so output in proper Adobe format
01577         return(ExportBitmapPaletteInternal(pRegion, BMInfo->bmiHeader.biClrUsed, BMInfo->bmiColors));
01578 
01579 
01580     // Not renderable (it's CamelotEPS), so we can output the bitmap as raw binary
01581     KernelDC *pDC = (KernelDC *) CCDC::ConvertFromNativeDC(pRegion->GetRenderDC());
01582 
01583     pDC->OutputToken(_T("%Camelot: Bitmap palette"));
01584     pDC->OutputRawBinary((BYTE *) BMInfo->bmiColors, 
01585                          BMInfo->bmiHeader.biClrUsed * sizeof(RGBQUAD));
01586     pDC->OutputNewLine();
01587 #endif
01588     // If we got here, no errors occured.
01589     return TRUE;
01590 }
01591 
01592 
01593 
01594 /********************************************************************************************
01595 
01596 >   virtual BOOL CWxBitmap::ExportSeparatedPalette(RenderRegion *pRegion) const;
01597                     
01598     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01599     Created:    2/7/96
01600 
01601     Inputs:     pRegion - The render region to export to
01602     Returns:    TRUE for success
01603 
01604     Purpose:    Exports a greyscale 8bpp palette suitable for use by the bitmaps output
01605                 by ExportSeparatedData.
01606 
01607     Notes:      This function is very specialised, for handling the output of a palette
01608                 for an 8bpp greyscale seaparation plate of a bitmap to be output with
01609                 OutputSeparatedData.
01610 
01611                 See CamelotEPSRenderRegion::DrawParallelogramBitmap for the only code which
01612                 should be calling this function.
01613 
01614     Errors:     Many ERROR3's - this bitmap must be deep, we must be printing, there
01615                 must be a valid ColourPlate for separating the output.
01616 
01617     SeeAlso:    CWxBitmap::ExportBitmapPalette; CWxBitmap::ExportSeparatedData
01618 
01619 ********************************************************************************************/
01620 
01621 BOOL CWxBitmap::ExportSeparatedPalette(RenderRegion *pRegion)
01622 {
01623 #if !defined(EXCLUDE_FROM_RALPH)
01624     ERROR3IF(pRegion == NULL, "Illegal NULL params");
01625     if (!pRegion->IsKindOf(CC_RUNTIME_CLASS(CamelotEPSRenderRegion)))
01626     {
01627         ERROR3("ExportBitmapPalette called by non-CamelotEPSRenderRegion class");
01628         return(TRUE);
01629     }
01630 
01631     // Sanity checks
01632     ERROR3IF(!pRegion->IsPrinting(), "ExportSeparatedBitmapPalette called when not printing?");
01633 
01634     ERROR3IF(pRegion->GetRenderView() == NULL, "No render view");
01635     ERROR3IF(pRegion->GetRenderView()->GetColourPlate() == NULL,
01636             "Not colour separating in ExportSeparatedBitmapPalette");
01637 
01638 RebuildXPEBitmap();
01639     KernelDC *pDC = (KernelDC *) CCDC::ConvertFromNativeDC(pRegion->GetRenderDC());
01640     BYTE pCLUT[256 * 3];
01641 
01642     INT32 i;
01643     // Do a greyscale intensity CLUT
01644     for (i = 0; i < 256; i++)
01645         pCLUT[i] = i;
01646 
01647     pDC->OutputNewLine();
01648     pDC->OutputToken(_T("<"));
01649     pDC->OutputRawBinary(pCLUT, 256);
01650     pDC->OutputToken(_T(">"));
01651     pDC->OutputNewLine();
01652 
01653     // And do a 24bit RGB CLUT
01654     for (i = 0; i < 256*3; i+=3)
01655         pCLUT[i] = pCLUT[i+1] = pCLUT[i+2] = i/3;
01656 
01657     pDC->OutputNewLine();
01658     pDC->OutputToken(_T("<"));
01659     pDC->OutputRawBinary(pCLUT, 256 * 3);
01660     pDC->OutputToken(_T(">"));
01661     pDC->OutputNewLine();
01662 
01663 #endif
01664     return(TRUE);
01665 }
01666 
01667 
01668 
01669 /********************************************************************************************
01670 
01671 >   virtual BOOL CWxBitmap::ExportContonePalette(RenderRegion *pRegion) const
01672                     
01673     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01674     Created:    ?
01675     Returns:    TRUE for success
01676     Purpose:    Exports this bitmap's contone palette to the given RenderRegion
01677                 
01678                 You must have called BuildContonePalette before calling this function!
01679 
01680     Notes:      This funmction does NOT colour separate the contone palette. However,
01681                 the colour is correctly separated when you call BuildContonePalette,
01682                 so it is imperative that you build the contone palette immediately
01683                 prior to export, and discard it immediately afterward (i.e. don't rely
01684                 on a cached version of the contone palette).
01685 
01686     SeeAlso:    OILBitmap::BuildContonePalette; CWxBitmap::ExportBitmapPaletteInternal
01687 
01688 ********************************************************************************************/
01689 
01690 BOOL CWxBitmap::ExportContonePalette(RenderRegion *pRegion)
01691 {
01692 #if !defined(EXCLUDE_FROM_RALPH)
01693 RebuildXPEBitmap();
01694     ERROR2IF(m_pContonePalette == NULL, FALSE, "No contone palette to export!");
01695 
01696     // If it's Camelot EPS, then export the bitmap
01697     if (pRegion->IsKindOf(CC_RUNTIME_CLASS(CamelotEPSRenderRegion)))
01698         return(ExportBitmapPaletteInternal(pRegion, BMInfo->bmiHeader.biClrUsed, m_pContonePalette));
01699 #endif
01700     // All ok
01701     return TRUE;
01702 }
01703 
01704 
01705 
01706 /********************************************************************************************
01707 
01708 >   virtual BOOL CWxBitmap::ExportBitmapData(RenderRegion *pRegion) const
01709                     
01710     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01711     Created:    ?
01712 
01713     Inputs:     pRegion - The Postscript RenderRegion to export to. In fact, if this is
01714                 not IsKindOf(CamelotEPSRenderRegion), this function will do nothing and
01715                 return TRUE.
01716 
01717     Returns:    TRUE for success
01718     Purpose:    Exports this bitmap's image data to the given RenderRegion
01719 
01720     Notes:      The RenderRegion is responsible for outputting all header/trailer info
01721                 about the bitmap, and for calling ExportBitmapPalette or ExportContonePalette
01722                 as appropriate, if necessary. Be very careful when fiddling with this code,
01723                 because it affects postscript printing as well as all EPS export formats,
01724                 including Xara v1.1 "native" EPS.
01725 
01726                 When exporting to postscript, this function can only handle
01727                 1,2,4,8,24,32 bpp images.
01728 
01729                 If you want to COLOUR SEPARATE the output, you should call
01730                 ExportSeparatedData instead. 
01731 
01732                 (BTW, This code is quite hideous, but I have not changed it, because it
01733                 is too easy to break Postscript, AI EPS, Artworks EPS, and/or Camelot EPS
01734                 by doing so)
01735 
01736     SeeAlso:    CWxBitmap::ExportSeparatedData;
01737                 CamelotEPSRenderRegion::DrawParallelogramBitmap
01738 
01739 ********************************************************************************************/
01740 
01741 BOOL CWxBitmap::ExportBitmapData(RenderRegion *pRegion)
01742 {
01743 #if !defined(EXCLUDE_FROM_RALPH)
01744 RebuildXPEBitmap();
01745     // Check the render region type
01746     if (pRegion->IsKindOf(CC_RUNTIME_CLASS(CamelotEPSRenderRegion)))
01747     {
01748         // It's Camelot EPS - export the bitmap.
01749         KernelDC *pDC = (KernelDC *) CCDC::ConvertFromNativeDC(pRegion->GetRenderDC());
01750         Filter *pFilter = pDC->GetParentFilter();
01751 
01752         // Find out if it needs to be renderable
01753         BOOL Renderable = (IS_A(pRegion, CamelotEPSRenderRegion) || pRegion->IsPrinting());
01754 
01755         // If it is renderable, find out if we can use Level 2 features.
01756         BOOL UseLevel2 = FALSE;
01757 
01758         if (Renderable)
01759         {
01760 // WEBSTER-ranbirr-12/11/96
01761 #ifndef WEBSTER
01762             if (pRegion->IsPrinting())
01763             {
01764 
01765 #ifndef STANDALONE
01766                 // Get the print info for this job.
01767                 CCPrintInfo *pInfo = CCPrintInfo::GetCurrent();
01768                 if (pInfo != NULL)
01769                 {
01770                     PrintControl *pPrCtrl = pInfo->GetPrintControl();
01771                     if (pPrCtrl->GetPSLevel() == PSLEVEL_2)
01772                         // Printing to a level 2 device - party on!
01773                         UseLevel2 = TRUE;
01774                 }
01775 #else
01776     ERROR2(FALSE,"CWxBitmap::ExportBitmapData trying to print on Viewer version!");
01777 #endif
01778             }
01779             else
01780 #endif //webster
01781             {
01782                 // Use the EPS preference.
01783                 if (EPSFilter::XSEPSExportPSType == 2)
01784                     UseLevel2 = TRUE;
01785             }
01786         }
01787 
01788         // Export the bitmap pixel data itself.
01789         if (!Renderable)
01790             pDC->OutputToken(_T("%Camelot: Bitmap data"));
01791         pDC->OutputNewLine();
01792         
01793         // Do each scanline...
01794         //
01795         // NB. We add 7 to make sure we round up to the next byte for fractional bytes,
01796         //     otherwise we lose pixels at the end of scanlines for bitmaps with less
01797         //     than 8bpp depth.
01798         INT32 Width  = ((BMInfo->bmiHeader.biWidth * BMInfo->bmiHeader.biBitCount) + 7) / 8;
01799         INT32 Height = BMInfo->bmiHeader.biHeight;
01800 
01801         INT32 Ofs = 0;
01802 
01803         // If renderable, then don't pad the data (except to the next byte boundary).
01804         INT32 Padding = Renderable ? 1 : 4;
01805 
01806         // If we're printiand trying to output 32bpp, we'll output it as 24bpp
01807         BOOL Do32bpp = pRegion->IsPrinting() && (BMInfo->bmiHeader.biBitCount == 32);
01808         if (Do32bpp)
01809             Width = BMInfo->bmiHeader.biWidth * 3;  // 32bpp is converted down to 24bpp
01810 
01811         // Swap RGB data as PostScript expects it in BGR format.
01812         BOOL SwapRGB = Renderable && (BMInfo->bmiHeader.biBitCount == 24);
01813 
01814         // Expand 4bpp images to 8bpp images as the Adobe SDK imaging library does
01815         // not seem to work on some printers with 4bpp images (e.g. Canon LBP4-PS).
01816         BOOL Expand4bpp = Renderable && (BMInfo->bmiHeader.biBitCount == 4);
01817 
01818         INT32 DataSize = Width;
01819         LPBYTE pAllocatedMem = NULL;        // Memory we must remember to free on exit
01820         if (SwapRGB || Do32bpp)
01821         {
01822             // We need to swap the R and B components around as PostScript expects to get
01823             // data like this:  BGRBGRBGR...
01824             // So we need a buffer in which to do this
01825             pAllocatedMem = (LPBYTE) CCMalloc(Width);
01826             if (pAllocatedMem == NULL)
01827                 // No more memory!
01828                 return FALSE;
01829         }
01830         else if (Expand4bpp)
01831         {
01832             // We need to expand the 4bpp data to 8bpp data.
01833             // So we need a buffer in which to do this
01834             DataSize = ((BMInfo->bmiHeader.biWidth * 8) + 7) / 8;
01835             pAllocatedMem = (LPBYTE) CCMalloc(DataSize);
01836             if (pAllocatedMem == NULL)
01837                 // No more memory!
01838                 return FALSE;
01839 
01840             // Double buffer size
01841         }
01842 
01843         LPBYTE pBuf = pAllocatedMem;        // Scanline buffer pointer - may point into the source bitmap
01844 
01845         UINT32 ScanlineSize = DIBUtil::ScanlineSize(BMInfo->bmiHeader.biWidth, 
01846                                                    BMInfo->bmiHeader.biBitCount);
01847 
01848         // If we are going to do ASCII85, get ready for it.
01849         if (UseLevel2)
01850         {
01851             if (!pDC->StartASCII85Output(TRUE))  // TRUE => RLE please
01852                 // Error
01853                 return FALSE;
01854         }
01855 
01856 
01857         for (INT32 i = 0; i < Height; i++)
01858         {
01859             if (Do32bpp)
01860             {
01861                 // Take a copy of this scanline, skipping the Alpha channels, and reverse the
01862                 // RGB ordering so that PostScript can use the data directly.
01863                 INT32 k = Ofs;
01864                 for (INT32 j = 0; j < Width; j += 3)
01865                 {
01866                     pBuf[j]     = BMBytes[k + 2];
01867                     pBuf[j + 1] = BMBytes[k + 1];
01868                     pBuf[j + 2] = BMBytes[k];
01869 
01870                     k += 4;
01871                 }
01872             }
01873             else if (SwapRGB)
01874             {
01875                 // Take a copy of this scanline and reverse the RGB ordering so that
01876                 // PostScript can use the data directly.
01877                 for (INT32 j = 0; j < Width; j += 3)
01878                 {
01879                     pBuf[j]     = BMBytes[Ofs + j + 2];
01880                     pBuf[j + 1] = BMBytes[Ofs + j + 1];
01881                     pBuf[j + 2] = BMBytes[Ofs + j];
01882                 }
01883             }
01884             else if (Expand4bpp)
01885             {
01886                 // Take a copy of this 4bpp scanline and expand it to 8bpp.
01887                 INT32 k = 0;
01888                 for (INT32 j = 0; j < Width; j++)
01889                 {
01890                     pBuf[k++] = (BMBytes[Ofs + j] & 0xF0) >> 4;
01891                     pBuf[k++] = BMBytes[Ofs + j] & 0xF;
01892                 }
01893             }
01894             else
01895                 // Just point to raw data
01896                 pBuf = BMBytes + Ofs;
01897 
01898             // Write the data out, possibly encoded in ASCII85
01899             INT32 nBytes;
01900 
01901             if (UseLevel2)
01902                 // No padding needed for renderable PostScript/EPS.
01903                 nBytes = pDC->OutputASCII85(pBuf, DataSize);
01904             else
01905                 // Normal ASCII Hex output (or binary in Native files).
01906                 nBytes = pDC->OutputRawBinary(pBuf, DataSize, Padding);
01907 
01908             if (nBytes == -1)
01909             {
01910                 // Error - prob out of disc space
01911                 if (pAllocatedMem != NULL)
01912                     CCFree(pAllocatedMem);
01913 
01914                 return FALSE;
01915             }
01916 
01917             // Update progress display
01918             if (pFilter != NULL)
01919                 pFilter->UpdateExportedNodeCount(1);
01920 
01921             // Do next line
01922             Ofs += ScanlineSize;
01923         }
01924 
01925         if (UseLevel2)
01926         {
01927             if (!pDC->EndASCII85Output())
01928                 // Error
01929                 return FALSE;
01930         }
01931 
01932         // Free the temp buffer if necessary.
01933         if (pAllocatedMem != NULL)
01934             CCFree(pAllocatedMem);
01935     }
01936 #endif
01937     // If we got here, no errors occured.
01938     return TRUE;
01939 }
01940 
01941 
01942 
01943 /********************************************************************************************
01944 
01945 >   virtual BOOL CWxBitmap::ExportSeparatedData(RenderRegion *pRegion, BYTE *SepTables) const
01946                     
01947     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01948     Created:    1/7/96
01949 
01950     Inputs:     pRegion - The Postscript RenderRegion to export to. In fact, if this is
01951                 not IsKindOf(CamelotEPSRenderRegion), this function will do nothing and
01952                 return TRUE.
01953 
01954                 SepTables - See ExportBitmapData. This function should ONLY be called
01955                 with a valid SepTabls pointer, from ExportBitmapData.
01956 
01957     Returns:    TRUE for success
01958 
01959     Purpose:    Exports this bitmap's image data to the given RenderRegion, colour
01960                 separating to an 8bpp image as it does so.
01961 
01962                 This function is the colour-separating analogue of ExportBitmapData.
01963 
01964                 It is only (currently) used when printing to postscript.
01965 
01966     Notes:      Separated bitmap data is ALWAYS in the form of a greyscale 8 bits per pixel
01967 
01968                 This function can handle any input bitmap depth (1/4/8/24/32) which
01969                 CWxBitmap::ReadPixel supports.
01970 
01971                 This function may only be called when:
01972                     SepTables != NULL
01973                     pRegion->GetRenderView()->GetColourPlate()->GetType() is a separation
01974                     plate (C/M/Y/K or Spot).
01975 
01976                 Implementation: We use ReadScanline32bpp to get the bitmap data in a
01977                 generic 32bpp format, then pass a generic colour separation engine over
01978                 it to generate a generic 8bpp greyscale separated bitmap. We could be
01979                 more efficient for low bpp bitmaps, but this would just introduce more
01980                 special-cases, and more chance of it not working in some circumstances.
01981 
01982     SeeAlso:    CWxBitmap::ExportBitmapData
01983 
01984 ********************************************************************************************/
01985 
01986 BOOL CWxBitmap::ExportSeparatedData(RenderRegion *pRegion, BYTE *SepTables)
01987 {
01988 #ifndef STANDALONE
01989     ERROR3IF(pRegion == NULL || SepTables == NULL, "Illegal NULL params");
01990 
01991     if (!pRegion->IsKindOf(CC_RUNTIME_CLASS(CamelotEPSRenderRegion)))
01992     {
01993         ERROR3("Not a CamelotEPSRenderRegion derived RenderRegion - bitmap not exported");
01994         return(TRUE);       // Return success - don't shaft the whole print just for one bitmap
01995     }
01996 
01997 RebuildXPEBitmap();
01998     KernelDC *pDC = (KernelDC *) CCDC::ConvertFromNativeDC(pRegion->GetRenderDC());
01999     Filter *pFilter = pDC->GetParentFilter();
02000 
02001     // If it is renderable, find out if we can use Level 2 features.
02002     BOOL UseLevel2 = FALSE;
02003     BOOL Renderable = (IS_A(pRegion, CamelotEPSRenderRegion) || pRegion->IsPrinting());
02004 
02005     if (Renderable)
02006     {
02007 //  WEBSTER-ranbirr-12/11/96
02008 #ifndef WEBSTER
02009         if (pRegion->IsPrinting())
02010         {
02011             // Get the print info for this job.
02012             CCPrintInfo *pInfo = CCPrintInfo::GetCurrent();
02013             if (pInfo != NULL)
02014             {
02015                 PrintControl *pPrCtrl = pInfo->GetPrintControl();
02016                 UseLevel2 = (pPrCtrl->GetPSLevel() == PSLEVEL_2);
02017             }
02018         }
02019         else
02020 #endif //webster
02021 
02022             UseLevel2 = (EPSFilter::XSEPSExportPSType == 2);            // Use the EPS preference.
02023     }
02024 
02025     // Export the bitmap pixel data itself.
02026     if (!Renderable)
02027         pDC->OutputToken(_T("%Camelot: Bitmap data"));
02028     pDC->OutputNewLine();
02029     
02030     // Get some useful constants...
02031 //  const INT32 BitsPerPixel    = BMInfo->bmiHeader.biBitCount;
02032     const INT32 PixelWidth  = BMInfo->bmiHeader.biWidth;
02033     const INT32 PixelHeight = BMInfo->bmiHeader.biHeight;
02034     const INT32 ByteWidth   = PixelWidth;
02035 
02036     // If we have to change the scanlines in any way, we'll use a temporary scanline buffer
02037     // which can hold a full scanline of 8bpp pixels
02038     BYTE *pOutputBuffer = (BYTE *) CCMalloc(ByteWidth);
02039     if (pOutputBuffer == NULL)
02040     {
02041         ERROR3("Scanline buffer allocation failed");
02042         return(FALSE);
02043     }
02044 
02045     Pixel32bpp *pInputBuffer = (Pixel32bpp *) CCMalloc(PixelWidth * sizeof(Pixel32bpp));
02046     if (pInputBuffer == NULL)
02047     {
02048         ERROR3("No memory for 32bpp separation scanline");
02049         return(FALSE);
02050     }
02051 
02052     // If we are going to do ASCII85, get ready for it.
02053     if (UseLevel2 && !pDC->StartASCII85Output(TRUE))  // TRUE => RLE please
02054     {
02055         ERROR3("StartASCII85Output failed");
02056         return(FALSE);
02057     }
02058 
02059     // If separating, find a colour context for the separation to use
02060     ColourContext *OutputContext = NULL;
02061     if (SepTables != NULL)
02062     {
02063         ERROR3IF(pRegion->GetRenderView() == NULL, "Darn");
02064         OutputContext = pRegion->GetRenderView()->GetColourContext(COLOURMODEL_RGBT);
02065 
02066         ERROR3IF(OutputContext == NULL, "Double Darn");
02067     }
02068 
02069     INT32 nBytes;
02070     for (INT32 y = 0; y < PixelHeight; y++)
02071     {
02072         GetScanline32bpp(y, TRUE, pInputBuffer);
02073         ColourSeparateScanline32to8(OutputContext, SepTables, pOutputBuffer, pInputBuffer, PixelWidth);
02074 
02075         // Write the data out, possibly encoded in ASCII85
02076         if (UseLevel2)
02077             nBytes = pDC->OutputASCII85(pOutputBuffer, ByteWidth);
02078         else
02079             nBytes = pDC->OutputRawBinary(pOutputBuffer, ByteWidth, (Renderable) ? 1 : 4);
02080 
02081         if (nBytes == -1)
02082         {
02083             ERROR3("EPS output failed - Out of disc space?");
02084             CCFree(pOutputBuffer);
02085             return(FALSE);
02086         }
02087 
02088         // Update progress display
02089         if (pFilter != NULL)
02090             pFilter->UpdateExportedNodeCount(1);
02091     }
02092 
02093     CCFree(pInputBuffer);
02094     CCFree(pOutputBuffer);
02095 
02096     if (UseLevel2 && !pDC->EndASCII85Output())
02097     {
02098         ERROR3("EndASCII85Output failed");
02099         return(FALSE);
02100     }
02101     return(TRUE);
02102 #else
02103     ERROR2(FALSE,"CWxBitmap::SeparateBitmapData being called in Viewer version!");
02104 #endif
02105 }
02106 
02107 
02108 /********************************************************************************************
02109 
02110 >   virtual BOOL CWxBitmap::GetScanline32bpp(UINT32 YPos, BOOL UsePalette,
02111                                             Pixel32bpp *Scanline) const;
02112 
02113     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02114     Created:    27/6/96
02115 
02116     Inputs:     YPos - The y position of the scanline in the bitmap
02117                 UsePalette -Ignored for deep bitmaps
02118                             For <=8bpp bitmaps, if this value is:
02119                                 FALSE, the bitmap's palette will be ignored, and the actual pixel
02120                                 (palette index) value will be returned as a greyscale RGB value
02121                                 TRUE, the pixel index value will be used to retrieve the 24bpp
02122                                 palette entry for the pixel, if a palette is available.
02123 
02124     Outputs:    Scanline - will be filled in with 32bpp pixel values on return
02125 
02126     Returns:    TRUE for success
02127 
02128     Purpose:    Copies a scanline out of this bitmap into the given 32bpp buffer.
02129                 The buffer must be no less than CWxBitmap::GetWidth() entries wide.
02130 
02131                 The scanline will be converted up from 1, 4, 8, 24, or 32bpp into
02132                 the generic Pixel32bpp format.
02133 
02134     Notes:      This function basically just calls ReadPixel for all pixels in the scanline
02135 
02136     SeeAlso:    CWxBitmap::ReadPixel32bpp
02137 
02138 ********************************************************************************************/
02139 
02140 BOOL CWxBitmap::GetScanline32bpp(UINT32 YPos, BOOL UsePalette, Pixel32bpp *Scanline)
02141 {
02142 RebuildXPEBitmap();
02143     ERROR3IF(YPos < 0 || YPos > GetHeight(), "Illegal Y position");
02144     ERROR3IF(Scanline == NULL, "Illegal NULL param");
02145 
02146     for (UINT32 XPos = 0; XPos < GetWidth(); XPos++)
02147         Scanline[XPos] = ReadPixel32bpp(XPos, YPos, UsePalette);
02148 
02149     return(TRUE);
02150 }
02151 
02152 /********************************************************************************************
02153 
02154 >   virtual wxImage * CWxBitmap::MakewxImage(UINT32 ImageWidth=0, UINT32 ImageHeight=0, BOOL UsePalette=TRUE) const;
02155 
02156     Author:     Alex Bligh
02157     Created:    26/04/2006
02158 
02159     Inputs:     ImageWidth - Width of image to make (or zero for width of bitmap)
02160                 ImageHeight - Depth of image to make (or zero for depth of bitmap)
02161                 UsePalette -Ignored for deep bitmaps
02162                             For <=8bpp bitmaps, if this value is:
02163                                 FALSE, the bitmap's palette will be ignored, and the actual pixel
02164                                 (palette index) value will be returned as a greyscale RGB value
02165                                 TRUE, the pixel index value will be used to retrieve the 24bpp
02166                                 palette entry for the pixel, if a palette is available.
02167 
02168     Outputs:    None
02169 
02170     Returns:    A pointer to a wxImage, or NULL for failure
02171 
02172     Purpose:    Makes a wxBitmap, slowly
02173 
02174                 The scanline will be converted up from 1, 4, 8, 24, or 32bpp into
02175                 the generic Pixel32bpp format.
02176 
02177     Notes:      This function basically just calls ReadPixel for all pixels in the scanline
02178 
02179     SeeAlso:    CWxBitmap::ReadPixel32bpp
02180 
02181 ********************************************************************************************/
02182 
02183 wxImage * CWxBitmap::MakewxImage(UINT32 ImageWidth, UINT32 ImageHeight, BOOL UsePalette)
02184 {
02185     if (!ImageWidth)
02186         ImageWidth=GetWidth();
02187     if (!ImageHeight)
02188         ImageHeight=GetHeight();
02189 
02190     wxImage * pImage = new wxImage(GetWidth(), GetHeight(), /*TYPENOTE: Correct*/ false);
02191     if (!pImage)
02192         return NULL;
02193 #if 0
02194     pImage->SetAlpha();
02195     if (!pImage->HasAlpha())
02196     {
02197         delete pImage;
02198         return NULL;
02199     }
02200 #endif
02201 
02202     RebuildXPEBitmap();
02203 
02204     double xstep = GetWidth()/ImageWidth;
02205     double ystep = GetHeight()/ImageHeight;
02206     double x=0;
02207     double y=0;
02208 
02209     for (UINT32 YPos = 0; YPos < ImageHeight; YPos++)
02210     {
02211         UINT32 YP=(UINT32)(y+0.5);
02212         x=0;
02213         for (UINT32 XPos = 0; XPos < ImageWidth; XPos++)
02214         {
02215             UINT32 XP=(UINT32)(x+0.5);
02216             Pixel32bpp p = ReadPixel32bpp(XP, YP, UsePalette);
02217             pImage->SetRGB(XPos, YPos, p.Red, p.Blue, p.Green);
02218 //          pImage->SetAlpha(XPos, YPos, 255-p.Alpha); // wxImage alpha has 0 for fully transparent
02219 
02220             x+=xstep;
02221         }
02222         y+=ystep;
02223     }
02224 
02225     return(pImage);
02226 }
02227 
02228 
02229 /********************************************************************************************
02230 
02231 >   void CWxBitmap::ColourSeparateScanline32to8(ColourContext *OutputContext, BYTE *SepTables,
02232                                                 BYTE *DestBuffer, BYTE *SrcBuffer,
02233                                                 INT32 PixelWidth)
02234     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02235     Created:    27/6/96
02236 
02237     Inputs:     DestBuffer  - points to a destination 24bpp RGB scanline buffer
02238                 SrcBuffer   - points to a source 24bpp RGB scanline buffer
02239                 PixelWidth  - The number of pixels to copy from Src to Dest
02240 
02241     Purpose:    Copies the scanline of 32bpp BGR values from SrcBuffer to DestBuffer,
02242                 running the pixels through colour separation tables en route.
02243                 NOTE that Src and Dest may point at the same buffer to convert in-place.
02244 
02245                 The output pixels are produced in 8bpp greyscale (0=black, 255=white)
02246                 format, and will occupy only the first PixelWidth bytes of the Dest buffer.
02247 
02248                 If you're not colour-separating, then you should replace this function
02249                 call with a simple memcpy or equivalent.
02250 
02251     Notes:      ONLY handles Pixel32bpp scanlines, and expects that SepTables points
02252                 at the separation tables.
02253 
02254                 The CMYK separation plates could have been written generically, but 
02255                 I have separated out the cases in order to squeeze a bit of speed out
02256                 of the inner pixel conversion loop.
02257 
02258 ********************************************************************************************/
02259 
02260 void CWxBitmap::ColourSeparateScanline32to8(ColourContext *OutputContext, BYTE *SepTables,
02261                                                 BYTE *DestBuffer, Pixel32bpp *SrcBuffer,
02262                                                 INT32 PixelWidth)
02263 {
02264     ERROR3IF(DestBuffer == NULL || SrcBuffer == NULL || PixelWidth < 1, "Illegal params");
02265     ERROR3IF(SepTables == NULL, "No separation tables!?");
02266     ERROR3IF(OutputContext == NULL || OutputContext->GetColourPlate() == NULL,
02267                 "The separation ColourPlate has gone missing!");
02268 
02269 //RebuildXPEBitmap();
02270     // --- A wee macro to find the Maximum of R,G,B, and place it into a variable called 
02271     // Temp, which we define right now in function scope so it's always available
02272     // (It's undefined at the end of this function)
02273     BYTE Temp;
02274     #define TEMPMAX(R,G,B)                  \
02275     {                                       \
02276         Temp = ((R) > (G))  ? (R) : (G);    \
02277         Temp = (Temp > (B)) ? Temp : (B);   \
02278     }
02279 
02280 
02281     // --- Izzy, Wizzy, let's get busy
02282     INT32 i;                                    // Loop Index
02283     BYTE Ink;                               // Temporary variable for storing the ink value in
02284 
02285     BYTE *UCR = SepTables + 768 + 255;      // UCR is the 4th table, but this points at the
02286                                             // END of the table for optimisation - precalcs (255 - Temp)
02287 
02288     ColourPlateType Plate = OutputContext->GetColourPlate()->GetType();
02289     BOOL bNegate = OutputContext->GetColourPlate()->IsNegative();
02290     BYTE *LUT = NULL;
02291 
02292     switch (Plate)
02293     {
02294         case COLOURPLATE_SPOT:
02295             for (i = 0; i < PixelWidth; i++)
02296                 DestBuffer[i] = 255;
02297             return;
02298             break;
02299     
02300         case COLOURPLATE_CYAN:
02301             LUT = SepTables + 0;                // Cyan table is the 1st table
02302             break;
02303 
02304         case COLOURPLATE_MAGENTA:
02305             LUT = SepTables + 256;              // Magenta table is the 2nd table
02306             break;
02307 
02308         case COLOURPLATE_YELLOW:
02309             LUT = SepTables + 512;              // Yellow table is the 3rd table
02310             break;
02311 
02312         default:
02313             LUT = SepTables + 1024;             // Black generation is the 5th table
02314             break;
02315     }
02316 
02317 PORTNOTE("cms", "Disabled XaraCMS")
02318 #ifndef EXCLUDE_FROM_XARALX
02319     BOOL PrintRGBBlackAsKey = XaraCMS::PrintRGBBlackAsKey;
02320 #else
02321     BOOL PrintRGBBlackAsKey = TRUE;
02322 #endif
02323 
02324     for (i = 0; i < PixelWidth; i++)
02325     {
02326         // It's colour, so get the maximum of R,G,B into Temp
02327         TEMPMAX(SrcBuffer[i].Red, SrcBuffer[i].Green, SrcBuffer[i].Blue);
02328 
02329         if (!PrintRGBBlackAsKey || Temp > 0)
02330         {
02331             switch (Plate)
02332             {
02333                 case COLOURPLATE_CYAN:
02334                     Ink = 255 - SrcBuffer[i].Red;       // Cyan ink is (255 - Red)
02335                     if (Ink>UCR[-Temp])
02336                         Ink -= UCR[-Temp];
02337                     else
02338                         Ink=0;
02339                     break;
02340 
02341                 case COLOURPLATE_MAGENTA:
02342                     Ink = 255 - SrcBuffer[i].Green;     // Magenta ink is (255 - Green)
02343                     if (Ink>UCR[-Temp])
02344                         Ink -= UCR[-Temp];
02345                     else
02346                         Ink=0;
02347                     break;
02348 
02349                 case COLOURPLATE_YELLOW:
02350                     Ink = 255 - SrcBuffer[i].Blue;      // Yellow ink is (255 - Blue)
02351                     if (Ink>UCR[-Temp])
02352                         Ink -= UCR[-Temp];
02353                     else
02354                         Ink=0;
02355                     break;
02356 
02357                 default:
02358                     Ink = 255 - Temp;                   // Black ink is (255 - Temp)
02359                     break;
02360             }
02361 
02362             Ink = LUT[Ink];
02363         }
02364         else
02365         {
02366             Ink = (Plate == COLOURPLATE_KEY) ? 255 : 0;
02367         }
02368 
02369         if (bNegate)
02370             DestBuffer[i] = Ink;
02371         else
02372             DestBuffer[i] = 255 - Ink;
02373     } 
02374     // And finally, vape our helper macro
02375     #undef TEMPMAX
02376 }
02377 
02378 
02379 /********************************************************************************************
02380 
02381 >   void CWxBitmap::ColourSeparate32to32(ColourContext *OutputContext, BYTE *SepTables)
02382 
02383     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> (from ColourSeparateScanline32to8)
02384     Created:    02/03/2004
02385 
02386     Inputs:     OutputContext   - The context to get the separation plate from
02387                 SepTables       - points to the separation tables
02388 
02389     Purpose:    Converts the bitmap in-place from full colour 32 bpp RGB to 
02390                 the relevant separation returning the result as 32 bpp with correct
02391                 colours for the specified plate
02392 
02393 ********************************************************************************************/
02394 
02395 void CWxBitmap::ColourSeparate32to32(ColourPlate *pPlate, BYTE *SepTables)
02396 {
02397     ERROR3IF(SepTables == NULL, "No separation tables!?");
02398     ERROR3IF(pPlate == NULL, "The separation ColourPlate has gone missing!");
02399 
02400     RebuildXPEBitmap();
02401     
02402     ERROR3IF(GetBPP() != 32, "Bitmap not 32bpp!");
02403 
02404     DWORD NumPixels = GetWidth() * GetHeight();
02405     BGRT* pPixel = (BGRT*)GetBitmapBits();
02406 
02407     // --- A wee macro to find the Maximum of R,G,B, and place it into a variable called 
02408     // Temp, which we define right now in function scope so it's always available
02409     // (It's undefined at the end of this function)
02410     BYTE Temp;
02411     #define TEMPMAX(R,G,B)                  \
02412     {                                       \
02413         Temp = ((R) > (G))  ? (R) : (G);    \
02414         Temp = (Temp > (B)) ? Temp : (B);   \
02415     }
02416 
02417     // --- Izzy, Wizzy, let's get busy
02418     DWORD i;                                    // Loop Index
02419     BYTE Ink;                               // Temporary variable for storing the ink value in
02420 
02421     BYTE *UCR = SepTables + 768 + 255;      // UCR is the 4th table, but this points at the
02422                                             // END of the table for optimisation - precalcs (255 - Temp)
02423 
02424     ColourPlateType Plate = pPlate->GetType();
02425     ColourPlateType OutputPlate = pPlate->IsMonochrome() ? COLOURPLATE_KEY : Plate;
02426     BOOL bNegate = pPlate->IsNegative();
02427     BYTE *LUT = NULL;
02428 
02429     switch (Plate)
02430     {
02431         case COLOURPLATE_CYAN:
02432             LUT = SepTables + 0;                // Cyan table is the 1st table
02433             break;
02434 
02435         case COLOURPLATE_MAGENTA:
02436             LUT = SepTables + 256;              // Magenta table is the 2nd table
02437             break;
02438 
02439         case COLOURPLATE_YELLOW:
02440             LUT = SepTables + 512;              // Yellow table is the 3rd table
02441             break;
02442 
02443         default:
02444             LUT = SepTables + 1024;             // Black generation is the 5th table
02445             break;
02446     }
02447 
02448 PORTNOTE("cms", "Disabled XaraCMS")
02449 #ifndef EXCLUDE_FROM_XARALX
02450     BOOL PrintRGBBlackAsKey = XaraCMS::PrintRGBBlackAsKey;
02451 #else
02452     BOOL PrintRGBBlackAsKey = TRUE;
02453 #endif
02454 
02455     for (i = 0; i < NumPixels; i++)
02456     {
02457         // It's colour, so get the maximum of R,G,B into Temp
02458         TEMPMAX(pPixel[i].Red, pPixel[i].Green, pPixel[i].Blue);
02459 
02460         if (!PrintRGBBlackAsKey || Temp > 0)
02461         {
02462             switch (Plate)
02463             {
02464                 case COLOURPLATE_CYAN:
02465                     Ink = 255 - pPixel[i].Red;      // Cyan ink is (255 - Red)
02466                     if (Ink>UCR[-Temp])
02467                         Ink -= UCR[-Temp];
02468                     else
02469                         Ink=0;
02470                     break;
02471 
02472                 case COLOURPLATE_MAGENTA:
02473                     Ink = 255 - pPixel[i].Green;    // Magenta ink is (255 - Green)
02474                     if (Ink>UCR[-Temp])
02475                         Ink -= UCR[-Temp];
02476                     else
02477                         Ink=0;
02478                     break;
02479 
02480                 case COLOURPLATE_YELLOW:
02481                     Ink = 255 - pPixel[i].Blue;     // Yellow ink is (255 - Blue)
02482                     if (Ink>UCR[-Temp])
02483                         Ink -= UCR[-Temp];
02484                     else
02485                         Ink=0;
02486                     break;
02487 
02488                 default:
02489                     Ink = 255 - Temp;                   // Black ink is (255 - Temp)
02490                     break;
02491             }
02492 
02493             Ink = LUT[Ink];
02494         }
02495         else
02496         {
02497             Ink = (Plate == COLOURPLATE_KEY) ? 255 : 0;
02498         }
02499 
02500         if (bNegate)
02501             Ink = 255 - Ink;
02502 
02503         switch (OutputPlate)
02504         {
02505             case COLOURPLATE_CYAN:
02506                 pPixel[i].Red = 255 - Ink;
02507                 pPixel[i].Green = 255;
02508                 pPixel[i].Blue = 255;
02509                 break;
02510 
02511             case COLOURPLATE_MAGENTA:
02512                 pPixel[i].Red = 255;
02513                 pPixel[i].Green = 255 - Ink;
02514                 pPixel[i].Blue = 255;
02515                 break;
02516 
02517             case COLOURPLATE_YELLOW:
02518                 pPixel[i].Red = 255;
02519                 pPixel[i].Green = 255;
02520                 pPixel[i].Blue = 255 - Ink;
02521                 break;
02522 
02523             default:
02524                 pPixel[i].Red = 255 - Ink;
02525                 pPixel[i].Green = 255 - Ink;
02526                 pPixel[i].Blue = 255 - Ink;
02527                 break;
02528         }
02529     } 
02530     // And finally, vape our helper macro
02531     #undef TEMPMAX
02532 }
02533 
02534 
02535 /********************************************************************************************
02536 
02537 >   CWxBitmap* CWxBitmap::MakeSeparatedCopy(ColourPlate *pPlate, BYTE *SepTables)
02538 
02539     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
02540     Created:    04/03/2004
02541     Returns:    pointer to a copy of this bitmap, NULL if it fails
02542     Purpose:    To make an colour separated copy of this bitmap
02543 
02544 
02545 ********************************************************************************************/
02546 
02547 OILBitmap* CWxBitmap::MakeSeparatedCopy(ColourPlate *pPlate, BYTE *SepTables)
02548 {
02549     ERROR3IF(SepTables == NULL, "No separation tables!?");
02550     ERROR3IF(pPlate == NULL, "The separation ColourPlate has gone missing!");
02551 
02552     if (SepTables == NULL || pPlate == NULL)
02553         return(NULL);
02554 
02555     RebuildXPEBitmap();
02556     // check to see that theres something to copy
02557     if (BMInfo == NULL || BMBytes == NULL)
02558     {
02559         ERROR3("This bitmap has no bits or info to copy!");
02560         return NULL;
02561     }
02562 
02563     LPBYTE pNewBits = NULL;
02564     LPBITMAPINFO pNewInfo = NULL;
02565 
02566     pNewInfo = AllocDIB(BMInfo->bmiHeader.biWidth, BMInfo->bmiHeader.biHeight, 32, &pNewBits);
02567 
02568     if (pNewInfo == NULL || pNewBits == NULL)
02569     {
02570         ERROR3("Failed to allocate bitmap structures");
02571         return NULL;
02572     }
02573 
02574     Pixel32bpp *pScanline = (Pixel32bpp *) CCMalloc(BMInfo->bmiHeader.biWidth * sizeof(Pixel32bpp));
02575     if (pScanline == NULL)
02576         return(NULL);
02577     BGRT* pPixel = (BGRT*)pNewBits;
02578 
02579     // --- A wee macro to find the Maximum of R,G,B, and place it into a variable called 
02580     // Temp, which we define right now in function scope so it's always available
02581     // (It's undefined at the end of this function)
02582     BYTE Temp;
02583     #define TEMPMAX(R,G,B)                  \
02584     {                                       \
02585         Temp = ((R) > (G))  ? (R) : (G);    \
02586         Temp = (Temp > (B)) ? Temp : (B);   \
02587     }
02588 
02589     // --- Izzy, Wizzy, let's get busy
02590     INT32 scan;
02591     INT32 i;                                // Loop Index
02592     BYTE Ink;                               // Temporary variable for storing the ink value in
02593 
02594     BYTE *UCR = SepTables + 768 + 255;      // UCR is the 4th table, but this points at the
02595                                             // END of the table for optimisation - precalcs (255 - Temp)
02596 
02597     ColourPlateType Plate = pPlate->GetType();
02598     ColourPlateType OutputPlate = pPlate->IsMonochrome() ? COLOURPLATE_KEY : Plate;
02599     BOOL bNegate = pPlate->IsNegative();
02600     BYTE *LUT = NULL;
02601 
02602     switch (Plate)
02603     {
02604         case COLOURPLATE_CYAN:
02605             LUT = SepTables + 0;                // Cyan table is the 1st table
02606             break;
02607 
02608         case COLOURPLATE_MAGENTA:
02609             LUT = SepTables + 256;              // Magenta table is the 2nd table
02610             break;
02611 
02612         case COLOURPLATE_YELLOW:
02613             LUT = SepTables + 512;              // Yellow table is the 3rd table
02614             break;
02615 
02616         default:
02617             LUT = SepTables + 1024;             // Black generation is the 5th table
02618             break;
02619     }
02620 
02621 PORTNOTE("cms", "Disabled XaraCMS")
02622 #ifndef EXCLUDE_FROM_XARALX
02623     BOOL PrintRGBBlackAsKey = XaraCMS::PrintRGBBlackAsKey;
02624 #else
02625     BOOL PrintRGBBlackAsKey = TRUE;
02626 #endif
02627 
02628     for (scan = 0; scan < BMInfo->bmiHeader.biHeight; scan++)
02629     {
02630         GetScanline32bpp(scan, TRUE, pScanline);
02631         for (i = 0; i < BMInfo->bmiHeader.biWidth; i++)
02632         {
02633             // It's colour, so get the maximum of R,G,B into Temp
02634             TEMPMAX(pScanline[i].Red, pScanline[i].Green, pScanline[i].Blue);
02635 
02636             if (!PrintRGBBlackAsKey || Temp > 0)
02637             {
02638                 switch (Plate)
02639                 {
02640                     case COLOURPLATE_CYAN:
02641                         Ink = 255 - pScanline[i].Red;       // Cyan ink is (255 - Red)
02642                         if (Ink>UCR[-Temp])
02643                             Ink -= UCR[-Temp];
02644                         else
02645                             Ink=0;
02646                         break;
02647 
02648                     case COLOURPLATE_MAGENTA:
02649                         Ink = 255 - pScanline[i].Green;     // Magenta ink is (255 - Green)
02650                         if (Ink>UCR[-Temp])
02651                             Ink -= UCR[-Temp];
02652                         else
02653                             Ink=0;
02654                         break;
02655 
02656                     case COLOURPLATE_YELLOW:
02657                         Ink = 255 - pScanline[i].Blue;      // Yellow ink is (255 - Blue)
02658                         if (Ink>UCR[-Temp])
02659                             Ink -= UCR[-Temp];
02660                         else
02661                             Ink=0;
02662                         break;
02663 
02664                     default:
02665                         Ink = 255 - Temp;                   // Black ink is (255 - Temp)
02666                         break;
02667                 }
02668 
02669                 Ink = LUT[Ink];
02670             }
02671             else
02672             {
02673                 Ink = (Plate == COLOURPLATE_KEY) ? 255 : 0;
02674             }
02675 
02676             if (bNegate)
02677                 Ink = 255 - Ink;
02678 
02679             switch (OutputPlate)
02680             {
02681                 case COLOURPLATE_CYAN:
02682                     pPixel[i].Red = 255 - Ink;
02683                     pPixel[i].Green = 255;
02684                     pPixel[i].Blue = 255;
02685                     break;
02686 
02687                 case COLOURPLATE_MAGENTA:
02688                     pPixel[i].Red = 255;
02689                     pPixel[i].Green = 255 - Ink;
02690                     pPixel[i].Blue = 255;
02691                     break;
02692 
02693                 case COLOURPLATE_YELLOW:
02694                     pPixel[i].Red = 255;
02695                     pPixel[i].Green = 255;
02696                     pPixel[i].Blue = 255 - Ink;
02697                     break;
02698 
02699                 default:
02700                     pPixel[i].Red = 255 - Ink;
02701                     pPixel[i].Green = 255 - Ink;
02702                     pPixel[i].Blue = 255 - Ink;
02703                     break;
02704             }
02705             pPixel[i].Transparency = pScanline[i].Alpha;
02706         }
02707         pPixel += BMInfo->bmiHeader.biWidth;        // Pointer arithmetic!!!
02708     }
02709 
02710     // And finally, vape our helper macro
02711     #undef TEMPMAX
02712 
02713     CWxBitmap* pNewBitmap = new CWxBitmap(pNewInfo, pNewBits);
02714 
02715     CCFree(pScanline);
02716 
02717     if (pNewBitmap == NULL)
02718     {
02719         ERROR3("Failed to allocate new CWxBitmap");
02720         FreeDIB(pNewInfo, pNewBits);
02721     }
02722     return pNewBitmap;
02723 }
02724 
02725 
02726 
02727 /********************************************************************************************
02728 
02729 >   virtual BOOL CWxBitmap::WritePalette(BaseCamelotFilter *pFilter)
02730 
02731     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
02732     Created:    20/06/96
02733     Inputs:     pFilter         - the filter to use to write the data.
02734     Outputs:    -
02735     Returns:    True if data saved ok, False otherwise
02736     Purpose:    Function used when exporting an 8bpp JPEG into the web file and we need to
02737                 squirt the palette information into the record ready for reuse when the file
02738                 is loaded back in.
02739 
02740 ********************************************************************************************/
02741 
02742 BOOL CWxBitmap::WritePalette(BaseCamelotFilter* pFilter)
02743 {
02744     ERROR2IF(pFilter == NULL,FALSE,"CWxBitmap::WritePalette null pFilter");
02745 RebuildXPEBitmap();
02746 
02747     BOOL ok = TRUE;
02748 
02749     UINT32 NumberOfPaletteEntries = GetNumPaletteEntries();
02750     ERROR2IF(NumberOfPaletteEntries == 0 || NumberOfPaletteEntries > 256, FALSE,"Palette entries 0 or > 256!");
02751     // We will save the number of palette entries as a byte, 0 - 255
02752     BYTE Entries = NumberOfPaletteEntries - 1;
02753     if (ok) ok = pFilter->Write(Entries);
02754     for (UINT32 i = 0; i < NumberOfPaletteEntries; i++)
02755     {
02756 #if !defined(__WXMSW__)
02757 //TRACEUSER("Phil", _T("WritePalette r=%x g=%x b=%x\n"), BMInfo->bmiColors[i].rgbBlue, BMInfo->bmiColors[i].rgbGreen, BMInfo->bmiColors[i].rgbRed);
02758         if (ok) ok = pFilter->Write(BMInfo->bmiColors[i].rgbBlue);
02759         if (ok) ok = pFilter->Write(BMInfo->bmiColors[i].rgbGreen);
02760         if (ok) ok = pFilter->Write(BMInfo->bmiColors[i].rgbRed);
02761 #else
02762 //TRACEUSER("Phil", _T("WritePalette r=%x g=%x b=%x\n"), BMInfo->bmiColors[i].rgbRed, BMInfo->bmiColors[i].rgbGreen, BMInfo->bmiColors[i].rgbBlue);
02763         if (ok) ok = pFilter->Write(BMInfo->bmiColors[i].rgbRed);
02764         if (ok) ok = pFilter->Write(BMInfo->bmiColors[i].rgbGreen);
02765         if (ok) ok = pFilter->Write(BMInfo->bmiColors[i].rgbBlue);
02766 #endif
02767     }
02768 
02769     // During the preparation process we told the system we would update by the
02770     // the number of entries in the palette, so do so
02771     pFilter->IncProgressBarCount(NumberOfPaletteEntries);
02772 
02773     return ok;
02774 }
02775 
02776 /********************************************************************************************
02777 
02778 >   virtual BOOL CWxBitmap::Convert24To8(RGBTRIPLE *pPalette, UINT32 NumberOfPaletteEntries)
02779 
02780     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
02781     Created:    4/9/96
02782     Inputs:     pPalette    - pointer to the palette in RGBTIPLE format to use when converting
02783                 NumberOfPaletteEntries - entries in this palette 
02784     Outputs:    -
02785     Returns:    True if worked ok, False otherwise
02786     Purpose:    Converts the OILbitmap from its present 24bpp form into an 8bpp form which
02787                 should closely match the one that was exported.
02788                 
02789                 Assumes that the bitmap is newly loaded in and hence can easily be deleted.
02790 
02791 ********************************************************************************************/
02792 
02793 BOOL CWxBitmap::Convert24To8(RGBTRIPLE *pPalette, UINT32 NumberOfPaletteEntries)
02794 {
02795     ERROR2IF(pPalette == NULL,FALSE,"KernelBitmap::Convert24To8 null pFilter");
02796     ERROR2IF(NumberOfPaletteEntries == 0,FALSE,"KernelBitmap::Convert24To8 NumberOfPaletteEntries = 0");
02797 RebuildXPEBitmap();
02798 
02799     BOOL ok = TRUE;
02800 TRACEUSER("Neville", wxT("CWxBitmap::Convert24To8 NumberOfPaletteEntries = %d\n"),NumberOfPaletteEntries);
02801 
02802     LPBITMAPINFO pDestBMInfo = NULL;
02803     LPBYTE pDestBMBytes = NULL;
02804 
02805     // Ask the DIB convert class to do the conversion for us
02806     ok = DIBUtil::Convert24to8( BMInfo, BMBytes, &pDestBMInfo, &pDestBMBytes, 
02807                                 pPalette, NumberOfPaletteEntries);
02808 
02809     if (ok)
02810     {
02811         // Free up the 24bpp version
02812         FreeDIB( BMInfo, BMBytes );
02813 
02814         // Hot swap it for the 8bpp version
02815         BMInfo = pDestBMInfo;
02816         BMBytes = pDestBMBytes;
02817 
02818         pDestBMInfo = NULL;
02819         pDestBMBytes = NULL;
02820 
02821         ScanLineByteWidth = 0;
02822         BitmapSize = 0; // in bytes
02823 
02824         CacheGeometry();
02825     }
02826 
02827     if (pDestBMInfo != NULL)
02828     {
02829         delete pDestBMInfo;
02830     }
02831 
02832     if (pDestBMBytes != NULL)
02833     {
02834         delete pDestBMBytes;
02835     }
02836 
02837     return ok;
02838 }
02839 
02840 /********************************************************************************************
02841 
02842 >   BOOL CWxBitmap::ImportBitmap(CCLexFile* pFile, BaseBitmapFilter* pBitmapFilter,
02843                                  BaseCamelotFilter* pFilter, BOOL IsCompressed)
02844 
02845     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
02846     Created:    20/06/96
02847     Inputs:     pFile           - the file to read the data from
02848                 pBitmapFilter   - the bitmap filter object to import the bitmap with.
02849                 pFilter         - the BaseCamelotFilter which provides functions like progress update
02850                 IsCompressed    - Flag to say the bitmap is compressed or not.  
02851     Returns:    TRUE if the bitmap was imported ok;
02852                 FALSE if not.
02853     Purpose:    Imports a bitmap object using the import filter provided. It is used by the
02854                 web/native filters to pull out a bitmap definition from inside a bitmap
02855                 definition record.
02856                 IsCompressed is only used for BMP/BMPZIP type bitmaps at present.
02857                 Assumes:
02858                     pFile has already been opened up for reading
02859                     pFilter has been set up for reading the data e.g. progress bar 
02860     Errors:     Out of memory, error in file data.
02861     SeeAlso:    CWxBitmap::ExportBitmap
02862 
02863 ********************************************************************************************/
02864 
02865 BOOL CWxBitmap::ImportBitmap(CCLexFile* pFile, BaseBitmapFilter* pBitmapFilter,
02866                              BaseCamelotFilter* pFilter, BOOL IsCompressed)
02867 {
02868     ERROR2IF(pFile == NULL,FALSE,"CWxBitmap::ImportBitmap null pFile");
02869     ERROR2IF(pBitmapFilter == NULL,FALSE,"CWxBitmap::ImportBitmap null pBitmapFilter");
02870     ERROR2IF(pFilter == NULL,FALSE,"CWxBitmap::ImportBitmap null pFilter");
02871 
02872     // Try to import bitmap using the required bitmap filter class.
02873     // Tell it to import into this CWxBitmap.
02874     if (pBitmapFilter->ReadFromFile(this, pFilter, pFile, IsCompressed))
02875     {
02876         CacheGeometry();
02877         return TRUE;
02878     }
02879 
02880     return FALSE;
02881 }
02882 
02883 
02884 
02885 /********************************************************************************************
02886 
02887 >   BOOL CWxBitmap::ImportBitmap(Filter *pFilter, const BitmapInfo *pInfo, 
02888                                  INT32 BitmapType)
02889 
02890     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
02891     Created:    23/08/94
02892     Inputs:     pFilter - the filter object to import with.
02893                 pInfo - details of the bitmap to import, or NULL if this should be obtained
02894                         from the file.
02895                 BitmapType - the type of bitmap data in the file.  This is usually 0, and
02896                              exists as a way of supporting platform-dependent bitmap
02897                              arrangements on different platforms.
02898     Returns:    TRUE if the bitmap was imported ok;
02899                 FALSE if not.
02900     Purpose:    Import a bitmap object using the given bitmap specification and the 
02901                 import filter provided.
02902     Errors:     Out of memory, error in file data.
02903     SeeAlso:    CWxBitmap::ExportBitmap
02904 
02905 ********************************************************************************************/
02906 
02907 BOOL CWxBitmap::ImportBitmap(Filter *pFilter, const BitmapInfo *pInfo, INT32 BitmapType)
02908 {
02909     // Check to see what the specified filter type is and take the appropriate action
02910     // If a bitmap type of filter (derived off BaseBitmapFilter) e.g. BMPFilter or
02911     // AccusoftFilters then pInfo will be NULL and we just need to load the bitmap in
02912     // using the specified filter.
02913     if (pFilter->IsKindOf(CC_RUNTIME_CLASS(BaseBitmapFilter)))
02914     {
02915         BaseBitmapFilter* pBitmapFilter = (BaseBitmapFilter*)pFilter;
02916 
02917         // Try to import bitmap using the required bitmap filter class.
02918         // Tell it to import into this CWxBitmap.
02919         if (pBitmapFilter->ReadFromFile(this))
02920         {
02921             CacheGeometry();
02922             return TRUE;
02923         }
02924         else
02925             return FALSE;
02926     }
02927     
02928     if (!pFilter->IsKindOf(CC_RUNTIME_CLASS(CamelotEPSFilter)))
02929     {
02930         ENSURE(FALSE, "Trying to import a bitmap with a non-Camelot EPS filter");
02931         return FALSE;
02932     }
02933     
02934     // Sanity checks
02935     ENSURE((pInfo->PixelDepth == 1) ||
02936            (pInfo->PixelDepth == 4) ||
02937            (pInfo->PixelDepth == 8) ||
02938            (pInfo->PixelDepth == 24) ||
02939            (pInfo->PixelDepth == 32), "Bad bitmap depth in ImportBitmap!");
02940 
02941     if ((pInfo->NumPaletteEntries > 0) && (pInfo->PixelDepth > 8))
02942     {
02943         ENSURE(FALSE, "We don't support palettes on bitmaps >8bpp!");
02944     }
02945 
02946 //  if (!IsUserName("Alex"))
02947 //  {
02948 //      ENSURE(BitmapType == 0, "Unknown bitmap type in CWxBitmap::ImportBitmap");
02949 //      if (BitmapType != 0)
02950 //          return FALSE;
02951 //  }
02952 
02953     CamelotEPSFilter *pEPSFilter = (CamelotEPSFilter *) pFilter;
02954 
02955     ENSURE((BMInfo == NULL) && (BMBytes == NULL),
02956            "Trying to import into an existing bitmap");
02957 
02958     // Allocate memory for bitmap
02959     BMInfo = AllocDIB(pInfo->PixelWidth, pInfo->PixelHeight, pInfo->PixelDepth, 
02960                       &BMBytes, NULL);
02961     if (BMInfo == NULL)
02962     {
02963         // Out of memory
02964         ENSURE(FALSE, "Failed to allocate memory to import bitmap!");
02965         return FALSE;
02966     }
02967 
02968     //BMInfo->bmiHeader.biXPelsPerMeter = Mul32Div32(pInfo->PixelWidth, MILLIS_PER_METRE, 
02969     //                                             pInfo->RecommendedWidth);
02970     //BMInfo->bmiHeader.biYPelsPerMeter = Mul32Div32(pInfo->PixelHeight, MILLIS_PER_METRE, 
02971     //                                             pInfo->RecommendedHeight);
02972     // Use the conversion value defined in units.h so that we are consistent
02973     // Also try and round up as well as down
02974     double xppm = ((double)pInfo->PixelWidth * M_MP_VAL)/ (double)(pInfo->RecommendedWidth);
02975     double yppm = ((double)pInfo->PixelHeight * M_MP_VAL)/ (double)(pInfo->RecommendedHeight);
02976     BMInfo->bmiHeader.biXPelsPerMeter = (INT32)(xppm + 0.5);
02977     BMInfo->bmiHeader.biYPelsPerMeter = (INT32)(yppm + 0.5);
02978 
02979     if ((BMInfo->bmiHeader.biXPelsPerMeter < 0) || 
02980         (BMInfo->bmiHeader.biYPelsPerMeter < 0))
02981     {
02982         ENSURE(FALSE, "Bad pixel size");
02983         return FALSE;
02984     }
02985 
02986     // Header is done; read the palette data if we need to 
02987     if (((pInfo->PixelDepth <= 8)) && (pInfo->NumPaletteEntries > 0))
02988     {
02989         if (!pEPSFilter->ImportBinary((BYTE *) BMInfo->bmiColors, 
02990                                       BMInfo->bmiHeader.biClrUsed * sizeof(RGBQUAD)))
02991         {
02992             // Error in hex data
02993             return FALSE;
02994         }
02995     }
02996 
02997     // Set the information up
02998     CacheGeometry();
02999 
03000     // And read in the image data
03001 //  if (IsUserName("Alex")) if (BitmapType !=0) return(TRUE);
03002 
03003     // Read in the Bitmap info
03004     if (pFilter->IsKindOf(CC_RUNTIME_CLASS(CamelotNativeEPSFilter)))
03005     {
03006         // Load it in scan line at a time please
03007         INT32 NumScanLines = pInfo->PixelHeight;
03008         for (INT32 i=0; i<NumScanLines; i++)
03009         {
03010             // read a scan line in
03011             if (!pEPSFilter->ImportBinary(BMBytes + (i*ScanLineByteWidth), ScanLineByteWidth))
03012                 return FALSE;
03013         }
03014 
03015         // all worked
03016         return TRUE;
03017     }
03018     else
03019     {
03020         // Load it all in, in one go.
03021         return pEPSFilter->ImportBinary(BMBytes, BMInfo->bmiHeader.biSizeImage);
03022     }
03023 
03024     // Should not get here really.
03025     return FALSE;
03026 }
03027 
03028 
03029 
03030 /********************************************************************************************
03031 
03032 >   virtual void CWxBitmap::PlotPixel(INT32 x, INT32 y, Pixel32bpp NewValue) = 0;
03033                     
03034     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> (rewrote Alex's disgusting hack)
03035     Created:    3/7/96
03036 
03037     Inputs:     x, y - coordinates within the bitmap of the pixel to plot
03038                 NewValue - a 32bpp pixel value.
03039 
03040     Outputs:    (changes attached oil bitmap)
03041     Returns:    Nothing
03042     Purpose:    Plots a 32bpp pixel to a deep bitmap (24, or 32bpp)
03043 
03044                 Currently unimplemented for 16bpp
03045                 Makes no sense for <= 8bpp
03046 
03047     Notes:      In debug builds, will check all kinds of stuff, but in release
03048                 builds, it assumes that you are providing legal offsets in the bitmap,
03049                 and are only using this call where it will work - this is to reduce
03050                 retail overhead on each pixel operation.
03051 
03052                 Will probably fail horribly if you haven't called CacheGeometry
03053         
03054     Errors:     ERROR3 if the bitmap is not 16, 24, or 32bpp
03055 
03056 ********************************************************************************************/
03057 
03058 void CWxBitmap::PlotPixel(INT32 x, INT32 y, Pixel32bpp NewValue)
03059 {
03060 RebuildXPEBitmap();
03061     ERROR3IF(BMInfo == NULL || BMBytes == NULL, "PlotPixel called on duff bitmap");
03062     ERROR3IF(x < 0 || y < 0 || x >= (INT32)GetWidth() || y >= (INT32)GetHeight(),
03063                 "Illegal pixel position in CWxBitmap::PlotPixel");
03064 
03065     BYTE *ScanlineStart = BMBytes + (y * ScanLineByteWidth);
03066 
03067     switch(BMInfo->bmiHeader.biBitCount)
03068     {
03069         case 16:
03070             ERROR3("Unimplemented code");
03071             break;
03072 
03073         case 24:
03074             ScanlineStart[x * 3 + 0] = NewValue.Red;
03075             ScanlineStart[x * 3 + 1] = NewValue.Green;
03076             ScanlineStart[x * 3 + 2] = NewValue.Blue;
03077             break;
03078 
03079         case 32:
03080             ScanlineStart[x * 4 + 0] = NewValue.Red;
03081             ScanlineStart[x * 4 + 1] = NewValue.Green;
03082             ScanlineStart[x * 4 + 2] = NewValue.Blue;
03083             ScanlineStart[x * 4 + 3] = NewValue.Alpha;
03084             break;
03085 
03086         default:    
03087             ERROR3("Unsupported (non-deep) bitmap format in PlotPixel(32bpp)");
03088             break;
03089     }
03090 }
03091 
03092 
03093 
03094 /********************************************************************************************
03095 
03096 >   virtual void CWxBitmap::PlotPixel(INT32 x, INT32 y, PixelGreyscale NewValue) = 0;
03097                     
03098     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> (rewrote Alex's disgusting hack)
03099     Created:    3/7/96
03100 
03101     Inputs:     x, y - coordinates within the bitmap of the pixel to plot
03102                 NewValue - an 8bpp pixel value, presumed to be a greyscale.
03103 
03104     Outputs:    (changes attached oil bitmap)
03105     Returns:    Nothing
03106 
03107     Purpose:    Plots an 8bpp (0..255) pixel to any type of bitmap
03108                 The pixel is taken to be a greyscale, and is truncated or expanded
03109                 as appropriate to fit the greyscale value into the destination bitmap
03110                 pixel format.
03111 
03112                 (Only 8, 24, and 32bpp formats are currently supported)
03113 
03114     Notes:      In debug builds, will check all kinds of stuff, but in release
03115                 builds, it assumes that you are providing legal offsets in the bitmap,
03116                 and are only using this call where it will work - this is to reduce
03117                 retail overhead on each pixel operation.
03118 
03119                 Will probably fail horribly if you haven't called CacheGeometry
03120         
03121     Errors:     ERROR3 if the bitmap is not 16, 24, or 32bpp
03122 
03123 ********************************************************************************************/
03124 
03125 void CWxBitmap::PlotPixel(INT32 x, INT32 y, PixelGreyscale NewValue)
03126 {
03127 RebuildXPEBitmap();
03128     ERROR3IF(BMInfo == NULL || BMBytes == NULL, "PlotPixel called on duff bitmap");
03129     ERROR3IF(x < 0 || y < 0 || x >= (INT32)GetWidth() || y >= (INT32)GetHeight(),
03130                 "Illegal pixel position in CWxBitmap::PlotPixel");
03131 
03132     BYTE *ScanlineStart = BMBytes + (y * ScanLineByteWidth);
03133 
03134     switch(BMInfo->bmiHeader.biBitCount)
03135     {
03136         case 8:
03137             ScanlineStart[x] = NewValue;
03138             break;
03139 
03140         case 24:
03141             ScanlineStart[x * 3 + 0] = \
03142                 ScanlineStart[x * 3 + 1] = \
03143                     ScanlineStart[x * 3 + 2] = NewValue;
03144             break;
03145 
03146         case 32:
03147             ScanlineStart[x * 4 + 0] = \
03148                 ScanlineStart[x * 4 + 1] = \
03149                     ScanlineStart[x * 4 + 2] = NewValue;
03150 
03151             ScanlineStart[x * 4 + 3] = 0;
03152             break;
03153 
03154         default:    
03155             ERROR3("Unsupported bitmap format in PlotPixel(8bpp)");
03156             break;
03157     }
03158 }
03159 
03160 
03161 
03162 /********************************************************************************************
03163 
03164 >   virtual Pixel32bpp CWxBitmap::ReadPixel32bpp(INT32 x, INT32 y, BOOL UsePalette = TRUE) const
03165                     
03166     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03167     Created:    3/7/96
03168     Inputs:     x, y - coordinates of the pixel to read
03169                 UsePalette -Ignored for deep bitmaps
03170                             For <=8bpp bitmaps, if this value is:
03171                                 FALSE, the bitmap's palette will be ignored, and the actual pixel
03172                                 (palette index) value will be returned as a greyscale RGB value
03173                                 TRUE, the pixel index value will be used to retrieve the 24bpp
03174                                 palette entry for the pixel, if a palette is available.
03175 
03176     Returns:    The pixel value of the given pixel, in 32bpp format
03177 
03178     Purpose:    reads a pixel
03179 
03180     Notes:      In debug builds, will check all kinds of stuff, but in release
03181                 builds, it assumes that you are providing legal offsets in the bitmap,
03182                 and are only using this call where it will work - this is to reduce
03183                 retail overhead on each pixel operation.
03184 
03185                 NOTE that for <=8bpp bitmaps, the behavior is as follows:
03186                     * If paletted, the value returned is the 24bit RGB looked up in the
03187                       palette
03188                     * Otherwise, the pixel value is assumed to be a greyscale intensity
03189                       and is converted into a 24bit RGB where R = G = B = intensity.
03190 
03191     SeeAlso:    CWxBitmap::ReadPixelGreyscale
03192 
03193 ********************************************************************************************/
03194 
03195 inline Pixel32bpp CWxBitmap::ReadPixel32bpp(INT32 x, INT32 y, BOOL UsePalette)
03196 {
03197 RebuildXPEBitmap();
03198     ERROR3IF(BMInfo == NULL || BMBytes == NULL, "PlotPixel called on duff bitmap");
03199     ERROR3IF(x < 0 || y < 0 || x >= (INT32)GetWidth() || y >= (INT32)GetHeight(),
03200                 "Illegal pixel position in CWxBitmap::ReadPixel");
03201 
03202     BYTE *ScanlineStart = BMBytes + (y * ScanLineByteWidth);
03203 
03204     Pixel32bpp Pix;
03205     Pix.Alpha = 0;                      // Generally there is no alpha channel, so set it to a default
03206 
03207     if (UsePalette && BMInfo->bmiHeader.biClrUsed < 1)
03208         UsePalette = FALSE;                             // No palette, so can't use one!
03209 
03210     switch(BMInfo->bmiHeader.biBitCount)
03211     {
03212         case 1:
03213             {
03214                 BYTE Temp = ScanlineStart[x >> 3];      // Get the byte containing the pixel (x / 8)
03215                 Temp &= 0x80 >> (x & 7);                // Mask out all bits except the pixel (x % 8)
03216 
03217                 // Look up in the palette, if any, else assume it's a greyscale (b&w)
03218                 if (UsePalette)
03219                 {
03220                     Temp = (Temp == 0) ? 0 : 1;
03221                     Pix.Red     = BMInfo->bmiColors[Temp].rgbRed;
03222                     Pix.Green   = BMInfo->bmiColors[Temp].rgbGreen;
03223                     Pix.Blue    = BMInfo->bmiColors[Temp].rgbBlue;
03224                 }
03225                 else
03226                 {
03227                     Temp = (Temp == 0) ? 0 : 255;
03228                     Pix.Red = Pix.Green = Pix.Blue = Temp;
03229                 }
03230             }
03231             break;
03232 
03233         case 4:
03234             {
03235                 BYTE Temp = ScanlineStart[x / 2];       // Get the byte containing the pixel
03236 
03237                 // Look up in the palette, if any, else assume it's a greyscale
03238                 if (UsePalette)
03239                 {
03240                     // Pull out the pixel's palette index
03241                     if ((x & 1) == 0)
03242                         Temp = (Temp >> 4) & 0x0f;                          // High nybble
03243                     else
03244                         Temp &= 0x0f;                                       // Low nybble
03245 
03246                     Pix.Red     = BMInfo->bmiColors[Temp].rgbRed;
03247                     Pix.Green   = BMInfo->bmiColors[Temp].rgbGreen;
03248                     Pix.Blue    = BMInfo->bmiColors[Temp].rgbBlue;
03249                 }
03250                 else
03251                 {
03252                     // And pull out the actual pixel value. Note that we repeat the nybble twice
03253                     // into the final byte to get the correct 8bpp greyscale value (white is FF, not F0!)
03254                     if ((x & 1) == 0)
03255                         Temp = (Temp & 0xf0) | ((Temp & 0xf0) >> 4);        // High nybble
03256                     else
03257                         Temp = (Temp & 0x0f) | ((Temp & 0x0f) << 4);        // Low nybble
03258 
03259                     Pix.Red = Pix.Green = Pix.Blue = Temp;
03260                 }
03261             }
03262             break;
03263 
03264         case 8:
03265             // Look up in the palette, if any, else assume it's a greyscale
03266             if (UsePalette)
03267             {
03268                 Pix.Red     = BMInfo->bmiColors[ScanlineStart[x]].rgbRed;
03269                 Pix.Green   = BMInfo->bmiColors[ScanlineStart[x]].rgbGreen;
03270                 Pix.Blue    = BMInfo->bmiColors[ScanlineStart[x]].rgbBlue;
03271             }
03272             else
03273                 Pix.Red = Pix.Green = Pix.Blue = ScanlineStart[x];
03274             break;
03275 
03276         case 24:
03277             x *= 3;
03278             Pix.Blue    = ScanlineStart[x++];
03279             Pix.Green   = ScanlineStart[x++];
03280             Pix.Red     = ScanlineStart[x++];
03281             break;
03282 
03283         case 32:
03284             x *= 4;
03285             Pix.Blue    = ScanlineStart[x++];
03286             Pix.Green   = ScanlineStart[x++];
03287             Pix.Red     = ScanlineStart[x++];
03288             Pix.Alpha   = ScanlineStart[x++];
03289             break;
03290 
03291         default:    
03292             Pix.Red = Pix.Green = Pix.Blue = 0;
03293             ERROR3("Unsupported bitmap format in ReadPixel(32bpp)");
03294             break;
03295     }
03296 
03297     return(Pix);
03298 }
03299 
03300 
03301 /******************************************************************************************
03302 
03303 >   INT32 CWxBitmap::ReturnPaletteIndexUsed( INT32 x, INT32 y ) const
03304 
03305     Author:     Alex_Price (Xara Group Ltd) <camelotdev@xara.com>
03306 
03307     Created:    29/09/99
03308 
03309     Inputs:     x, y - The x and y co-ordinates of the pixel under consideration
03310 
03311     Returns:    -1 if something went wrong, otherwise the relevant palette index.
03312 
03313     Purpose:    When the user clicks in, or moves the mouse over a pixel in one of the 
03314                 preview images, this function is called to work out the actual palette 
03315                 index of the colour used.
03316 
03317     Notes:      This function is based on the function ReadPixel32bpp()
03318 
03319 ******************************************************************************************/
03320 
03321 INT32 CWxBitmap::ReturnPaletteIndexUsed( INT32 x, INT32 y )
03322 {
03323 RebuildXPEBitmap();
03324     ERROR3IF(BMInfo == NULL || BMBytes == NULL, "PlotPixel called on duff bitmap");
03325     ERROR3IF(x < 0 || y < 0 || x >= (INT32)GetWidth() || y >= (INT32)GetHeight(),
03326                 "Illegal pixel position in CWxBitmap::ReadPixel");
03327 
03328     BYTE *ScanlineStart = BMBytes + (y * ScanLineByteWidth);
03329 
03330     INT32 PaletteIndex;
03331 
03332     switch(BMInfo->bmiHeader.biBitCount)
03333     {
03334         case 1:
03335             {
03336                 BYTE Temp = ScanlineStart[x >> 3];      // Get the byte containing the pixel (x / 8)
03337                 Temp &= 0x80 >> (x & 7);                // Mask out all bits except the pixel (x % 8)
03338                 Temp = (Temp == 0) ? 0 : 1;
03339                 PaletteIndex = Temp;
03340             }
03341             break;
03342 
03343         case 4:
03344             {
03345                 BYTE Temp = ScanlineStart[x / 2];       // Get the byte containing the pixel
03346 
03347                 // Pull out the pixel's palette index
03348                 if ((x & 1) == 0)
03349                     Temp = (Temp >> 4) & 0x0f;
03350                 else
03351                     Temp &= 0x0f;
03352 
03353                 PaletteIndex = Temp;
03354             }
03355             break;
03356 
03357         case 8:
03358             PaletteIndex = ScanlineStart[x];
03359             break;
03360 
03361         default:    
03362             PaletteIndex = -1;
03363             ERROR3( "Couldn't find the palette index" );
03364             break;
03365     }
03366 
03367     return PaletteIndex;
03368 }
03369 
03370 
03371 /********************************************************************************************
03372 
03373 >   inline PixelGreyscale CWxBitmap::ReadPixelGreyscale(INT32 x, INT32 y) const
03374                     
03375     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03376     Created:    3/7/96
03377     Inputs:     x, y - coordinates of the pixel to read
03378 
03379     Returns:    The pixel value of the given pixel, as an 8bpp greyscale
03380 
03381     Purpose:    reads a pixel
03382 
03383     Notes:      In debug builds, will check all kinds of stuff, but in release
03384                 builds, it assumes that you are providing legal offsets in the bitmap,
03385                 and are only using this call where it will work - this is to reduce
03386                 retail overhead on each pixel operation.
03387 
03388                 Coloured pixels from deep bitmaps will be converted to greyscales
03389                 Pixels from <=8bpp bitmaps will be read directly, and ASSUMED to be in
03390                 a greyscale format (e.g. it does NOT read the palette entry for the
03391                 pixel value and convert that to a greyscale)
03392 
03393     SeeAlso:    CWxBitmap::ReadPixel32bpp
03394 
03395 ********************************************************************************************/
03396 
03397 PixelGreyscale CWxBitmap::ReadPixelGreyscale(INT32 x, INT32 y)
03398 {
03399 RebuildXPEBitmap();
03400     ERROR3IF(BMInfo == NULL || BMBytes == NULL, "PlotPixel called on duff bitmap");
03401     ERROR3IF(x < 0 || y < 0 || x >= (INT32)GetWidth() || y >= (INT32)GetHeight(),
03402                 "Illegal pixel position in CWxBitmap::ReadPixel");
03403 
03404     BYTE *ScanlineStart = BMBytes + (y * ScanLineByteWidth);
03405     PixelGreyscale Pix;
03406 
03407     switch(BMInfo->bmiHeader.biBitCount)
03408     {
03409         case 1:
03410             {
03411                 BYTE Temp = ScanlineStart[x >> 3];      // Get the byte containing the pixel (x / 8)
03412                 Temp &= 0x80 >> (x & 7);                // Mask out all bits except the pixel (x % 8)
03413 
03414                 Pix = (Temp == 0) ? 0 : 255;
03415             }
03416             break;
03417 
03418         case 4:
03419             {
03420                 BYTE Temp = ScanlineStart[x / 2];       // Get the byte containing the pixel
03421 
03422                 // And pull out the actual pixel value. Note that we repeat the nybble twice
03423                 // into the final byte to get the correct 8bpp greyscale value (white is FF, not F0!)
03424                 if ((x & 1) == 0)
03425                     Temp = (Temp & 0xf0) | ((Temp & 0xf0) >> 4);        // High nybble
03426                 else
03427                     Temp = (Temp & 0x0f) | ((Temp & 0x0f) << 4);        // Low nybble
03428 
03429                 Pix = Temp;
03430             }
03431             break;
03432 
03433         case 8:
03434             Pix = ScanlineStart[x];
03435             break;
03436 
03437         case 24:
03438             {
03439                 double Temp;
03440 
03441                 x *= 3;
03442                 Temp  = 0.109 * (double) ScanlineStart[x++];        // B
03443                 Temp += 0.586 * (double) ScanlineStart[x++];        // G
03444                 Temp += 0.305 * (double) ScanlineStart[x];          // R
03445 
03446                 Pix = (BYTE) Temp;
03447             }
03448             break;
03449  
03450         case 32:
03451             {
03452                 double Temp;
03453 
03454                 x *= 4;
03455                 Temp  = 0.109 * (double) ScanlineStart[x++];        // B
03456                 Temp += 0.586 * (double) ScanlineStart[x++];        // G
03457                 Temp += 0.305 * (double) ScanlineStart[x];          // R
03458                                                                     // Alpha
03459                 Pix = (BYTE) Temp;
03460             }
03461             break;
03462 
03463         default:    
03464             Pix = 0;
03465             ERROR3("Unsupported bitmap format in ReadPixel(32bpp)");
03466             break;
03467     }
03468 
03469     return(Pix);
03470 }
03471 
03472 
03473 
03474 /********************************************************************************************
03475 
03476 >   void CWxBitmap::CacheGeometry
03477                     
03478     Author:     Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com>
03479     Created:    14/9/94
03480     Inputs:     None
03481     Outputs:    Caches scanline widths etc in the CWxBitmap
03482     Returns:    Nothing
03483     Purpose:    Sets up the cached info in the header so the plot routines will work fast
03484     Errors:     -
03485     SeeAlso:    -
03486 
03487 ********************************************************************************************/
03488 
03489 void CWxBitmap::CacheGeometry()
03490 {
03491     if (BMInfo)
03492     {
03493         // For now we need to restrict the size of the bitmaps
03494         // Hopefully a KernelBitmap member along the lines of PostProcessNewBitmap(pDocument)
03495         // will be provided at some stage to do something better
03496         // For now restrict it to the length of the shorter A0 side
03497         // The minimum size is the number of pixels as millipoints
03498         // This can probably done mathematically as well
03499         LPBITMAPINFOHEADER pHeader = &(BMInfo->bmiHeader);
03500 
03501         if (pHeader->biXPelsPerMeter != 0 || pHeader->biYPelsPerMeter != 0)
03502         {
03503             const double MaxSize    = 0.84;
03504 
03505             const double MaxWidth   = MaxSize;
03506             const double Width      = pHeader->biWidth;
03507             const double MinWidth   = Width / M_MP_VAL;
03508             const double XDensity   = pHeader->biXPelsPerMeter;
03509             const double RealWidth  = Width / XDensity;
03510             INT32 XRecommended = (INT32)(96 * (M_MP_VAL / IN_MP_VAL));
03511 
03512             const double MaxHeight  = MaxSize;
03513             const double Height     = pHeader->biHeight;
03514             const double MinHeight  = Height / M_MP_VAL;
03515             const double YDensity   = pHeader->biYPelsPerMeter;
03516             const double RealHeight = Height / YDensity;
03517             INT32 YRecommended = (INT32)(96 * (M_MP_VAL / IN_MP_VAL));
03518 
03519             const double AspectRatio = XDensity / YDensity;
03520 
03521             BOOL bIsTooBig      = FALSE;
03522             BOOL bIsTooSmall    = FALSE;
03523 
03524             // Check the width isn't too small or large
03525             if (pHeader->biXPelsPerMeter != 0)
03526             {
03527                 if (RealWidth > MaxWidth)
03528                 {
03529                     XRecommended = (INT32)(pHeader->biWidth / MaxWidth);
03530                     bIsTooBig = TRUE;
03531                 }
03532                 else if (RealWidth < MinWidth)
03533                 {
03534                     XRecommended = (INT32)(pHeader->biWidth / MinWidth);
03535                     bIsTooSmall = TRUE;
03536                 }
03537             }
03538 
03539             // Check the height is neither too large nor too small, but just right
03540             if (pHeader->biXPelsPerMeter != 0)
03541             {
03542                 if (RealHeight > MaxHeight)
03543                 {
03544                     YRecommended = (INT32)(pHeader->biHeight / MaxHeight);
03545                     bIsTooBig = TRUE;
03546                 }
03547                 else if (RealHeight < MinHeight)
03548                 {
03549                     YRecommended = (INT32)(pHeader->biHeight / MinHeight);
03550                     bIsTooSmall = TRUE;
03551                 }
03552             }
03553             // This is gorgeous...
03554             // If it's being awkward pick a density
03555             if (bIsTooBig || bIsTooSmall)
03556             {
03557                 if ((bIsTooBig && bIsTooSmall) || AspectRatio != 1.0)
03558                 {
03559                     // It's being really awkward so forget it and use the default
03560                     pHeader->biXPelsPerMeter = 0;
03561                     pHeader->biYPelsPerMeter = 0;
03562                 }
03563                 // From here on we know the original densities were the same.
03564                 // We'll pick the density that gives us the closest to the desired size
03565                 else if ((bIsTooBig && XRecommended > YRecommended) ||
03566                         (bIsTooSmall && XRecommended < YRecommended))
03567                 {
03568                     pHeader->biXPelsPerMeter = XRecommended;
03569                     pHeader->biYPelsPerMeter = XRecommended;
03570                 }
03571                 else
03572                 {
03573                     pHeader->biXPelsPerMeter = YRecommended;
03574                     pHeader->biYPelsPerMeter = YRecommended;
03575                 }
03576             }
03577         }
03578 
03579         ScanLineByteWidth = DIBUtil::ScanlineSize( pHeader->biWidth, pHeader->biBitCount );
03580         BitmapSize = ScanLineByteWidth*(pHeader->biHeight); // in bytes
03581     }
03582     else
03583     {
03584         ScanLineByteWidth = 0;
03585         BitmapSize = 0;
03586     }
03587 }
03588 
03589 
03590 
03591 /********************************************************************************************
03592 
03593 >   virtual INT32 CWxBitmap::operator==(const OILBitmap &Other)
03594                 
03595     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
03596     Created:    26/1/95
03597     Inputs:     The other bitmap to compare this one with
03598     Returns:    TRUE, or FALSE.
03599     Purpose:    Checks to see if one bitmap is the same as another.
03600     Errors:     -
03601     SeeAlso:    -
03602 
03603 ********************************************************************************************/
03604 
03605 INT32 CWxBitmap::operator==(const OILBitmap &Other)
03606 {
03607     CWxBitmap* OtherBmp = (CWxBitmap*)&Other;
03608 OtherBmp->RebuildXPEBitmap();
03609 
03610     if (BMInfo == NULL || OtherBmp->BMInfo == NULL)
03611         return FALSE;   // If either of the Info fields are NULL, then 
03612                         // they are either not the same, or we can't tell !!
03613 
03614     if (BMBytes == NULL || OtherBmp->BMBytes == NULL)
03615         return FALSE;   // If either of the Bytes are NULL, then 
03616                         // they are either not the same, or we can't tell !!
03617 
03618     // Lets check the Bitmap Header first
03619     if (BMInfo->bmiHeader.biSizeImage   != OtherBmp->BMInfo->bmiHeader.biSizeImage  ||
03620         BMInfo->bmiHeader.biWidth       != OtherBmp->BMInfo->bmiHeader.biWidth      ||
03621         BMInfo->bmiHeader.biHeight      != OtherBmp->BMInfo->bmiHeader.biHeight     ||
03622         BMInfo->bmiHeader.biBitCount    != OtherBmp->BMInfo->bmiHeader.biBitCount   ||
03623         BMInfo->bmiHeader.biClrUsed     != OtherBmp->BMInfo->bmiHeader.biClrUsed    ||
03624 
03625         BMInfo->bmiHeader.biXPelsPerMeter != OtherBmp->BMInfo->bmiHeader.biXPelsPerMeter ||
03626         BMInfo->bmiHeader.biYPelsPerMeter != OtherBmp->BMInfo->bmiHeader.biYPelsPerMeter)
03627     {
03628         return FALSE;
03629     }
03630     
03631     // Well they looks similar, but the only way to be sure, is to compare the Bits !!
03632 
03633     // First lets check the Palettes
03634     if (BMInfo->bmiHeader.biBitCount <= 8)
03635     {
03636         INT32 NumCols   = BMInfo->bmiHeader.biClrUsed;
03637         INT32* Pal      = (INT32*)BMInfo->bmiColors;
03638         INT32* OtherPal     = (INT32*)OtherBmp->BMInfo->bmiColors;
03639 
03640         // Is the palette the same ?
03641         if (memcmp(Pal, OtherPal, NumCols*4) != 0)
03642             return FALSE;
03643     }
03644 
03645     // Well the Palettes are the Same .... Lets check the actual data now.
03646 
03647     INT32 Width     = BMInfo->bmiHeader.biWidth;
03648     INT32 Height = BMInfo->bmiHeader.biHeight;
03649     INT32 Bpp   = BMInfo->bmiHeader.biBitCount;
03650 
03651 /*
03652 // Alas, this doesn't work.
03653 
03654     // go and compare 'em
03655     if ((BMInfo->bmiHeader.biSizeImage != OtherBmp->BMInfo->bmiHeader.biSizeImage) ||
03656         (memcmp(BMBytes, OtherBmp->BMBytes, BMInfo->bmiHeader.biSizeImage)!=0))
03657         return FALSE;
03658 
03659     // Blimey !! They're the Same !!
03660     return TRUE;
03661 */
03662 
03663     // How many (whole) bytes are there in each scan line ?
03664     INT32 ScanLineBytes = (Width * Bpp) / 8;
03665 
03666     INT32 ExtraBits = 0;
03667     BYTE BitMask = 0;
03668 
03669     if (Bpp < 8)
03670     {
03671         // For less than 8 bpp the scanlines could
03672         // end on a sub-byte point
03673         ExtraBits = (Width * Bpp) - (ScanLineBytes * 8);    // ie.(width * bpp) % 8
03674         //BitMask = (1<<ExtraBits) - 1;
03675         const BYTE BitMaskArray[8] = {0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE};
03676         ERROR3IF (ExtraBits < 0 || ExtraBits > 7, "CWxBitmap::operator== - extraordinary ExtraBits");
03677         BitMask = BitMaskArray[ExtraBits];  // NB.ExtraBits == 0 not used
03678     }
03679 
03680     // The scan lines are always DWord or Word Aligned,
03681     // So now get the actual bytes need to skip over a scanline
03682     INT32 ScanAlign = DIBUtil::ScanlineSize(Width, Bpp);
03683 
03684     BYTE* BmpData = BMBytes;
03685     BYTE* OtherBmpData = OtherBmp->BMBytes;
03686 
03687     for (INT32 Scan = 0; Scan < Height; Scan++)
03688     {
03689         // Is this scan line the same ?
03690         if (memcmp(BmpData, OtherBmpData, ScanLineBytes) != 0)
03691             return FALSE;
03692 
03693         if (ExtraBits > 0)
03694         {
03695             // The scanlines are not exactly byte aligned, so we'll get the DWORD
03696             // after the whole number of bytes, and mask off the bits that we
03697             // are interested in
03698             // Actually as we've just compared ScanLineBytes we need only check the
03699             // last byte (which is byte aligned)
03700             BYTE BmpExtraByte = *(BmpData + ScanLineBytes) & BitMask;
03701             BYTE OtherExtraByte = *(OtherBmpData + ScanLineBytes) & BitMask;
03702             //INT32 ExtraBmpWord    = (*((INT32*)(BmpData + ScanLineBytes))) & BitMask;
03703             //INT32 ExtraOtherWord = (*((INT32*)(OtherBmpData + ScanLineBytes))) & BitMask;
03704 
03705             // Are the extra bits the same ?
03706             if (BmpExtraByte != OtherExtraByte)
03707                 return FALSE;
03708         }
03709 
03710         BmpData         += ScanAlign;
03711         OtherBmpData    += ScanAlign;
03712     }
03713 
03714     // Blimey !! They're the Same !!
03715     return TRUE;
03716 }
03717 
03718 /********************************************************************************************
03719 
03720 >   virtual BOOL CWxBitmap::LoadBitmap(UINT32 BitmapResourceID)
03721                 
03722     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
03723     Created:    26/1/95
03724     Inputs:     The Resource ID of the bitmap to Load
03725     Returns:    TRUE, or FALSE (Loaded or Failed).
03726     Purpose:    Loads a bitmap from the resources.
03727     Errors:     -
03728     SeeAlso:    -
03729 
03730 ********************************************************************************************/
03731 
03732 BOOL CWxBitmap::LoadBitmap(UINT32 BitmapResourceID)
03733 {
03734     wxBitmap * pBitmap=CamArtProvider::Get()->FindBitmap((ResourceID)BitmapResourceID);
03735     if (!pBitmap)
03736         return FALSE;
03737 
03738     return CreateFromwxBitmap(pBitmap);
03739 }
03740 
03741 BOOL CWxBitmap::CreateFromwxBitmap(wxBitmap * pBitmap)
03742 {
03743     wxImage i = pBitmap->ConvertToImage();
03744     return CreateFromwxImage(&i);
03745 }
03746 
03747 BOOL CWxBitmap::CreateFromwxImage(wxImage * pImage)
03748 {
03749     LPBITMAPINFO bmInfo;
03750     LPBYTE bmBytes;
03751 
03752     bmInfo = AllocDIB( pImage->GetWidth(), pImage->GetHeight(), 32, &bmBytes );
03753     if (!bmInfo || !bmBytes)
03754         return FALSE;
03755 
03756     BMInfo=bmInfo;
03757     BMBytes=bmBytes;
03758 
03759     INT32 dpi=96;
03760 
03761     double xppm = ((double)dpi * 10000.0)/254.0;
03762     bmInfo->bmiHeader.biXPelsPerMeter = (INT32)(xppm + 0.5);
03763     bmInfo->bmiHeader.biYPelsPerMeter = bmInfo->bmiHeader.biXPelsPerMeter;
03764 
03765     CacheGeometry();
03766 
03767     unsigned char * pData=pImage->GetData();
03768     unsigned char * pAlpha=NULL;
03769     if (pImage->HasAlpha())
03770         pAlpha=pImage->GetAlpha();
03771 
03772     // Reasonably rapid conversion to internal format
03773     for (UINT32 YPos = 0; YPos < GetHeight(); YPos++)
03774     {
03775         // DIBs are the wrong way up
03776         BYTE *ScanlineStart = BMBytes + ((GetHeight()-YPos-1) * ScanLineByteWidth);
03777         INT32 off=0;
03778 
03779         for (UINT32 XPos = 0; XPos < GetWidth(); XPos++)
03780         {
03781             ScanlineStart[off++] = pData[2]; //Red
03782             ScanlineStart[off++] = pData[1]; //Green
03783             ScanlineStart[off++] = pData[0]; //Blue
03784             pData+=(UINT_PTR)3;
03785             ScanlineStart[off++] = pAlpha?(255-*(pAlpha++)):0; // Alpha
03786         }
03787     }
03788 
03789     return TRUE;
03790 }
03791 
03792 /********************************************************************************************
03793 
03794 >   BOOL CWxBitmap::GetPaletteUsage(INT32 *pUsageBuf)
03795 
03796     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
03797     Created:    3/7/95
03798     Outputs:    pUsageBuf - array of longs big enough to hold the usage stats of the 
03799                 palette for this bitmap.
03800     Returns:    TRUE if ok;
03801                 FALSE if an error occured (e.g. this is not a paletted bitmap!)
03802     Purpose:    Find out how many times each palette entry is used in the bitmap.
03803                 This is currently used when rendering paletted images to PostScript.
03804     Errors:     Not a paletted bitmap.
03805     SeeAlso:    CWxBitmap::GetScanlineMask
03806 
03807 ********************************************************************************************/
03808 
03809 BOOL CWxBitmap::GetPaletteUsage(INT32 *UsageBuf)
03810 {
03811     ERROR3("CWxBitmap::GetPaletteUsage is unimplemented");
03812     return(FALSE);
03813 
03814 /*
03815     I can't see ANYTHING in this code which is even remotely likely to work!
03816 
03817     ---
03818 
03819     // Make sure this is a paletted image
03820     if ((BMInfo->bmiHeader.biBitCount < 4) ||
03821         (BMInfo->bmiHeader.biBitCount > 8) ||
03822         (BMInfo->bmiHeader.biClrUsed == 0))
03823     {
03824         // This bitmap does not have a palette!
03825         return FALSE;
03826     }
03827 
03828     CacheGeometry();
03829 
03830     if (BytesPerPixelShift !=-1)
03831         return FALSE;
03832             
03833     if ((BytesPerPixelShift < 0) || (BytesPerPixelShift > 2))
03834         return FALSE;
03835 
03836     const UINT32 Width  = BMInfo->bmiHeader.biWidth;
03837     const UINT32 Height = BMInfo->bmiHeader.biHeight;
03838     INT32 Index = 0;
03839 
03840     // Special case for 4bpp bitmaps
03841     BOOL Is4bpp = (BMInfo->bmiHeader.biBitCount == 4);
03842 
03843     for (UINT32 x = 0; x < Width; x++)
03844     {
03845         for (UINT32 y = 0; y > Height; y++)
03846         {
03847             INT32 p = (y * ScanLineByteWidth) + (x << BytesPerPixelShift);
03848 
03849             if (p < BitmapSize)
03850             {
03851                 if (Is4bpp)
03852                 {
03853                 }
03854                 else
03855                 {
03856                     switch (BytesPerPixelShift)
03857                     {
03858                         case 0:
03859                             Index = (INT32)(*( ((LPBYTE)(BMBytes + p))) <<24 );
03860                             break;
03861 
03862                         case 1:
03863                             Index = (INT32)(*( ((LPWORD)(BMBytes + p))) <<16 );
03864                             break;
03865 
03866                         case 2:
03867                             Index = (INT32)(*( ((LPDWORD)(BMBytes + p))) );
03868                             break;
03869                     }
03870                 }
03871 
03872                 UsageBuf[Index]++;
03873             }
03874         }
03875     }
03876 
03877     ENSURE(FALSE,"CWxBitmap::ReadPixel memory address out of range");
03878     return(0);
03879 */
03880 }
03881 
03882 BOOL CWxBitmap::PrepareMask(INT32 PaletteEntry)
03883 {
03884     return FALSE;
03885 }
03886 
03887 /********************************************************************************************
03888 
03889 >   BOOL CWxBitmap::GetScanlineMaskBits(INT32 ScanlineY, LPBYTE ScanlineBuf)
03890 
03891     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
03892     Created:    3/7/95
03893     Inputs:     PaletteEntry - which entry to build a mask for.
03894                 ScanlineY - the scanline to get the mask for. (0 => bottom line of bitmap)
03895     Outputs:    ScanlineBuf - where to put the 1bpp mask - this should be large enough to
03896                               hold one scanline's worth of mask.
03897     Returns:    TRUE if successful;
03898                 FALSE if not (e.g. this is not a paletted bitmap).
03899     Purpose:    Given a palette
03900     Errors:     Not a paletted bitmap
03901     SeeAlso:    CWxBitmap::GetPaletteUsage
03902 
03903 ********************************************************************************************/
03904 
03905 BOOL CWxBitmap::GetScanlineMaskBits(INT32 ScanlineY, LPBYTE ScanlineBuf)
03906 {
03907     return TRUE;
03908 }
03909 
03910 BOOL CWxBitmap::DestroyMask()
03911 {
03912     return FALSE;
03913 }
03914 
03915 
03916 /********************************************************************************************
03917 
03918 >   void CWxBitmap::DeleteData(BOOL bResetToDefault = TRUE)
03919 
03920     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
03921     Created:    12/8/96
03922     Purpose:    Deletes the actual bitmap data.
03923 
03924 ********************************************************************************************/
03925 
03926 void CWxBitmap::DeleteData(BOOL bResetToDefault)
03927 {
03928 //  ERROR2IF(this == OILBitmap::Default, FALSE, "Someone is trying to delete the default bitmap data");
03929 
03930     FreeDIB( BMInfo, BMBytes );
03931     BMInfo = NULL;
03932     BMBytes = NULL;
03933 
03934     if (bResetToDefault)
03935     {
03936         BMInfo  = ((CWxBitmap*)OILBitmap::Default)->BMInfo;
03937         BMBytes = ((CWxBitmap*)OILBitmap::Default)->BMBytes;
03938         
03939         ScanLineByteWidth   = ((CWxBitmap*)OILBitmap::Default)->ScanLineByteWidth;
03940         BitmapSize          = ((CWxBitmap*)OILBitmap::Default)->BitmapSize;
03941 
03942         DestroyGreyscaleVersion();
03943         DestroyContonePalette();
03944     }
03945 
03946     return;
03947 }
03948 
03949 /********************************************************************************************
03950 
03951 >   BOOL CWxBitmap::HasBeenDeleted()
03952 
03953 
03954     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
03955     Created:    12/8/96
03956     Purpose:    Returns whether or not the actual bitmap data has been deleted.
03957 
03958 ********************************************************************************************/
03959 
03960 BOOL CWxBitmap::HasBeenDeleted()
03961 { 
03962     if (this == OILBitmap::Default)
03963         return FALSE;       // Can't delete the default bitmap
03964 
03965     ERROR3IF(OILBitmap::Default == NULL, "The default bitmap is NULL");
03966     if (OILBitmap::Default == NULL)
03967         return TRUE;
03968 
03969     // If we are using the default bitmap data, then we must have been deleted
03970     return (BMBytes == ((CWxBitmap*)OILBitmap::Default)->BMBytes);
03971 }
03972 
03973 /********************************************************************************************
03974 
03975 >   void CWxBitmap::GenerateGreyscaleTable()
03976 
03977     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
03978     Created:    15/8/96
03979     Purpose:    -
03980 
03981 ********************************************************************************************/
03982 
03983 void CWxBitmap::GenerateGreyscaleTable()
03984 {
03985 RebuildXPEBitmap();
03986 //  if (GetBPP() != 8)
03987     if (GetBPP()>8)
03988         return;
03989     UINT32 bpp = GetBPP() ;
03990 
03991     if (m_pGreyscaleTable != NULL)
03992         return;
03993 
03994     m_pGreyscaleTable = new BYTE[1<<bpp];
03995     if (m_pGreyscaleTable == NULL)
03996         return;
03997 
03998     for (INT32 i=0; i<1<<bpp; i++)
03999     {
04000         double R = BMInfo->bmiColors[i].rgbRed;
04001         double G = BMInfo->bmiColors[i].rgbGreen;
04002         double B = BMInfo->bmiColors[i].rgbBlue;
04003 
04004         m_pGreyscaleTable[i] = BYTE((R * 0.305) + (G * 0.586) + (B * 0.109));
04005 //      TRACEUSER( "Will", _T("Intensity[%d] = %d\n"), i, m_pGreyscaleTable[i]);
04006     }
04007 }
04008 
04009 /********************************************************************************************
04010 
04011 >   BOOL CWxBitmap::IsBrowserPalette() const
04012 
04013     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
04014     Created:    16/06/97
04015     Returns:    True if the bitmap has a browser compatible palette.
04016     Purpose:    To see if the palette attached to this bitmap is browser compatible.
04017                 It runs through the colours in a browser palette and checks to see if they
04018                 are all present. The ordering is not checked and so the palette may be
04019                 different from the one that we actually use.
04020 
04021 ********************************************************************************************/
04022 
04023 BOOL CWxBitmap::IsBrowserPalette()
04024 {
04025     // Not interested in deep bitmaps
04026     if (GetBPP() != 8)
04027         return FALSE;
04028 
04029 RebuildXPEBitmap();
04030     UINT32 PaletteEntries = GetNumPaletteEntries();
04031     if (PaletteEntries < 216)
04032         return FALSE;
04033     
04034     // Borrow the code from PaletteManager::MakePaletteBrowserCompatible
04035     TRACEUSER( "Neville", wxT("Checking 216 colours\n") );
04036     BOOL found = FALSE;
04037     for (INT32 r = 0; r <= 100; r += 20)
04038     {
04039         for (INT32 g = 0; g <=100; g += 20)
04040         {
04041             for (INT32 b = 0; b <= 100; b += 20)
04042             {
04043                 BYTE ra = BYTE((double(r)/100)*255.0);
04044                 BYTE ga = BYTE((double(g)/100)*255.0);
04045                 BYTE ba = BYTE((double(b)/100)*255.0);
04046 
04047                 for (UINT32 i = 0; i < PaletteEntries && !found; i++)
04048                 {
04049                     found = BMInfo->bmiColors[i].rgbRed   == ra &&
04050                             BMInfo->bmiColors[i].rgbGreen == ga &&
04051                             BMInfo->bmiColors[i].rgbBlue  == ba;
04052                 }
04053 
04054                 if (!found)
04055                 {
04056                     TRACEUSER( "Neville", wxT("Colour not found - %d %d %d\n") ,r , g, b );
04057                     return FALSE;
04058                 }
04059             }
04060         }
04061     }
04062 
04063     // reached here so found all 216 colours
04064     TRACEUSER( "Neville", wxT("216 colours check finished\n") );
04065     return TRUE;    
04066 }
04067 
04068 /********************************************************************************************
04069 
04070 >   LPRGBQUAD CWxBitmap::GetPaletteForBitmap()
04071 
04072     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
04073     Created:    03/07/97
04074     Returns:    The BITMAPINFO for this bitmap or null.
04075     Purpose:    To get at the BITMAPINFO palette that this bitmap may have.
04076                 
04077                 BITMAPINFO  consists of:-
04078                         BITMAPINFOHEADER    bmiHeader;
04079                         RGBQUAD             bmiColors[1];
04080 
04081 ********************************************************************************************/
04082 
04083 LPBITMAPINFO CWxBitmap::GetBitmapInfo()
04084 {
04085 RebuildXPEBitmap();
04086     return BMInfo;
04087 }
04088 
04089 /********************************************************************************************
04090 
04091 >   LPRGBQUAD CWxBitmap::GetPaletteForBitmap()
04092 
04093     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
04094     Created:    03/07/97
04095     Returns:    The palette for this bitmap or null.
04096     Purpose:    To get at the RGBQUAD palette that this bitmap may have.
04097                 
04098                 BITMAPINFO  consists of:-
04099                         BITMAPINFOHEADER    bmiHeader;
04100                         RGBQUAD             bmiColors[1];
04101 
04102 ********************************************************************************************/
04103 
04104 LPRGBQUAD CWxBitmap::GetPaletteForBitmap()
04105 {
04106     // Not interested in deep bitmaps
04107     if (GetBPP() > 8)
04108         return NULL;
04109 
04110 RebuildXPEBitmap();
04111     if (BMInfo == NULL)
04112         return NULL;
04113 
04114     // Return the palette from the BITMAPINFO structure
04115     return &(BMInfo->bmiColors[0]);
04116 }
04117 
04118 /********************************************************************************************
04119 
04120 >   LPBITMAPINFOHEADER CWxBitmap::GetBitmapInfoHeader()
04121 
04122     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
04123     Created:    03/07/97
04124     Returns:    The bitmap header for this bitmap or null.
04125     Purpose:    To get at the BITMAPINFOHEADER that this bitmap should have.
04126                 
04127                 BITMAPINFO  consists of:-
04128                         BITMAPINFOHEADER    bmiHeader;
04129                         RGBQUAD             bmiColors[1];
04130 
04131 ********************************************************************************************/
04132 
04133 LPBITMAPINFOHEADER CWxBitmap::GetBitmapInfoHeader()
04134 {
04135 RebuildXPEBitmap();
04136     if (BMInfo == NULL)
04137         return NULL;
04138 
04139     // Return the BITMAPINFOHEADER for this bitmap
04140     return &BMInfo->bmiHeader;
04141 }
04142 
04143 /********************************************************************************************
04144 
04145 >   BOOL CWxBitmap::ArePalettesTheSame(const LPLOGPALETTE pLogPalette, const INT32 TransColour = -1)
04146 
04147     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
04148     Created:    03/07/97
04149     Inputs:     pLogPalette     A log palette to check the palette against
04150                 TransColour     The transparent colour in the palette
04151     Returns:    True if the bitmap has the same palette as the LOG palette.
04152     Purpose:    To see if the palette attached to this bitmap is browser compatible.
04153                 It runs through the colours in a browser palette and checks to see if they
04154                 are all present. The ordering is not checked and so the palette may be
04155                 different from the one that we actually use.
04156                 Doesn't check the flags byte, just the RGB bytes.
04157 
04158 ********************************************************************************************/
04159 
04160 BOOL CWxBitmap::ArePalettesTheSame(const LPLOGPALETTE pLogPalette, const INT32 TransColour)
04161 {
04162     ERROR2IF(pLogPalette == NULL,FALSE,"ArePalettesTheSame Bad LOGPALETTE param");
04163 
04164     // Not interested in deep bitmaps
04165     UINT32 bpp = GetBPP();
04166     if (bpp != 8)
04167         return FALSE;
04168 
04169 RebuildXPEBitmap();
04170     // Check the palette of this bitmap against this browser palette
04171     LPRGBQUAD pPalette = GetPaletteForBitmap();
04172     if (pPalette == NULL)
04173         return FALSE;
04174 
04175     UINT32 PaletteEntries = GetNumPaletteEntries();
04176     if (PaletteEntries != pLogPalette->palNumEntries)
04177         return FALSE;
04178 
04179     // Check this against our browser palette
04180     BOOL PaletteOk = TRUE;
04181     for (INT32 i = 0; i < pLogPalette->palNumEntries; i++)
04182     {
04183         // If it is the transparent colour then the entry must be white
04184         if (i == TransColour)
04185         {
04186             if (pPalette[i].rgbRed != 0xFF && 
04187                 pPalette[i].rgbGreen != 0xFF &&
04188                 pPalette[i].rgbBlue != 0xFF)
04189             {
04190                 PaletteOk = FALSE;
04191                 break;
04192             }
04193         }
04194         else if (pPalette[i].rgbRed != pLogPalette->palPalEntry[i].peRed &&
04195                  pPalette[i].rgbGreen != pLogPalette->palPalEntry[i].peGreen &&
04196                  pPalette[i].rgbBlue != pLogPalette->palPalEntry[i].peBlue)
04197         {
04198             PaletteOk = FALSE;
04199             break;
04200         }
04201     }
04202 
04203     return PaletteOk;
04204 }
04205 
04206 
04207 
04208 /********************************************************************************************
04209 
04210 >   void CWxBitmap::ExtractBitsAndInfo(LPBYTE pBytes, LPBITMAPINFO pInfo)
04211 
04212     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04213     Created:    17/8/2000
04214     Outputs:    the bytes and bitmapinfo of this bitmap
04215     Returns:    -
04216     Purpose:    To extract the bitmap data for use elsewhere, sets them to null so that
04217                 the CWxBitmap object can be deleted
04218 
04219 ********************************************************************************************/
04220 
04221 void CWxBitmap::ExtractBitsAndInfo(LPBYTE* ppBytes, LPBITMAPINFO* ppInfo)
04222 {
04223 RebuildXPEBitmap();
04224     *ppBytes = BMBytes;
04225     *ppInfo = BMInfo;
04226 
04227     BMBytes = NULL;
04228     BMInfo = NULL;
04229 }
04230 
04231 
04232 
04233 
04234 /********************************************************************************************
04235 
04236 >   void CWxBitmap::ReplaceBitmap(LPBYTE pBytes, LPBITMAPINFO pInfo)
04237 
04238     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
04239     Created:    04/02/2004
04240     Inputs:     the bytes and bitmapinfo of the new bitmap
04241     Returns:    -
04242     Purpose:    To reset the bitmap stored in this CWxBitmap object
04243 
04244 ********************************************************************************************/
04245 
04246 void CWxBitmap::ReplaceBitmap(LPBYTE pBytes, LPBITMAPINFO pInfo)
04247 {
04248     if (IsDefaultBitmap())
04249     {
04250         ERROR2RAW("ReplaceBitmap asked to replace the default bitmap!");
04251         return;
04252     }
04253     // Do we have valid inputs?
04254     if (pBytes==NULL && pInfo==NULL)
04255     {
04256         ERROR2RAW("Call to ReplaceBitmap with bad parameters");
04257         return;
04258     }
04259 
04260     // Remove the old data from memory
04261     FreeDIB( BMInfo, BMBytes );
04262     DestroyGreyscaleVersion();
04263     DestroyContonePalette();
04264 
04265     // Set the new data pointers
04266     BMInfo = pInfo;
04267     BMBytes = pBytes;
04268 
04269     // Set the information up
04270     CacheGeometry();
04271 }
04272 
04273 
04274 void CWxBitmap::CopyFullyTransparentFrom(OILBitmap* pBitmap)
04275 {
04276     if (GetWidth() != pBitmap->GetWidth() ||
04277         GetHeight() != pBitmap->GetHeight() ||
04278         GetBPP() != 32 ||
04279         pBitmap->GetBPP() != 32)
04280     {
04281         ERROR3("Incompatible bitmaps passed to CopyFullyTransparentFrom");
04282         return;
04283     }
04284 
04285     // Pointers to the pixel we are dealing with
04286     UINT32* pMask = (UINT32*)(pBitmap->GetBitmapBits());
04287     UINT32* pDest = (UINT32*)GetBitmapBits();
04288 
04289     // Loop through all the pixels
04290     for (UINT32 j=0; j < pBitmap->GetHeight(); j++)
04291     {
04292         for (UINT32 i=0; i < pBitmap->GetWidth(); i++)
04293         {
04294             // If this bit is background then set the corresponding pixel 
04295             // in the output bitmap to fully transparent black
04296             if (*pMask == 0xFF000000)
04297                 *pDest = 0xFF000000;
04298 
04299             // Move to the next pixel
04300             pMask++;
04301             pDest++;
04302         }
04303     }
04304 }

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