imgmgkft.cpp

Go to the documentation of this file.
00001 // $Id: pngfiltr.cpp 1282 2006-06-09 09:46:49Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 
00099 // A ImageMagick import/export filter 
00100 
00101 #include "camtypes.h"
00102 
00103 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00104 #include "progress.h"
00105 //#include "docview.h"  // DocView - in camtypes.h [AUTOMATICALLY REMOVED]
00106 #include "imgmgkft.h"
00107 #include "pngutil.h"    // ImageMagick utility class
00108 //#include "oilfltrs.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 #include "oilbitmap.h"
00110 //#include "bmpfiltr.h"
00111 //#include "dibutil.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00112 #include "grndbmp.h"
00113 #include "nodebmp.h"
00114 //#include "wbitmap.h"  // Windows specific bitmap information   
00115 //#include "andy.h"
00116 //#include "resource.h" // Inform Warning _R(IDS_OK)
00117 //#include "filtrres.h" // Filter ids
00118 //#include "will3.h"        // for _R(IDS_GENOPTPALMSGID)
00119 #include "outptpng.h"   // ImageMagick filter type, includes imglib.h 
00120 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00121 #include "maskfilt.h"   // MaskedFilter class
00122 #include "bmapprev.h"   // tab preview dialog
00123 #include "palman.h"     // PaletteManager::FindFirstDontUseColourInPalette
00124 //#include "mrhbits.h"  //  For CBMPBits::RenderSelectionToBMP
00125 #include "bitfilt.h"
00126 #include "selall.h"     //  For OPTOKEN_EDITSELECTALL
00127 #include "osrndrgn.h"
00128 
00129 CC_IMPLEMENT_DYNAMIC(ImageMagickFilter, MaskedFilter)
00130 CC_IMPLEMENT_DYNCREATE(ImageMagickExportOptions, MaskedFilterExportOptions)
00131 
00132 #define new CAM_DEBUG_NEW
00133 
00134 // Set the default path from a macro so it can be overridden at compile time
00135 #ifndef DEFAULT_IMAGEMAGICK_PATH
00136 //  #define DEFAULT_IMAGEMAGICK_PATH "/usr/bin/convert"
00137     #define DEFAULT_IMAGEMAGICK_PATH "convert"
00138 #endif
00139 
00140 #define DIP_QUOTE(x) _T(x) 
00141 
00142 OutputPNG   ImageMagickFilter::DestImageMagick;
00143 FilterType  ImageMagickFilter::s_FilterType = IMAGEMAGICK;  // Type of filter in use (ImageMagick .. ImageMagick_TRANSINTER)
00144 
00145 String_256  ImageMagickFilter::s_ImageMagickPath = DIP_QUOTE(DEFAULT_IMAGEMAGICK_PATH);
00146 BOOL        ImageMagickFilter::s_HaveImageMagick = FALSE;
00147 BOOL        ImageMagickFilter::s_HaveCheckedPath = FALSE;
00148 BOOL        ImageMagickFilter::s_DoWarning = TRUE;
00149 BOOL        ImageMagickFilter::s_Disable = FALSE;
00150 
00151 BOOL        ImageMagickFilter::s_OutputTransparent = FALSE;
00152 BOOL        ImageMagickFilter::s_OutputInterlaced = FALSE;
00153 
00154 #if 1
00155 
00156 IMFilterStringToUINT32 * ImageMagickExportOptions::s_pHash = NULL;
00157 
00158 
00159 /********************************************************************************************
00160 
00161 >   ImageMagickExportOptions::ImageMagickExportOptions(const FilterType FilterID, const StringBase* pFilterName)
00162 
00163     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
00164     Created:    29/10/96
00165     Purpose:    Default constructor for a ImageMagickExportOptions object to provide ImageMagick export
00166                 options
00167 
00168 ********************************************************************************************/
00169 ImageMagickExportOptions::ImageMagickExportOptions(const FilterType FilterID, const StringBase* pFilterName, ResourceID FilterTypeID) :
00170                         MaskedFilterExportOptions(_R(IDD_EXPORTBMPOPTS), FilterID, pFilterName)
00171 {
00172     FilterName = *pFilterName;
00173     m_FilterTypeID = FilterTypeID;
00174 
00175     // if we don't already have the static hash, generate one
00176     // We never delete this (harmless)
00177     if (!s_pHash)
00178     {
00179         s_pHash = new IMFilterStringToUINT32;
00180     }
00181 
00182     if (!s_pHash) // Not much we can do
00183         return;
00184 
00185     // Declare the preference if it hasn't been seen already
00186     if (!GetConfigPtr((const TCHAR *)(*pFilterName)))
00187     {
00188         // OK, it's not in the hash already, so we need to declare it
00189         (*s_pHash)[camStrdup((const TCHAR *)*pFilterName)]=0;
00190         UINT32 * pPref = GetConfigPtr((const TCHAR *)(*pFilterName));
00191         ERROR3IF(!pPref, "Config did not stick");
00192         if (pPref)
00193         {   
00194             if (Camelot.DeclareSection(_T("Filters"), 10))
00195             {
00196                 String_256 PrefName = *pFilterName;
00197                 String_256 Prefix(_T("ExportImageMagickFlags"));
00198                 Prefix+=PrefName;
00199                 Camelot.DeclarePref( NULL, Prefix, pPref, 0, 3 );
00200             }
00201         }
00202     }
00203 }
00204 
00205 /********************************************************************************************
00206 
00207 >   virtual BOOL ImageMagickExportOptions::RetrieveDefaults()
00208 
00209     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
00210     Created:    29/10/96
00211     Purpose:    See BitmapExportOptions for interface details
00212     Notes:      Gets GIF specific preferences
00213 
00214 ********************************************************************************************/
00215 BOOL ImageMagickExportOptions::RetrieveDefaults()
00216 {
00217     if (!MaskedFilterExportOptions::RetrieveDefaults())
00218         return FALSE;
00219 
00220     SetMakeInterlaced(GetConfig() & 1);
00221     return TRUE;
00222 }
00223 
00224 /********************************************************************************************
00225 
00226 >   virtual BOOL ImageMagickExportOptions::SetAsDefaults() const
00227 
00228     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
00229     Created:    29/10/96
00230     Purpose:    Provides additional implementation to set ImageMagick specific options as defaults
00231     See Also:   BitmapExportOptions::SetAsDefaults()
00232 
00233 ********************************************************************************************/
00234 BOOL ImageMagickExportOptions::SetAsDefaults() const
00235 {
00236     if (!MaskedFilterExportOptions::SetAsDefaults())
00237         return FALSE;
00238 
00239     SetConfig( ( WantTransparent() ? 2 : 0 ) | (WantInterlaced() ? 1 : 0) );
00240 
00241     return TRUE;
00242 }
00243 
00244 #endif
00245 
00246 /********************************************************************************************
00247 
00248 >   ImageMagickFilter::ImageMagickFilter()
00249 
00250     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00251     Created:    26/4/96
00252     Purpose:    Constructor for an ImageMagickFilter object.  The object should be initialised
00253                 before use.
00254     SeeAlso:    ImageMagickFilter::Init
00255 
00256 ********************************************************************************************/
00257 ImageMagickFilter::ImageMagickFilter() : MaskedFilter()
00258 {
00259     ExportRegion = NULL;
00260     TempFile = NULL;
00261     m_ImportDPI = 0;
00262 
00263     // Things that the derive class constructor may stamp on
00264     Flags.CanImport     = TRUE;
00265     Flags.CanExport     = TRUE;
00266     FilterID            = FILTERID_IMAGEMAGICK;
00267     FilterNameID        = _R(IDS_IMAGEMAGICK_FILTERNAME);
00268     FilterInfoID        = _R(IDS_IMAGEMAGICK_FILTERINFO);
00269     FilterExtID         = _R(IDS_IMAGEMAGICK_FILTEREXT);
00270     ImportMsgID         = _R(IDS_IMAGEMAGICK_IMPORTMSG);
00271     ExportMsgID         = _R(IDS_IMAGEMAGICK_PREPAREMSG);           // "Preparing ImageMagick file..."
00272     ExportingMsgID      = _R(IDS_IMAGEMAGICK_EXPORTMSG);        // "Exporting ImageMagick file..."
00273     Export2ndStageMsgID = _R(IDS_IMAGEMAGICK_MASKINGMSG);   // "Preparing mask for ImageMagick file..."
00274 }
00275 
00276 /********************************************************************************************
00277 
00278 >   BOOL ImageMagickFilter::Init()
00279 
00280     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00281     Created:    26/4/96
00282     Returns:    TRUE if the filter was initialised ok, FALSE otherwise.
00283     Purpose:    Initialise an ImageMagickFilter object.
00284     Errors:     Will fail if not enough memory to initialise.
00285     SeeAlso:    EPSStack
00286 
00287 ********************************************************************************************/
00288 BOOL ImageMagickFilter::Init()
00289 {
00290     // Get the OILFilter object
00291     pOILFilter = new ImageMagickOILFilter(this, FilterNameID, FilterExtID);
00292     if (pOILFilter==NULL)
00293         return FALSE;
00294 
00295     // Load the description strings
00296     FilterName.Load(FilterNameID);
00297     FilterInfo.Load(FilterInfoID);
00298 
00299     // All ok
00300     return TRUE;
00301 }
00302 
00303 /********************************************************************************************
00304 
00305 >   INT32 ImageMagickFilter::HowCompatible(PathName& Filename, ADDR HeaderStart, UINT32 HeaderSize, 
00306                                 UINT32 FileSize)
00307 
00308     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00309     Created:    26/4/96
00310     Inputs:     Filename - name of the file.
00311                 HeaderStart - Address of the first few bytes of the file.
00312                 HeaderSize - the number of bytes in the header pointed to by FileStart.
00313                 FileSize - the size of the whole file, in bytes.
00314     Returns:    0 => Not a ImageMagick file.
00315                 10 => It is a ImageMagick file.
00316     Purpose:    Determine if this filter can load the specified file.
00317 
00318 ********************************************************************************************/
00319 INT32 ImageMagickFilter::HowCompatible(PathName& Filename, ADDR HeaderStart, UINT32 HeaderSize, 
00320                             UINT32 FileSize)
00321 {
00322     // We need to remember what we thought of this file in our class variable.
00323     // So, set it to a nice default value at the start.
00324     String_256 fextension = Filename.GetType();
00325     fextension.toLower();
00326 
00327     ImageMagickHowCompatible = (fextension == (String_256)GetExtension()) ? GetCompatibility():0;
00328 
00329     // Return the found value to the caller.
00330     return ImageMagickHowCompatible;
00331 }
00332 
00333 /********************************************************************************************
00334 
00335 >   virtual BOOL ImageMagickFilter::IsThisBppOk(UINT32 Bpp)
00336 
00337     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00338     Created:    26/4/96
00339     Inputs:     Bpp or Colour depth.
00340     Returns:    TRUE if this filter can cope with this colour depth, FALSE otherwise.
00341     Purpose:    Check if this Bitmap filter can cope with saving at this Bpp/Colour depth.
00342     SeeAlso:    OpMenuExport::DoWithParam;
00343 
00344 ********************************************************************************************/
00345 BOOL ImageMagickFilter::IsThisBppOk(UINT32 Bpp)
00346 {
00347     return (Bpp == 1 || Bpp == 4 || Bpp == 8 || Bpp == 24 || Bpp == 32);
00348 }
00349 
00350 /********************************************************************************************
00351 
00352 >   BOOL ImageMagickFilter::ReadFromFile( OILBitmap* pOilBitmap, BaseCamelotFilter* pFilter,
00353                                 CCLexFile* pFile, BOOL IsCompressed)
00354 
00355     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00356     Created:    20/7/96
00357     Inputs:     pOilBitmap  pointer to the oil bitmap data to be filled in
00358                 pFilter         - the BaseCamelotFilter which provides functions like progress update
00359                 pFile           - the CCFile class to use to read the data from
00360                 IsCompressed    - Flag to say the bitmap is compressed or not.  
00361     Outputs:    Will have filled in BMInfo  pointer to the bitmap header to fill in
00362                                     BMBytes pointer to the bitmap data to fill in
00363     Purpose:    Actually does the process of reading a bitmap from a file.
00364                 Inherited classes override this to read in different file formats.
00365                 It is used by the web/native filters to pull out a bitmap definition from
00366                 inside a bitmap definition record.
00367                 IsCompressed is only used for BMP/BMPZIP type bitmaps at present.
00368                 Assumes:
00369                     pFile has already been opened up for reading
00370                     pFilter has been set up for reading the data e.g. progress bar 
00371     Returns:    TRUE if worked, FALSE if failed.
00372 
00373 ********************************************************************************************/
00374 BOOL ImageMagickFilter::ReadFromFile( OILBitmap* pOilBitmap, BaseCamelotFilter* pFilter,
00375                             CCLexFile* pFile, BOOL IsCompressed)
00376 {
00377     ERROR2IF(pOilBitmap == NULL,FALSE,"BMPFilter::ReadFromFile null OilBitmap pointer");
00378     ERROR2IF(pFilter == NULL,FALSE,"BMPFilter::ReadFromFile null pFilter pointer");
00379     ERROR2IF(pFile == NULL,FALSE,"BMPFilter::ReadFromFile null pFile pointer");
00380 
00381     // Try to import bitmap as usual binary BMP file.
00382     CWxBitmap* pWBitmap = (CWxBitmap*)pOilBitmap;
00383     
00384     LPBITMAPINFO *pInfo = &(pWBitmap->BMInfo);
00385     LPBYTE *pBytes = &(pWBitmap->BMBytes);
00386 
00387     INT32 TransColour = -1;
00388 
00389     // Read from file,using pFilter for progress bar updates
00390     BOOL ok = ConvertToTempFile(pFile); 
00391     if (ok)
00392         ok = PNGUtil::ReadFromFile(TempFile, pInfo, pBytes, &TransColour, NULL, pFilter);
00393     TidyTempFile();
00394     if (!ok)
00395         return FALSE;
00396 
00397     if(pWBitmap->BMInfo->bmiHeader.biBitCount == 32)
00398     {
00399         // If we`re exporting a 32Bit BMP then we need to make sure that we convert the
00400         // Alpha channel to Transparency! i.e. invert it!
00401         UINT32 BmpSize = pWBitmap->BMInfo->bmiHeader.biSizeImage;
00402         BYTE* Bits = pWBitmap->BMBytes;
00403 
00404         for(UINT32 i = 0; i < BmpSize; i+=4)
00405             Bits[i+3] = ~Bits[i+3];
00406     }
00407 
00408     // Everything went ok and we imported the bitmap ok
00409     SetTransColour(TransColour);
00410     UINT32 Bpp = pWBitmap->GetBPP();
00411     if (TransColour != -1 && Bpp <= 8)
00412         pOilBitmap->SetTransparencyIndex(TransColour);
00413 
00414     SetLastBitmap();        // can only import one bitmap at the moment
00415     return TRUE;
00416 }
00417 
00418 /********************************************************************************************
00419 
00420 >   BOOL ImageMagickFilter::ReadFromFile(OILBitmap* pOilBitmap)
00421 
00422     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00423     Created:    26/4/96
00424     Inputs:     pOilBitmap  pointer to the oil bitmap data to be filled in
00425     Outputs:    Will have filled in BMInfo  pointer to the bitmap header to fill in
00426                                     BMBytes pointer to the bitmap data to fill in
00427     Purpose:    Actually does the process of reading a bitmap from a file.
00428                 Inherited classes override this to read in different file formats.
00429                 
00430     Returns:    TRUE if worked, FALSE if failed.
00431 
00432 ********************************************************************************************/
00433 BOOL ImageMagickFilter::ReadFromFile(OILBitmap* pOilBitmap)
00434 {
00435     ERROR2IF(pOilBitmap == NULL,FALSE,"ImageMagickFilter::ReadFromFile null OilBitmap pointer");
00436     
00437     // Try to import the bitmap as a ImageMagick file.      
00438     CCLexFile *pImportFile = GetImportFile();
00439     ERROR2IF(pImportFile==NULL,FALSE,"ImageMagickFilter::ReadFromFile - No import file");
00440 
00441     UINT32 ImportMsgId = GetImportMsgID();      
00442     String_64 ProgressString(ImportMsgId);
00443     ProgressString = GetImportProgressString(pImportFile, ImportMsgId);
00444 
00445     CWxBitmap* pWBitmap = (CWxBitmap*)pOilBitmap;
00446     
00447     LPBITMAPINFO *pInfo = &(pWBitmap->BMInfo);
00448     LPBYTE *pBytes = &(pWBitmap->BMBytes);
00449     
00450     INT32 TransColour = -1;
00451 
00452     // The ImageMagick filter liked it very much and so use it, showing progress bar
00453     BOOL ok = ConvertToTempFile(pImportFile); 
00454     if (ok)
00455         ok = PNGUtil::ReadFromFile(TempFile, pInfo, pBytes, &TransColour, &ProgressString);
00456     TidyTempFile();
00457     if (!ok)
00458         return FALSE;
00459 
00460     SetTransColour(TransColour);
00461     UINT32 Bpp = pWBitmap->GetBPP();
00462     if (TransColour != -1 && Bpp <= 8)
00463         pOilBitmap->SetTransparencyIndex(TransColour);
00464 
00465     SetLastBitmap();        // can only import one bitmap at the moment
00466     
00467     return TRUE;
00468 }
00469 
00470 /********************************************************************************************
00471 
00472 >   virtual BOOL ImageMagickFilter::GetExportOptions(BitmapExportOptions* pOptions)
00473 
00474     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
00475     Created:    12/11/96
00476     Purpose:    See BaseBitmapFilter for interface details
00477 
00478 ********************************************************************************************/
00479 BOOL ImageMagickFilter::GetExportOptions(BitmapExportOptions* pOptions)
00480 {
00481     ERROR2IF(pOptions == NULL, FALSE, "NULL Args");
00482 
00483     ImageMagickExportOptions* pImageMagickOptions = (ImageMagickExportOptions*)pOptions;
00484     ERROR3IF(!pImageMagickOptions->IS_KIND_OF(ImageMagickExportOptions), "pImageMagickOptions isn't");
00485 
00486     // the depth we ask GDraw to render is always 32-bit, so we can get transparency
00487     // we have to convert for other formats when writing the actual bytes to the file
00488     SetDepthToRender(32);
00489 
00490     // We haven't written the header yet
00491     WrittenHeader = FALSE;
00492 
00493     // We are a first pass render and not doing the mask, by default
00494     SecondPass = FALSE;
00495     DoingMask = FALSE;
00496 
00497     // Determine the filter type currently in use in Accusoft format
00498     s_FilterType = IMAGEMAGICK;
00499     pImageMagickOptions->SetFilterType(IMAGEMAGICK);
00500 
00501     BOOL Ok = FALSE;
00502 
00503     OpDescriptor* pOpDes = OpDescriptor::FindOpDescriptor(OPTOKEN_GIFTABDLG);
00504     if (pOpDes != NULL)
00505     {
00506         // set up the data for the export options dialog
00507         OpParam Param((void *)pOptions, (void *)this);
00508 
00509         // invoke the dialog
00510         pOpDes->Invoke(&Param);
00511 
00512         // SMFIX
00513         // we have brought the dlg up so get the options from the dlg as the graphic type may have changed
00514         pOptions = BmapPrevDlg::m_pExportOptions;
00515 
00516         // check for valid options
00517         //  This may get messed up, so have to use the second line below.
00518         Ok = BmapPrevDlg::m_bClickedOnExport;
00519     }
00520     else
00521     {   
00522         ERROR3("Unable to find OPTOKEN_BMAPPREVDLG");
00523     } 
00524 
00525     // Return with the ok/cancel state used on the dialog box
00526     return Ok;
00527 }
00528 
00529 // SMFIX sjk 5/12/00 there used to be some junk in the call to GetExportOptions that assumed the
00530 // filter type being used which could be changed by the GetExportOptions call itself
00531 // therefore all this sort of stuff should be called on the correct known filter using this
00532 // call afterwards
00533 void ImageMagickFilter::PostGetExportOptions(BitmapExportOptions* pOptions)
00534 {
00535     // should be of this type
00536     ImageMagickExportOptions* pImageMagickOptions = (ImageMagickExportOptions*)pOptions;
00537     ERROR3IF(!pImageMagickOptions->IS_KIND_OF(ImageMagickExportOptions), "pImageMagickOptions isn't");
00538 
00539     // do the baseclass options
00540     MaskedFilter::PostGetExportOptions(pOptions);
00541 
00542     // do the specific to this class options
00543     // Filter type can be changed by the export options dialog box from say 
00544 
00545     s_OutputTransparent = pImageMagickOptions->WantTransparent();
00546     s_OutputInterlaced = pImageMagickOptions->WantInterlaced();
00547     UINT32 Silliness = pImageMagickOptions->WantTransparent() ? 2 : 0;
00548     Silliness |= pImageMagickOptions->WantInterlaced() ? 1 : 0;
00549     if (Silliness >= 0 && Silliness <= 4)
00550     {
00551         Compression = Silliness;
00552         s_FilterType = IMAGEMAGICK;
00553 
00554         if (pImageMagickOptions->WantTransparent() && pImageMagickOptions->GetSelectionType() == SELECTION)
00555             DoingMask = TRUE;
00556     }
00557 }
00558 
00559 /********************************************************************************************
00560 
00561 >   virtual void ImageMagickFilter::CleanUpAfterExport()
00562 
00563     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00564     Created:    14/5/96
00565     Purpose:    Cleans up the memory allocated at the end of Exporting or when exporting has
00566                 been aborted for some reason. Does its cleaning up and then calls the
00567                 baseclass version to do its stuff,  - used
00568                 when the import process ends, either normally or abnormally. Override if
00569                 extra things are required.
00570     SeeAlso:    BaseBitmapFilter::PrepareToExport(); BaseBitmapFilter::CleanUpAfterExport();
00571     Scope:      Protected
00572 
00573 ********************************************************************************************/
00574 void ImageMagickFilter::CleanUpAfterExport()
00575 {
00576     // Called right at the end of the export process or when the epxort has been aborted
00577     // Clean up any objects unique to this class.
00578     // Free up any DIBs that we might have left lying around on the export
00579     if (pDestBMInfo && pDestBMBytes)
00580     {
00581         FreeDIB( pDestBMInfo, pDestBMBytes );
00582         pDestBMInfo = NULL;
00583         pDestBMBytes = NULL;    
00584     }
00585 
00586     // the depth we ask GDraw to render is always 32-bit, so we can get transparency
00587     // we have to convert for other formats when writing the actual bytes to the file
00588     SetDepthToRender(32);
00589 
00590     // We haven't written the header yet
00591     WrittenHeader = FALSE;
00592 
00593     // We are a first pass render and not doing the mask, by default
00594     SecondPass = FALSE;
00595     DoingMask = FALSE;
00596 
00597     // Now call the baseclass version to do its stuff
00598     BaseBitmapFilter::CleanUpAfterExport();
00599 }
00600 
00601 /********************************************************************************************
00602 
00603 >   virtual UINT32 ImageMagickFilter::GetExportMsgID()
00604 
00605     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00606     Created:    10/07/96
00607     Returns:    The id of the message to put on the progress display whilst exporting.
00608     Purpose:    Used to get the message id to be used during export.
00609                 Overides the baseclass form of the function so that during the two stage
00610                 export process it can change the message.
00611     SeeAlso:    DoExport; TI_GIFFilter::GetExportMsgID;
00612 
00613 ********************************************************************************************/
00614 UINT32 ImageMagickFilter::GetExportMsgID()
00615 {
00616     if (GeneratingOptimisedPalette())
00617         return _R(IDS_GENOPTPALMSGID);              // "Generating optimised palette..."
00618 
00619     ImageMagickExportOptions* pImageMagickOptions = (ImageMagickExportOptions*)GetBitmapExportOptions();
00620     ERROR2IF(pImageMagickOptions == NULL, FALSE, "NULL Args");
00621     ERROR3IF(!pImageMagickOptions->IS_KIND_OF(ImageMagickExportOptions), "pImageMagickOptions isn't");
00622 
00623     // If we are exporting with transparency on and on first pass use the masking message
00624     // otherwise use the exporting message.
00625     if (pImageMagickOptions->GetSelectionType() == SELECTION && pImageMagickOptions->WantTransparent())
00626     {
00627         // Special 4 stage rendering operation
00628         // - Render selected objects to white background
00629         // - Render mask 1bpp
00630         // - Render all objects
00631         // - Save data out to disk
00632         if (!SecondPass)
00633             return Export2ndStageMsgID;         // "Preparing mask for ImageMagick file..."
00634         else
00635             return Filter::GetExportMsgID();    // "Preparing ImageMagick file..."
00636     }
00637     else
00638     {
00639         // Special 3 stage rendering operation
00640         // - Render objects to white background
00641         // - Render mask 1bpp
00642         // - Save data out to disk
00643         if (DoingMask)
00644             return Export2ndStageMsgID;         // "Preparing mask for ImageMagick file..."
00645         else
00646             return Filter::GetExportMsgID();    // "Preparing ImageMagick file..."
00647     }
00648 
00649     return ExportingMsgID;
00650 }
00651 
00652 /********************************************************************************************
00653 
00654 >   BOOL ImageMagickFilter::EndWriteToFile( )
00655 
00656     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00657     Created:    14/5/96
00658     Inputs:     -
00659     Purpose:    Cleans up after writing the bitmap data out to a file. Inherited classes
00660                 override this to write in different file formats.
00661                 This is slightly different to most other bitmap filters in that it is here
00662                 that the data actually gets written out to file, after doing the transparency
00663                 translation, if required.
00664     Returns:    TRUE if worked, FALSE if failed.
00665 
00666 ********************************************************************************************/
00667 BOOL ImageMagickFilter::EndWriteToFile()
00668 {
00669     if (GeneratingOptimisedPalette())
00670         return TRUE;        // No need to output anything
00671 
00672     //  Can reset the band number now.
00673     m_BandNumber = 0;
00674 
00675     ImageMagickExportOptions* pImageMagickOptions = (ImageMagickExportOptions*)GetBitmapExportOptions();
00676     ERROR2IF(pImageMagickOptions == NULL, FALSE, "NULL Args");
00677     ERROR3IF(!pImageMagickOptions->IS_KIND_OF(ImageMagickExportOptions), "pImageMagickOptions isn't");
00678 
00679     // Do the transparency translation just before we write out the data as a ImageMagick.
00680     // This involves doing a 1 bpp export of the same area and using this to work
00681     // out which areas are transparent or not.
00682     // Only do this if the user has requested transparency and we outputting at 8bpp
00683     BOOL SaveDataOut = TRUE;
00684 
00685     if (BadExportRender)
00686     {
00687         // Delete our whitearea bitmap
00688         if (pTempBitmapMask != NULL)
00689             CCFree(pTempBitmapMask);
00690 
00691         pTempBitmapMask = NULL;
00692     }
00693 
00694     BOOL ok=FALSE;
00695 
00696     // Save the data out if required. Only if we exported ok.
00697     if (SaveDataOut && !BadExportRender)
00698     {
00699         ok = CreateTempFile();
00700     
00701         if (ok)
00702         {
00703             // Now that we know the transparent index we can output the ImageMagick header
00704             ok = DestImageMagick.OutputPNGHeader(TempFile, NULL, pImageMagickOptions->WantInterlaced(),
00705                                         pImageMagickOptions->GetTransparencyIndex(),
00706                                         pImageMagickOptions->GetDepth() <= 8 ? pImageMagickOptions->GetLogicalPalette() : NULL);
00707         }
00708 
00709         // Actually write the destination bitmap out to the file showing an hourglass
00710         // and/or progress bar as we go. Always show the Exporting message.
00711         // Need to do in one go due to interlacing
00712         if (ok)
00713         {
00714             String_64 ProgressString(ExportingMsgID);
00715             ProgressString = GetExportProgressString(TempFile, ExportingMsgID);
00716             BeginSlowJob(100, FALSE, &ProgressString);
00717             
00718             ok = DestImageMagick.OutputPNGBits(TempFile, DestImageMagick.GetDestBitmapBits());
00719             DestImageMagick.TidyUp();
00720             if (ok)
00721                 ok=ConvertFromTempFile(OutputFile);
00722 
00723             EndSlowJob();
00724         }
00725         else
00726         {
00727             DestImageMagick.TidyUp();
00728         }
00729     }
00730     else
00731     {
00732         DestImageMagick.TidyUp();
00733     }
00734 
00735 
00736     ERROR1IF(!ok, FALSE, _R(IDE_IMAGEMAGICK_ERROR));
00737 
00738     TidyTempFile();
00739     
00740     return TRUE;
00741 }
00742 
00743 /********************************************************************************************
00744 
00745 >   static BOOL ImageMagickFilter::WriteDataToFile( BOOL End, UINT32 Bpp, UINT32 Compression)
00746 
00747     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00748     Created:    14/5/96
00749     Inputs:     End - TRUE if this is the last block of the file.
00750                 Bpp - output depth in terms of bits per pixel
00751                 Compression - usually True if compression required, False otherwise
00752                             In the ImageMagick case this is used to pass in the transparency and
00753                             interlace state.
00754     Returns:    TRUE if worked, FALSE if errored.
00755     Purpose:    Physically put the bitmap into the disk.
00756                 NOTE - ONLY COPES WITH End=TRUE currently
00757                 AtEnd is ignored now and should always be set to TRUE.
00758                 Unused at present due to static problems when cretaing the 1bpp bitmap. 
00759     SeeAlso:    WriteToFile(); AccusoftFilters::WriteToFile; AccusoftFilters::WriteDataToFile;
00760 
00761 ********************************************************************************************/
00762 BOOL ImageMagickFilter::WriteDataToFile( BOOL End, UINT32 Bpp, UINT32 Compression)
00763 {
00764     ERROR2(FALSE,"ImageMagickFilter::WriteDataToFile called when not implemented");
00765 }
00766 
00767 /********************************************************************************************
00768 
00769 >   virtual BOOL ImageMagickFilter::WriteBitmapToFile(KernelBitmap* pKernelBitmap, double Dpi)
00770 
00771     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00772     Created:    26/4/96
00773     Inputs:     Pointer to the bitmap to save.
00774                 Dpi of the bitmap to be saved
00775     Returns:    TRUE if worked, FALSE if errored.
00776     Purpose:    Physically put the bitmap into the disk.  Inherited classes override this to write
00777                 in different file formats.
00778     SeeAlso:    WriteDataToFile(); AccusoftFilters::WriteToFile; AccusoftFilters::WriteDataToFile;
00779 
00780 ********************************************************************************************/
00781 BOOL ImageMagickFilter::WriteBitmapToFile(KernelBitmap* pKernelBitmap, double Dpi)
00782 {
00783     ERROR2IF(pKernelBitmap == NULL,FALSE,"ImageMagickFilter::WriteBitmapToFile null bitmap pointer specified");
00784 
00785     // Get a pointer to the actual bitmap so that we can get some details from it.
00786     OILBitmap *pOilBitmap = pKernelBitmap->ActualBitmap;
00787     ERROR2IF(pOilBitmap == NULL,FALSE,"ImageMagickFilter::WriteBitmapToFile null oil bitmap pointer");
00788 
00789     // Now get the pointer to the info header and actual bits data.
00790     // Need to use the actual bitmap pointer
00791     CWxBitmap* pWBitmap = (CWxBitmap*)pOilBitmap;
00792     LPBITMAPINFO pInfo = pWBitmap->BMInfo;
00793     LPBYTE pBytes = pWBitmap->BMBytes;
00794 //  UINT32 Bpp = pWBitmap->GetBPP();
00795 
00796     // Now, save the data out showing the correct progress string
00797     String_64 ProgressString(ExportingMsgID);
00798     BOOL ok = FALSE;
00799 //  BOOL Interlace = TRUE;  // Use interlace or not
00800 //  BOOL Transparency = FALSE;  // Use transparency or not
00801 
00802     if(pInfo->bmiHeader.biBitCount == 32)
00803     {
00804         // If we`re exporting a 32Bit BMP then we need to make sure that we convert the
00805         // Alpha channel to Transparency! i.e. invert it!
00806         UINT32 BmpSize = pInfo->bmiHeader.biSizeImage;
00807 
00808         for(UINT32 i = 0; i < BmpSize; i+=4)
00809             pBytes[i+3] = ~pBytes[i+3];
00810     }
00811 
00812     ok = WriteToFile(OutputFile, pInfo, pBytes, &ProgressString);
00813 
00814     //  This function is used when saving from the bitmap gallery. If we save a 32-bit bitmap as
00815     //  a ImageMagick, then we have to undo the alpha channel reversing that we did above.
00816     //  Failure to do this will change the bitmap displayed in the bitmap gallery.
00817     if(pInfo->bmiHeader.biBitCount == 32)
00818     {
00819         UINT32 BmpSize = pInfo->bmiHeader.biSizeImage;
00820 
00821         for(UINT32 i = 0; i < BmpSize; i+=4)
00822             pBytes[i+3] = ~pBytes[i+3];
00823     }
00824     
00825     return ok;
00826 }
00827 
00828 /********************************************************************************************
00829 
00830 >   virtual BOOL ImageMagickFilter::WriteBitmapToFile(KernelBitmap* pKernelBitmap,
00831                                             BaseCamelotFilter*pFilter,
00832                                             CCLexFile* pFile, INT32 Compression);
00833     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00834     Created:    21/6/96
00835     Inputs:     pKernelBitmap   - Pointer to the bitmap to be exported.
00836                 pFilter         - Pointer to the BaseCamelot filter which provides progress functions
00837                 pFile           - Pointer to the CCFile class to use for export
00838                 Compression     - used to flag how much compression of the data is required.
00839     Returns:    TRUE if worked, FALSE if errored.
00840     Purpose:    Physically put the bitmap into the disk.  Inherited classes override this to write
00841                 in different file formats.
00842                 This is used by the native/web format to output the actual bitmap data content
00843                 of a bitmap definition record. The function can assume that the CCFile is open
00844                 and ready for writing and must use the functions provided by pFilter to update
00845                 the progress system.
00846     SeeAlso:    BitmapListComponent::SaveBitmapDefinition;
00847 
00848 ********************************************************************************************/
00849 BOOL ImageMagickFilter::WriteBitmapToFile(KernelBitmap* pKernelBitmap, BaseCamelotFilter* pFilter,
00850                                         CCLexFile* pFile, INT32 Compression)
00851 {
00852     ERROR2IF(pKernelBitmap == NULL,FALSE, "ImageMagickFilter::WriteBitmapToFile null pKernelBitmap");
00853     ERROR2IF(pFilter == NULL,FALSE, "ImageMagickFilter::WriteBitmapToFile null pFilter");
00854     ERROR2IF(pFile == NULL,FALSE, "ImageMagickFilter::WriteBitmapToFile null pFile");
00855 
00856     // Get a pointer to the actual bitmap so that we can get some details from it.
00857     OILBitmap *pOilBitmap = pKernelBitmap->ActualBitmap;
00858     ERROR2IF(pOilBitmap == NULL,FALSE,"ImageMagickFilter::WriteBitmapToFile null oil bitmap pointer");
00859 
00860     // Now get the pointer to the info header and actual bits data.
00861     // Need to use the actual bitmap pointer
00862     CWxBitmap* pWBitmap = (CWxBitmap*)pOilBitmap;
00863     LPBITMAPINFO Info = pWBitmap->BMInfo;
00864     LPBYTE Bytes = pWBitmap->BMBytes;
00865     UINT32 Bpp = pWBitmap->GetBPP();
00866 
00867     // Now, save the data out showing the correct progress string
00868     BOOL ok = FALSE;
00869     BOOL Interlace = FALSE;     // Must not use interlacing as it will screw the progress bar updates
00870 //  BOOL Transparency = FALSE;  // Use transparency or not
00871     INT32 Transparent = -1; // colour or -1 = no transparency
00872     if (Bpp <= 8)
00873         pOilBitmap->GetTransparencyIndex(&Transparent);
00874     
00875     if(Info->bmiHeader.biBitCount == 32)
00876     {
00877         // If we`re exporting a 32Bit BMP then we need to make sure that we convert the
00878         // Alpha channel to Transparency! i.e. invert it!
00879         UINT32 BmpSize = Info->bmiHeader.biSizeImage;
00880 
00881         for(UINT32 i = 0; i < BmpSize; i+=4)
00882             Bytes[i+3] = ~Bytes[i+3];
00883     }
00884     
00885     // Write to file, no header and using pFilter for progress bar updates
00886     ok = WriteToFile(pFile, Info, Bytes, Interlace, Transparent, pFilter);
00887     
00888     return ok;
00889 }
00890 
00891 /********************************************************************************************
00892 
00893 >   static BOOL ImageMagickFilter::WriteToFile ( CCLexFile* File, LPBITMAPINFO Info, LPBYTE Bits,
00894                                         BOOL Interlace, INT32 Transparent,
00895                                         BaseCamelotFilter* pFilter = NULL )
00896 
00897     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00898     Created:    10/7/96
00899     Inputs:     File        An opened CCFile that can be written to. It should be positioned at the
00900                             start. Caller is responsible for closing it. The file needs to be in
00901                             Binary mode.
00902                 Info        BITMAPINFO structure for the dib.
00903                 Bits        The bitmap data itself
00904                 Interlace   allows interlacing to be turned off or on
00905                 Transparent if -1 then no transpparent colour, if not -1 then specifies the index
00906                             number of the transparent colour in the palette
00907                 pFilter     is an alternative way of handling the progress bar, assume the
00908                             progress bar has been start and just call the IncProgressBarCount in BaseCamelotFilter
00909                             to do the progress bar update. Defaults to NULL i.e. no progress bar.
00910     Outputs:    -
00911     Returns:    TRUE if worked, FALSE if failed (error will be set accordingly but not reported)
00912     Purpose:    Write a bitmap in memory straight out as a ImageMagick to file with no rendering or
00913                 conversion between different colour depths (apart from 32 to 24) or resolution.
00914                 ***Errors on 16-bit builds***
00915                 A progress hourglass can be shown if required using the BaseCamelotFilter as
00916                 the controlling influence.
00917                 
00918                 This function is used by the new native/web  file format to do a straight save of 
00919                 the data into the file.
00920 
00921                 (caller should close file)
00922     Errors:     Calls SetError on FALSE returns.
00923     Scope:      Static
00924     SeeAlso:    AccusoftFilters::WriteToFile; DIBUtil::WriteToFile;
00925 
00926 ********************************************************************************************/
00927 BOOL ImageMagickFilter::WriteToFile( CCLexFile* File, LPBITMAPINFO Info, LPBYTE Bits,
00928                             BOOL Interlace, INT32 TransparentColour,
00929                             BaseCamelotFilter* pFilter )
00930 {
00931 #ifdef DO_EXPORT
00932     ERROR2IF(File==NULL,FALSE,"ImageMagickFilter::WriteToFile File pointer is null");
00933     ERROR2IF(Info==NULL,FALSE,"ImageMagickFilter::WriteToFile BitmapInfo pointer is null");
00934     ERROR2IF(Bits==NULL,FALSE,"ImageMagickFilter::WriteToFile Bits pointer is null");
00935 
00936     // BITMAPINFO  consists of:-
00937     //      BITMAPINFOHEADER    bmiHeader;
00938     //      RGBQUAD             bmiColors[1];
00939     LPBITMAPINFOHEADER pInfoHeader = &Info->bmiHeader;
00940     ERROR2IF(pInfoHeader==NULL,FALSE,"ImageMagickFilter::WriteToFile BitmapInfoHeader pointer is null");
00941         
00942     LPRGBQUAD pPalette = &(Info->bmiColors[0]);
00943     ERROR2IF(pPalette==NULL,FALSE,"ImageMagickFilter::WriteToFile palette pointer is null");
00944 
00945     // Set up our format type flags.
00946     if(Info->bmiHeader.biBitCount == 32)
00947     {
00948         // If we`re exporting a 32Bit BMP then we need to make sure that we convert the
00949         // Alpha channel to Transparency! i.e. invert it!
00950         UINT32 BmpSize = Info->bmiHeader.biSizeImage;
00951 
00952         for(UINT32 i = 0; i < BmpSize; i+=4)
00953             Bits[i+3] = ~Bits[i+3];
00954     }
00955 
00956     if (CreateTempFile())
00957     {
00958         // Output a ImageMagick header for this file, using the RGBQUAD palette rather than a LOGPALETTE
00959         DestImageMagick.OutputPNGHeader(TempFile, pInfoHeader, Interlace, TransparentColour, NULL, pPalette);
00960     
00961         // Now write out the bitmap data itself.
00962         DestImageMagick.OutputPNGBits(TempFile, Bits, TRUE, pFilter);
00963         // The above has set the OutputFile member variable of DestImageMagick. We desperately need to
00964         // reset this as otherwise the next bitmap export may go wrong as it calls the tidy up
00965         // and so will refer to the deleted CCFile. Oh Er!
00966         DestImageMagick.TidyUp();
00967         ConvertFromTempFile(File);
00968     }
00969     else
00970     {
00971         DestImageMagick.TidyUp();
00972     }
00973 
00974     TidyTempFile();
00975 
00976     // er, we seem to have finished OK so say so
00977     return TRUE;
00978 #else
00979     return FALSE;
00980 #endif
00981 }
00982 
00983 /********************************************************************************************
00984 
00985 >   static BOOL ImageMagickFilter::WriteToFile ( CCLexFile* File, LPBITMAPINFO Info, LPBYTE Bits,
00986                                         String_64* ProgressString = NULL )
00987 
00988     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00989     Created:    26/4/96
00990     Inputs:     File    An opened CCFile that can be written to. It should be positioned at the
00991                         start. Caller is responsible for closing it. The file needs to be in
00992                         Binary mode.
00993                 Info    BITMAPINFO structure for the dib.
00994                 Bits    The bitmap data itself
00995                 ProgressString allows the user to specify whether they require a progress
00996                         hourglass or not. If NULL then none is shown, otherwise an progress bar 
00997                         is shown using the text supplied. Defaults to NULL i.e. no progress bar.
00998     Outputs:    -
00999     Returns:    TRUE if worked, FALSE if failed (error will be set accordingly but not reported)
01000     Purpose:    Write a bitmap in memory straight out as a ImageMagick to file with no rendering or
01001                 conversion between different colour depths (apart from 32 to 24) or resolution.
01002                 ***Errors on 16-bit builds***
01003                 A progress hourglass can be shown if required.
01004                 This function is used by the save bitmap button on the bitmap gallery. All
01005                 other bitmap export uses the OutputDIB class instead as this copes with using
01006                 a render region and converting from 32 to the destination format.
01007                 (caller should close file)
01008     Errors:     Calls SetError on FALSE returns.
01009     Scope:      Static
01010     SeeAlso:    AccusoftFilters::WriteToFile; DIBUtil::WriteToFile;
01011 
01012 ********************************************************************************************/
01013 BOOL ImageMagickFilter::WriteToFile( CCLexFile* File, LPBITMAPINFO Info, LPBYTE Bits,
01014                             String_64* ProgressString )
01015 {
01016 #ifdef DO_EXPORT
01017 
01018     ERROR2IF(File==NULL,FALSE,"ImageMagickFilter::WriteToFile File pointer is null");
01019     ERROR2IF(Info==NULL,FALSE,"ImageMagickFilter::WriteToFile BitmapInfo pointer is null");
01020     ERROR2IF(Bits==NULL,FALSE,"ImageMagickFilter::WriteToFile Bits pointer is null");
01021 
01022     // If the caller has specified a string then assume they require a progress bar
01023     // Start it up.
01024     if (ProgressString != NULL)
01025         BeginSlowJob(100, FALSE, ProgressString);
01026 
01027     // BITMAPINFO  consists of:-
01028     //      BITMAPINFOHEADER    bmiHeader;
01029     //      RGBQUAD             bmiColors[1];
01030     LPBITMAPINFOHEADER pInfoHeader = &Info->bmiHeader;
01031     ERROR2IF(pInfoHeader==NULL,FALSE,"ImageMagickFilter::WriteToFile BitmapInfoHeader pointer is null");
01032         
01033     LPRGBQUAD pPalette = &(Info->bmiColors[0]);
01034     ERROR2IF(pPalette==NULL,FALSE,"ImageMagickFilter::WriteToFile palette pointer is null");
01035 
01036     // Set up our format type flags.
01037     INT32 Transparent = -1; // colour or -1 = no transparency
01038     BOOL Interlace = s_OutputInterlaced;    // Use interlace or not
01039     BOOL WantTransparent = s_OutputTransparent;
01040 
01041     if (WantTransparent)
01042     {
01043         // We want to try and output the transparency if possible ...
01044 
01045         // Scan through the palette, and try and find an index with
01046         // the transparency flag set
01047 
01048         INT32 cols = Info->bmiHeader.biClrUsed;
01049         // If we have zero colours on a bitmap which is 8bpp or less then this is bad.
01050         // This should be translated as the maximum number of colours allowed
01051         if (Info->bmiHeader.biBitCount <= 8 && cols == 0)
01052             cols = 1 << Info->bmiHeader.biBitCount;
01053 
01054         for (INT32 i = 0; i < cols; i++)
01055         {
01056             if (Info->bmiColors[i].rgbReserved == 0xFF)
01057             {
01058                 Transparent = i;
01059                 TRACEUSER( "Neville", _T("ImageMagick output with transp index of %d\n"),Transparent);
01060                 break;
01061             }       
01062         }   
01063     }
01064 
01065     BOOL ok = CreateTempFile();
01066 
01067     if (ok)
01068     {
01069         // Output the ImageMagick data
01070         // Output a ImageMagick header for this file, using the RGBQUAD palette rather than a LOGPALETTE
01071         if (Transparent == -1)
01072             ok = DestImageMagick.OutputPNGHeader(TempFile, pInfoHeader, Interlace, -1, NULL, pPalette);
01073         else
01074             ok = DestImageMagick.OutputPNGHeader(TempFile, pInfoHeader, Interlace, Transparent, NULL, pPalette);
01075     }
01076 
01077     // Now write out the bitmap data itself.
01078     if (ok)
01079         ok = DestImageMagick.OutputPNGBits(TempFile, Bits, TRUE);
01080 
01081     // Tidy up here anyway
01082     DestImageMagick.TidyUp();
01083 
01084     // process it
01085     if (ok)
01086         ok = ConvertFromTempFile(File);
01087 
01088     // If started, then stop then progress bar
01089     if (ProgressString != NULL)
01090         EndSlowJob();
01091 
01092     TidyTempFile();
01093 
01094     ERROR1IF(!ok, FALSE, _R(IDE_IMAGEMAGICK_ERROR));
01095 
01096     // er, we seem to have finished OK so say so
01097     return TRUE;
01098 #endif
01099 }
01100 
01101 /********************************************************************************************
01102 
01103 >   virtual BOOL ImageMagickFilter::WritePreFrame(void)
01104 
01105     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01106     Created:    11/7/96
01107     Inputs:     -
01108     Returns:    FALSE if failed else TRUE
01109     Purpose:    To write out any frame specific info before the image
01110     SeeAlso:    GIFFilter::WritePreFrame(void)
01111 
01112 ********************************************************************************************/
01113 BOOL ImageMagickFilter::WritePreFrame(void)
01114 {
01115     return DestImageMagick.ReStartFile(NULL);
01116 }
01117 
01118 /********************************************************************************************
01119 
01120 >   virtual BOOL ImageMagickFilter::WriteFrame(void)
01121 
01122     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01123     Created:    11/7/96
01124     Inputs:     -
01125     Returns:    FALSE if failed else TRUE
01126     Purpose:    To write out the image itself
01127                 This base class version actually calls the WriteToFile() function so that
01128                 derived classes do not have to implement any of the multi-image stuff
01129     SeeAlso:    GIFFilter::WriteFrame(void)
01130 
01131 ********************************************************************************************/
01132 BOOL ImageMagickFilter::WriteFrame(void)
01133 {
01134     return MaskedFilter::WriteToFile(TRUE);
01135 }
01136 
01137 
01138 /********************************************************************************************
01139 
01140 >   virtual BOOL ImageMagickFilter::WritePostFrame(void)
01141 
01142     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01143     Created:    11/7/96
01144     Inputs:     -
01145     Returns:    FALSE if failed else TRUE
01146     Purpose:    To write out any frame specific info after the image
01147     SeeAlso:    GIFFilter::WritePostFrame(void)
01148 
01149 ********************************************************************************************/
01150 BOOL ImageMagickFilter::WritePostFrame(void)
01151 {
01152     return EndWriteToFile();
01153 }
01154 
01155 /********************************************************************************************
01156 
01157 >   virtual BOOL ImageMagickFilter::WriteFileEnd(void)
01158 
01159     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01160     Created:    11/7/96
01161     Inputs:     -
01162     Returns:    FALSE if failed else TRUE
01163     Purpose:    To write out the file specific data at the end of the file
01164                 This base class version calls EndWriteToFile() so that derived classes
01165                 do not have to implement the multi-image stuff
01166     SeeAlso:    GIFFilter::WriteFileEnd(void)
01167 
01168 ********************************************************************************************/
01169 BOOL ImageMagickFilter::WriteFileEnd(void)
01170 {
01171     return TRUE;
01172 }
01173 
01174 /********************************************************************************************
01175 
01176 >   virtual BOOL ImageMagickFilter::WritePreSecondPass(void)
01177 
01178     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01179     Created:    11/7/96
01180     Inputs:     -
01181     Returns:    FALSE if failed else TRUE
01182     Purpose:    Called to do any processing required after the first and before the second
01183                 pass of a two pass export
01184     SeeAlso:    GIFFilter::WritePreSecondPass(void)
01185 
01186 ********************************************************************************************/
01187 BOOL ImageMagickFilter::WritePreSecondPass(void)
01188 {
01189     return EndWriteToFile();
01190 }
01191 
01192 /********************************************************************************************
01193 
01194 >   virtual void ImageMagickFilter::InvertAlpha ( LPBITMAPINFO  lpBitmapInfo,
01195                                         LPBYTE      lpBits )
01196 
01197     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
01198     Created:    27/6/00
01199     Purpose:    Camelot uses a different transparency scheme to the rest of the world, in
01200                 that 255 is clear, and 0 is opaque. Until the rest of the world catches up,
01201                 it's necessary to invert the alpha channel to make exported files compatible
01202                 with other programs.
01203 
01204 ********************************************************************************************/
01205 void ImageMagickFilter::InvertAlpha ( LPBITMAPINFO  lpBitmapInfo,
01206                             LPBYTE      lpBits )
01207 {
01208     DIBUtil::InvertAlpha(lpBitmapInfo, lpBits);
01209 }
01210 
01211 /********************************************************************************************
01212 
01213 >   virtual OutputDIB* ImageMagickFilter::GetOutputDIB ( void )
01214 
01215     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
01216     Created:    27/6/00
01217     Returns     OutputDIB* - A pointer to DestImageMagick.
01218     Purpose:    Casts the current output DIB to be a generic OutputDIB class. This allows the
01219                 same code to be re-used in the base class.
01220 
01221 ********************************************************************************************/
01222 OutputDIB* ImageMagickFilter::GetOutputDIB ( void )
01223 {
01224     // Perform an upcast to allow the pointer to be used in a generic manner.
01225     return static_cast<OutputDIB*> ( &DestImageMagick );
01226 }
01227 
01228 /********************************************************************************************
01229 
01230 >   virtual BitmapExportOptions* ImageMagickFilter::CreateExportOptions() const
01231 
01232     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
01233     Created:    29/10/96
01234     Purpose:    See BaseBitmapFilter for interface details
01235     Notes:      Provides a new ImageMagickExportOptions instance
01236 
01237 ********************************************************************************************/
01238 BitmapExportOptions* ImageMagickFilter::CreateExportOptions() const
01239 {
01240     ImageMagickExportOptions* pImageMagickOptions = new ImageMagickExportOptions(IMAGEMAGICK, &FilterName, FilterNameID);
01241     return (BitmapExportOptions*)pImageMagickOptions;
01242 }
01243 
01244 void ImageMagickFilter::AlterPaletteContents( LPLOGPALETTE pPalette )
01245 {
01246     PORTNOTETRACE("filters","ImageMagickFilter::AlterPaletteContents - do nothing");
01247 //  DestImageMagick.AlterExportPalette( pPalette );
01248 }
01249 
01250 
01251 /********************************************************************************************
01252 
01253 >   BOOL ImageMagickFilter::CreateTempFile()
01254 
01255     Author:     Alex Bligh <alex@alex.org.uk>
01256     Created:    18/07/2006
01257     Purpose:    Create an expty temporary file
01258     Inputs:     None
01259     Outputs:    None
01260     Returns:    TRUE on success, FALSE on error
01261     Notes:      -
01262 
01263 ********************************************************************************************/
01264 
01265 BOOL ImageMagickFilter::CreateTempFile()
01266 {
01267     if (TempFile)
01268         delete TempFile;
01269 
01270     TempFile = new CCDiskFile;
01271     if (!TempFile)
01272         return FALSE;
01273 
01274     wxFile dummyFile; // to prevent deletion race condition
01275     TempFileName = wxFileName::CreateTempFileName(wxEmptyString, &dummyFile);
01276     PathName pthFileName=String_256(TempFileName);
01277     
01278     if (!(TempFile->open(pthFileName, ios::out | ios::trunc | ios::binary)))
01279     {
01280         ::wxRemoveFile(TempFileName);
01281         ERROR1(FALSE, _R(IDE_IMAGEMAGICK_ERROR));
01282     }
01283 
01284     return TRUE;
01285 }
01286 
01287 /********************************************************************************************
01288 
01289 >   BOOL ImageMagickFilter::ConvertFromTempFile(CCLexFile * File)
01290 
01291     Author:     Alex Bligh <alex@alex.org.uk>
01292     Created:    18/07/2006
01293     Purpose:    Process the temporary file by calling ImageMagick
01294     Inputs:     file - the CCLexFile for the final file
01295     Outputs:    None
01296     Returns:    TRUE on success, FALSE on error
01297     Notes:      -
01298 
01299 ********************************************************************************************/
01300 
01301 BOOL ImageMagickFilter::ConvertFromTempFile(CCLexFile * File)
01302 {
01303     PathName OutputPath = File->GetPathName();
01304     ERROR2IF(!OutputPath.IsValid(), FALSE, "ImageMagickFilter::ConvertFromTempFile can only be used on real files");
01305 
01306     ERROR2IF(!TempFile || TempFileName.IsEmpty(), FALSE, "ImageMagickFilter::ConvertFromTempFile has no temporary file to process");
01307     TempFile->close();
01308 
01309     wxChar * cifn;
01310     wxChar * cofn;
01311     wxChar * pcommand=_T("/usr/bin/convert");
01312     wxChar * IMargv[4];
01313 
01314     // get filename in usable form
01315     cifn = camStrdup(wxString(_T("png:"))+TempFileName );
01316     cofn = camStrdup(GetTag()+_T(":")+(const TCHAR *)(OutputPath.GetPath()));
01317 
01318     // Now convert the file
01319     IMargv[0]=pcommand;
01320     IMargv[1]=cifn;
01321     IMargv[2]=cofn;
01322     IMargv[3]=NULL;
01323     long /*TYPENOTE: Correct*/ ret = ::wxExecute((wxChar **)IMargv, wxEXEC_SYNC | wxEXEC_NODISABLE);
01324     
01325     free(cifn);
01326     free(cofn);
01327 
01328     if (ret)
01329     {
01330         TidyTempFile();
01331         ::wxRemoveFile(wxString((const TCHAR *)(OutputPath.GetPath())));
01332         ERROR1(FALSE, _R(IDE_IMAGEMAGICK_ERROR));
01333     }
01334 
01335     TidyTempFile(); // ensures filename zapped so it isn't removed later
01336 
01337     return TRUE;        
01338 }
01339 
01340 
01341 
01342 /********************************************************************************************
01343 
01344 >   BOOL ImageMagickFilter::ConvertToTempFile(CCLexFile * File)
01345 
01346     Author:     Alex Bligh <alex@alex.org.uk>
01347     Created:    18/07/2006
01348     Purpose:    Process the passed file into the temp file by calling ImageMagick
01349     Inputs:     file - the CCLexFile for the source file
01350     Outputs:    None
01351     Returns:    TRUE on success, FALSE on error
01352     Notes:      -
01353 
01354 ********************************************************************************************/
01355 
01356 BOOL ImageMagickFilter::ConvertToTempFile(CCLexFile * File)
01357 {
01358     if (!CreateTempFile())
01359         return FALSE;
01360 
01361     PathName InputPath = File->GetPathName();
01362     ERROR2IF(!InputPath.IsValid(), FALSE, "ImageMagickFilter::ConvertToTempFile can only be used on real files");
01363 
01364     ERROR2IF(!TempFile || TempFileName.IsEmpty(), FALSE, "ImageMagickFilter::ConvertToTempFile has no temporary file to process");
01365     TempFile->close();
01366 
01367     wxChar * cifn;
01368     wxChar * cofn;
01369     wxChar * pcommand=_T("/usr/bin/convert");
01370     wxChar * IMargv[10];
01371     wxChar * cdpi = NULL;
01372 
01373     // get filename in usable form
01374     cifn = camStrdup(GetTag()+_T(":")+(const TCHAR *)(InputPath.GetPath())+_T("[0]"));
01375     cofn = camStrdup(wxString(_T("png:"))+TempFileName );
01376 
01377     INT32 p = 0;
01378 
01379     // Now convert the file
01380     IMargv[p++]=pcommand;
01381     if (CanDoImportDPI())
01382     {
01383         // Always specify a DPI if the filter takes it, but use the screen default DPI if none specified
01384         wxScreenDC dc;
01385         wxSize DefaultDPI=OSRenderRegion::GetFixedDCPPI(dc);
01386         IMargv[p++]=_T("-density");
01387         UINT32  uHorzDpi = UINT32( m_ImportDPI ? m_ImportDPI : DefaultDPI.GetWidth() );
01388         UINT32  uVertDpi = UINT32( m_ImportDPI ? m_ImportDPI : DefaultDPI.GetHeight() );
01389         cdpi = camStrdup( wxString::Format( _T("%dx%d"), uHorzDpi, uVertDpi ) );
01390         IMargv[p++]=cdpi;   
01391     }
01392     IMargv[p++]=cifn;
01393     IMargv[p++]=cofn;
01394     IMargv[p++]=NULL;
01395 
01396 #ifdef AVOID_BROKEN_GDB
01397     ::wxCopyFile(wxString(_T("/tmp/test.png")), TempFileName);
01398 #else
01399     long /*TYPENOTE: Correct*/ ret = ::wxExecute((wxChar **)IMargv, wxEXEC_SYNC | wxEXEC_NODISABLE);
01400 #endif
01401     
01402     free(cifn);
01403     free(cofn);
01404     if (cdpi)
01405     {
01406         free(cdpi);
01407         cdpi = NULL;
01408     }
01409 
01410     if (ret)
01411     {
01412         TidyTempFile();
01413         ERROR1(FALSE, _R(IDE_IMAGEMAGICK_ERROR));
01414     }
01415 
01416     PathName pthFileName=String_256(TempFileName);
01417 
01418     // Reopen the file
01419     if (!(TempFile->open(pthFileName, ios::in | ios::binary)))
01420     {
01421         TidyTempFile();
01422         ERROR1(FALSE, _R(IDE_IMAGEMAGICK_ERROR));
01423     }
01424 
01425     return TRUE;        
01426 }
01427 
01428 /********************************************************************************************
01429 
01430 >   BOOL ImageMagickFilter::TidyTempFile(BOOL Delete=TRUE)
01431 
01432     Author:     Alex Bligh <alex@alex.org.uk>
01433     Created:    18/07/2006
01434     Purpose:    Closes any temporary file, and potentially removes it
01435     Inputs:     None
01436     Outputs:    None
01437     Returns:    TRUE on success, FALSE on error
01438     Notes:      -
01439 
01440 ********************************************************************************************/
01441 
01442 BOOL ImageMagickFilter::TidyTempFile(BOOL Delete/*=TRUE*/)
01443 {
01444     if (TempFile)
01445     {
01446         delete (TempFile);
01447         TempFile = NULL;
01448     }
01449 
01450     if (!TempFileName.IsEmpty())
01451     {
01452         if (Delete)
01453             ::wxRemoveFile(TempFileName);
01454         TempFileName = wxEmptyString;
01455     }
01456     return TRUE;
01457 }
01458 
01459 /********************************************************************************************
01460 
01461 >   static BOOL ImageMagickFilter::CheckPath()
01462 
01463     Author:     Alex Bligh <alex@alex.org.uk>
01464     Created:    18/07/2006
01465     Purpose:    Determines whether or not ImageMagick is installed. Also registers filter prefs
01466     Inputs:     None
01467     Outputs:    None
01468     Returns:    TRUE if ImageMagick is available, else fals
01469     Notes:      -
01470 
01471 ********************************************************************************************/
01472 
01473 BOOL ImageMagickFilter::CheckPath()
01474 {
01475     if (s_HaveCheckedPath)
01476         return s_HaveImageMagick;
01477 
01478     s_HaveImageMagick = FALSE;
01479     s_HaveCheckedPath = TRUE;
01480 
01481     BOOL ok = Camelot.DeclareSection(_T("Filters"), 10)
01482             && Camelot.DeclarePref( NULL, _T("ImageMagickDisable"), &ImageMagickFilter::s_Disable, 0, 1 )
01483             && Camelot.DeclarePref( NULL, _T("ImageMagickWarning"), &ImageMagickFilter::s_DoWarning, 0, 1 )
01484             && Camelot.DeclarePref( NULL, _T("ImageMagickPath"), &ImageMagickFilter::s_ImageMagickPath );
01485 
01486     if (!ok || s_Disable)
01487         return s_HaveImageMagick;
01488 
01489     if (s_ImageMagickPath == _T(""))
01490         s_ImageMagickPath = DIP_QUOTE(DEFAULT_IMAGEMAGICK_PATH);
01491 
01492     wxArrayString output;
01493     long /*TYPENOTE: Correct*/ ret=::wxExecute(wxString((const TCHAR *)s_ImageMagickPath)/*+_T(" --version")*/, output, wxEXEC_SYNC | wxEXEC_NODISABLE);
01494     if (!ret && output.GetCount()>0)
01495     {
01496         wxString check = output[0];
01497         wxString version;
01498         if (check.StartsWith(_T("Version: ImageMagick "),&version))
01499         {
01500             wxStringTokenizer tk(version, _T(".: "));
01501             if (tk.CountTokens()>=3)
01502             {
01503                 long /*TYPENOTE: Correct*/ v1,v2,v3=0;
01504                 tk.GetNextToken().ToLong(&v1);
01505                 tk.GetNextToken().ToLong(&v2);
01506                 tk.GetNextToken().ToLong(&v3);
01507                 double version = v1*10000.0+v2*100.0+v3;
01508                 if (version>=060000.0)
01509                 {
01510                     s_HaveImageMagick = TRUE;
01511                     s_DoWarning = TRUE; // warn them again if it ever goes away
01512                 }
01513             }
01514         }
01515     }
01516 
01517     if (!s_HaveImageMagick && s_DoWarning)
01518     {
01519         InformWarning(_R(IDS_WARN_NOIMAGEMAGICK), _R(IDS_OK));
01520         s_DoWarning = FALSE; // disable the warning on subsequent runs
01521     }
01522 
01523     return s_HaveImageMagick;       
01524 }
01525 
01526 /********************************************************************************************
01527 
01528 >   ImageMagickOILFilter::ImageMagickOILFilter(Filter* pFilter)
01529 
01530     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01531     Created:    18/07/2006
01532     Inputs:     pFilter - The Filter
01533     Purpose:    Constructs the oily parts of the PNG File Format Filter (ie the list of
01534                 File Extensions that this filter understands)
01535 
01536 ********************************************************************************************/
01537 
01538 ImageMagickOILFilter::ImageMagickOILFilter(Filter* pFilter, ResourceID FilterNameID, ResourceID FilterExtID) : OILFilter(pFilter)
01539 {
01540     FilterName.Load(FilterNameID);
01541     FilterExt.Load(FilterExtID);
01542 } 

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