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 }