// $Id: bmpcomp.cpp 1488 2006-07-20 15:31:34Z phil $ /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE ================================XARAHEADERSTART=========================== Xara LX, a vector drawing and manipulation program. Copyright (C) 1993-2006 Xara Group Ltd. Copyright on certain contributions may be held in joint with their respective authors. See AUTHORS file for details. LICENSE TO USE AND MODIFY SOFTWARE ---------------------------------- This file is part of Xara LX. Xara LX is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. Xara LX and its component source files are distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Xara LX (see the file GPL in the root directory of the distribution); if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ADDITIONAL RIGHTS ----------------- Conditional upon your continuing compliance with the GNU General Public License described above, Xara Group Ltd grants to you certain additional rights. The additional rights are to use, modify, and distribute the software together with the wxWidgets library, the wxXtra library, and the "CDraw" library and any other such library that any version of Xara LX relased by Xara Group Ltd requires in order to compile and execute, including the static linking of that library to XaraLX. In the case of the "CDraw" library, you may satisfy obligation under the GNU General Public License to provide source code by providing a binary copy of the library concerned and a copy of the license accompanying it. Nothing in this section restricts any of the rights you have under the GNU General Public License. SCOPE OF LICENSE ---------------- This license applies to this program (XaraLX) and its constituent source files only, and does not necessarily apply to other Xara products which may in part share the same code base, and are subject to their own licensing terms. This license does not apply to files in the wxXtra directory, which are built into a separate library, and are subject to the wxWindows license contained within that directory in the file "WXXTRA-LICENSE". This license does not apply to the binary libraries (if any) within the "libs" directory, which are subject to a separate license contained within that directory in the file "LIBS-LICENSE". ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS ---------------------------------------------- Subject to the terms of the GNU Public License (see above), you are free to do whatever you like with your modifications. However, you may (at your option) wish contribute them to Xara's source tree. You can find details of how to do this at: http://www.xaraxtreme.org/developers/ Prior to contributing your modifications, you will need to complete our contributor agreement. This can be found at: http://www.xaraxtreme.org/developers/contribute/ Please note that Xara will not accept modifications which modify any of the text between the start and end of this header (marked XARAHEADERSTART and XARAHEADEREND). MARKS ----- Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara designs are registered or unregistered trademarks, design-marks, and/or service marks of Xara Group Ltd. All rights in these marks are reserved. Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. http://www.xara.com/ =================================XARAHEADEREND============================ */ // Kernel level parts of bitmap lists /* */ #include "camtypes.h" #include "bmpcomp.h" //#include "bmplist.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "bitmap.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "bitmpinf.h" #include "bmpsrc.h" #include "ccbuffil.h" //#include "list.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "fillattr.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "will.h" #include "nativeps.h" // The old style EPS native filter, used in v1.1 #include "clipint.h" #include "nodebmp.h" //#include "progress.h" #include "toollist.h" #include "objchge.h" #include "csrstack.h" #include "clipint.h" #include "ophist.h" #include "sgliboil.h" //#include "will2.h" #include "expbmp.h" // ExportedBitmaps handling class #include "impbmp.h" // ImportedBitmaps handling class //#include "camfiltr.h" // BaseCamelotFilter - version 2 native filter - in camtypes.h [AUTOMATICALLY REMOVED] #include "cxftags.h" // TAG_DEFINEBITMAP_**** #include "cxfile.h" // CXF_UNKNOWN_SIZE //#include "cxfrech.h" // CXaraFileRecordHandler - in camtypes.h [AUTOMATICALLY REMOVED] #include "expcol.h" // ExportedColours handling class //#include "cxfrec.h" // CXaraFileRecord handler - in camtypes.h [AUTOMATICALLY REMOVED] //#include "tim.h" // _R(IDT_CANT_FIND_FILTER) //#include "filtrres.h" // _R(IDS_DONT_SUPPORT_BITMAP_TYPE) _R(IDS_NATIVE_BITMAPWARNING) #include "bitfilt.h" // BaseBitmapFlter //#include "fixmem.h" // CCMalloc, CCFree - in camtypes.h [AUTOMATICALLY REMOVED] CC_IMPLEMENT_MEMDUMP( BitmapList, List ) CC_IMPLEMENT_DYNAMIC( BitmapListComponentClass, DocComponentClass ) CC_IMPLEMENT_DYNAMIC( BitmapListComponent, DocComponent ) // Declare smart memory handling in Debug builds #define new CAM_DEBUG_NEW /********************************************************************************************** > BitmapList::BitmapList() Author: Will_Cowling (Xara Group Ltd) Created: 12/12/94 Inputs: - Outputs: - Returns: - Purpose: BitmapList constructor **********************************************************************************************/ BitmapList::BitmapList() { ParentDoc = NULL; // Document containing this list } /********************************************************************************************** > BitmapList::~BitmapList() Author: Will_Cowling (Xara Group Ltd) Created: 12/12/94 Inputs: - Outputs: - Returns: - Purpose: BitmapList destructor **********************************************************************************************/ BitmapList::~BitmapList() { ListItem* pItem = GetHead(); ListItem* pNextItem; while (pItem) { pNextItem = GetNext(pItem); KernelBitmap* pBmp = (KernelBitmap*)pItem; ERROR3IF(pBmp->GetParentBitmapList() != this, "Bad ParentList ptr found in bitmap (during BitmapList destructor)"); // if this bitmap is used by a brush we don't want to delete it here. if (!pBmp->IsUsedByBrush()) delete pBmp; // This should remove it from the list first else { pBmp->Detach(); RemoveItem(pBmp); } pItem = pNextItem; } // Tidy up the global bitmap list Camelot.GetGlobalBitmapList()->DeleteAllUnusedBitmaps(); } /********************************************************************************************** > void BitmapList::Init(BaseDocument *ParentDocument) Author: Will_Cowling (Xara Group Ltd) Created: 12/12/94 Inputs: ParentDocument - the parent document of this Bitmap list Purpose: BitmapList initialiser. MUST be called after constructing a BitmapList in order to correctly initialise it. Note that if ParentDocument is not set to a useful value, some operations on Bitmap lists will fail. **********************************************************************************************/ void BitmapList::Init(BaseDocument *ParentDocument) { ERROR3IF(ParentDocument == NULL, "NULL ParentDoc in BitmapList::Init!\n"); // Ensure the default bitmap is always in the list. KernelBitmap* Default = new KernelBitmap(); Default->Attach(this); ParentDoc = ParentDocument; } /********************************************************************************************** > BOOL BitmapList::AddItem(KernelBitmap *Item) Author: Will_Cowling (Xara Group Ltd) Created: 12/12/94 Returns: TRUE Purpose: Adds an item to the tail of the Bitmaplist, and incremeants it's usage count. (Unless it's already in the list, in which case it's usage count is just bumped up). **********************************************************************************************/ BOOL BitmapList::AddItem(KernelBitmap *Item) { ERROR3IF(Item == NULL, "Trying to add NULL item to Bitmap List"); if (Item == NULL) return FALSE; // Is this Bitmap already in the list ? LISTPOS pos = FindPosition((ListItem*)Item); if (pos == NOT_IN_LIST || pos == EMPTY_LIST) { // It's not in the list yet, so add it on the end AddTail((ListItem*)Item); if (ParentDoc != NULL) { BROADCAST_TO_ALL(BitmapListChangedMsg(this)); } return TRUE; } else { // It's already in the list, so just return // (It's usage count has already been incremeanted) return FALSE; } } /********************************************************************************************** > BOOL BitmapList::RemoveItem(KernelBitmap *Item) Author: Will_Cowling (Xara Group Ltd) Created: 12/12/94 Returns: TRUE Purpose: Removes an item from the list. **********************************************************************************************/ BOOL BitmapList::RemoveItem(KernelBitmap *Item) { ERROR3IF(Item == NULL, "Trying to remove NULL item from Bitmap List"); if (Item == NULL) return FALSE; // Is this Bitmap in the list ? LISTPOS pos = FindPosition((ListItem*)Item); if (pos != NOT_IN_LIST || pos == EMPTY_LIST) { // It's not in the list yet, so add it on the end List::RemoveItem((ListItem*)Item); Item->m_pParentList = NULL; if (ParentDoc != NULL) { BROADCAST_TO_ALL(BitmapListChangedMsg(this)); } return TRUE; } else { // It's not in the list, so just return return FALSE; } } /********************************************************************************************** > BOOL BitmapList::MoveBefore(KernelBitmap *InsertPoint, KernelBitmap *ItemToMove) Author: Will_Cowling (Xara Group Ltd) Created: 12/12/94 Returns: TRUE Purpose: Re-arranges the bitmaps in the list. **********************************************************************************************/ BOOL BitmapList::MoveBefore(KernelBitmap *InsertPoint, KernelBitmap *ItemToMove) { List::RemoveItem((ListItem*)ItemToMove); List::InsertBefore((ListItem*)InsertPoint, (ListItem*)ItemToMove); if (ParentDoc != NULL) { BROADCAST_TO_ALL(BitmapListChangedMsg(this)); } return TRUE; } /********************************************************************************************** > BOOL BitmapList::MoveAfter(KernelBitmap *InsertPoint, KernelBitmap *ItemToMove) Author: Will_Cowling (Xara Group Ltd) Created: 12/12/94 Returns: TRUE Purpose: Re-arranges the bitmaps in the list. **********************************************************************************************/ BOOL BitmapList::MoveAfter(KernelBitmap *InsertPoint, KernelBitmap *ItemToMove) { List::RemoveItem((ListItem*)ItemToMove); List::InsertAfter((ListItem*)InsertPoint, (ListItem*)ItemToMove); if (ParentDoc != NULL) { BROADCAST_TO_ALL(BitmapListChangedMsg(this)); } return TRUE; } /********************************************************************************************** > BaseDocument *BitmapList::GetParentDocument(void) Author: Will_Cowling (Xara Group Ltd) Created: 12/12/94 Returns: The document in which this Bitmap list resides Purpose: To find the parent document of this Bitmap list **********************************************************************************************/ BaseDocument *BitmapList::GetParentDocument(void) { ERROR3IF(ParentDoc == NULL, "Uninitialised BitmapList detected!"); return(ParentDoc); } /********************************************************************************************** > KernelBitmap* BitmapList::FindDuplicateBitmap(OILBitmap* pBitmap) Author: Will_Cowling (Xara Group Ltd) Created: 14/8/96 Purpose: Looks to see if an identical bitmap is already in the bitmap list **********************************************************************************************/ KernelBitmap* BitmapList::FindDuplicateBitmap(OILBitmap* pOILBitmap) { ListItem* pItem = GetHead(); while (pItem != NULL) { KernelBitmap* pBmp = (KernelBitmap*)pItem; if (pBmp->ActualBitmap && pBmp->ActualBitmap != pOILBitmap && *pBmp->ActualBitmap == *pOILBitmap) { return pBmp; } pItem = GetNext(pItem); } return NULL; } /********************************************************************************************** > KernelBitmap* BitmapList::FindDefaultBitmap() Author: Will_Cowling (Xara Group Ltd) Created: 10/8/96 Purpose: Finds the default bitmap in this bitmap list **********************************************************************************************/ KernelBitmap* BitmapList::FindDefaultBitmap() { ListItem* pItem = GetHead(); while (pItem != NULL) { KernelBitmap* pBmp = (KernelBitmap*)pItem; if (pBmp->ActualBitmap && pBmp->ActualBitmap == OILBitmap::Default) { return pBmp; } pItem = GetNext(pItem); } return NULL; } /******************************************************************************************** > BOOL BitmapListComponentClass::Init() Author: Will_Cowling (Xara Group Ltd) Created: 12/12/94 Returns: TRUE if all went well; FALSE if not. Purpose: Register the Bitmap list document component with the main application. Errors: Out of memory. SeeAlso: DocComponent ********************************************************************************************/ BOOL BitmapListComponentClass::Init() { // Instantiate a component class to register with the application. BitmapListComponentClass *pClass = new BitmapListComponentClass; if (pClass == NULL) return FALSE; // Register it GetApplication()->RegisterDocComponent(pClass); // All ok return TRUE; } /******************************************************************************************** > BOOL BitmapListComponentClass::AddComponent(BaseDocument *pDocument) Author: Will_Cowling (Xara Group Ltd) Created: 12/12/94 Inputs: pDocument - the document to add the Bitmap list to. Returns: TRUE if the Bitmap list was added ok; FALSE if not. Purpose: Add a Bitmap list component to the specified document. Errors: Out of memory SeeAlso: BitmapListComponentClass ********************************************************************************************/ BOOL BitmapListComponentClass::AddComponent(BaseDocument *pDocument) { // Check to see if this document already has a Bitmap list; if so, leave it alone. if (pDocument->GetDocComponent(CC_RUNTIME_CLASS(BitmapListComponent)) != NULL) return TRUE; // No Bitmap list - try to create a new one for this document. BitmapList *pList = new BitmapList; if(pList == NULL) return FALSE; pList->Init(pDocument); // Let the BitmapList know what its parent document is // Ok - create the Bitmap list component using this list. BitmapListComponent *pComponent = new BitmapListComponent(pList); if (pComponent == NULL) { // Out of memory... delete pList; return FALSE; } // All ok - add the component to the document. pDocument->AddDocComponent(pComponent); return TRUE; } /******************************************************************************************** > BitmapListComponent::BitmapListComponent() Author: Will_Cowling (Xara Group Ltd) Created: 12/12/94 Purpose: Construct a Bitmap list component. DO NOT use this constructor. It gives and ERROR3 (and sets up this in a semi-safe default state) SeeAlso: BitmapListComponent ********************************************************************************************/ BitmapListComponent::BitmapListComponent() { ERROR3("BitmapListComponent constructed with default constructor!?\n"); } /******************************************************************************************** > BitmapListComponent::BitmapListComponent(BitmapList *pBmpList) Author: Will_Cowling (Xara Group Ltd) Created: 12/12/94 Inputs: pColList - the Bitmap list to use for this Bitmap list componet. Purpose: Construct a Bitmap list component using the given Bitmap list. Errors: ENSURE if pColList is NULL. SeeAlso: BitmapListComponent ********************************************************************************************/ BitmapListComponent::BitmapListComponent(BitmapList *pBmpList) { ENSURE(pBmpList != NULL, "NULL Bitmap list in Bitmap list component constructor!"); // Install this Bitmap list. pBitmaps = pBmpList; // Initialise Exporter bitmap list pExportedBitmaps = NULL; // Initialise Importer bitmap list pImportedBitmaps = NULL; // Our link to the BaseCamelotFilter pCamFilter = NULL; // Set our variable so that we warn about a possible replacement only once WarnedBefore = FALSE; // Initialise Exporter bitmap list (used for EPS only) pBitmapsToExport = NULL; } /******************************************************************************************** > BitmapListComponent::~BitmapListComponent() Author: Will_Cowling (Xara Group Ltd) Created: 12/12/94 Purpose: Clean up a Bitmap list component's data structures - deletes the Bitmap list. Errors: - SeeAlso: BitmapListComponent ********************************************************************************************/ BitmapListComponent::~BitmapListComponent() { // Delete our Bitmap list. delete pBitmaps; // As we have finished with it now, destroy the list of imported bitmaps if (pImportedBitmaps) { delete pImportedBitmaps; pImportedBitmaps = NULL; } // As we have finished with it now, destroy the list of exported bitmaps if (pExportedBitmaps) { delete pExportedBitmaps; pExportedBitmaps = NULL; } if (pBitmapsToExport) { delete pBitmapsToExport; pBitmapsToExport = NULL; } } /******************************************************************************************** > BOOL BitmapListComponent::EPSStartImport(EPSFilter *pFilter) Author: Will_Cowling (Xara Group Ltd) Created: 12/12/94 Inputs: pFilter - the EPS filter that is being used to import a file. Purpose: Inform the Bitmap list document component that an EPS import is about to start. SeeAlso: DocComponent ********************************************************************************************/ BOOL BitmapListComponent::EPSStartImport(EPSFilter *pFilter) { return FALSE; } /******************************************************************************************** > void BitmapListComponent::EPSEndImport(EPSFilter *pFilter, BOOL Success) Author: Will_Cowling (Xara Group Ltd) Created: 12/12/94 Inputs: pFilter - the EPS filter that is being used to import a file. Success - TRUE => The import was successful; FALSE => The import failed - abandon any changes. Purpose: Inform the Bitmap list document component that an EPS import has just finished. SeeAlso: DocComponent ********************************************************************************************/ void BitmapListComponent::EPSEndImport(EPSFilter *pFilter, BOOL Success) { } /******************************************************************************************** > BOOL BitmapListComponent::EPSStartExport(EPSFilter *pFilter) Author: Will_Cowling (Xara Group Ltd) Created: 12/12/94 Inputs: pFilter - the EPS filter that is being used to import a file. Purpose: Inform the Bitmap list document component that an EPS export is about to start. SeeAlso: DocComponent ********************************************************************************************/ BOOL BitmapListComponent::EPSStartExport(EPSFilter *pFilter) { #ifdef DO_EXPORT ERROR3IF(pBitmapsToExport != NULL, "Why is there an export bitmap list already ?"); // Build the list of bitmaps to export here ... pBitmapsToExport = new ExportedBitmaps(); ERROR3IF(pBitmapsToExport == NULL, "Couldn't create bitmap export list !!"); if (pBitmapsToExport == NULL) return FALSE; Document* ParentDoc = (Document*)pBitmaps->GetParentDocument(); ERROR3IF(ParentDoc == NULL, "Bitmap list has no parent document !!"); if (ParentDoc == NULL) { delete pBitmapsToExport; pBitmapsToExport = NULL; return FALSE; } UINT32 BitmapNumber = 0; // Scan the document's tree for bitmap references Node* pNode = Node::DocFindFirstDepthFirst(ParentDoc); while (pNode != NULL) { // Ignore hidden nodes if (!pNode->IsNodeHidden()) { INT32 Count = 0; // Does this node have any bitmaps in it ? KernelBitmap* pBitmap = pNode->EnumerateBitmaps(Count++); while (pBitmap != NULL) { // Check for a deleted bitmap if (pBitmap->HasBeenDeleted()) { ERROR2IF(pBitmap->GetParentBitmapList() == NULL, 0L, "Deleted bitmap has no parent list"); // Use the default bitmap instead pBitmap = pBitmap->GetParentBitmapList()->FindDefaultBitmap(); // There should always be a default bitmap at the start of the list ERROR2IF(pBitmap == NULL, 0L, "Couldn't find the default bitmap"); } // Found a bitmap reference, so ... // .. if this bitmap is not in the export list, add it if (pBitmapsToExport->GetBitmap(pBitmap) == NULL) pBitmapsToExport->AddBitmap(pBitmap, BitmapNumber++); pBitmap = pNode->EnumerateBitmaps(Count++); } } // Move onto the next node in the tree pNode = pNode->DocFindNextDepthFirst(); } #endif return TRUE; } /******************************************************************************************** > void BitmapListComponent::EPSEndExport(EPSFilter *pFilter, BOOL Success) Author: Will_Cowling (Xara Group Ltd) Created: 12/12/94 Inputs: pFilter - the EPS filter that is being used to import a file. Success - TRUE => The import was successful; FALSE => The import failed - abandon any changes. Purpose: Inform the Bitmap list document component that an EPS export has just finished. SeeAlso: DocComponent ********************************************************************************************/ void BitmapListComponent::EPSEndExport(EPSFilter *pFilter) { #ifdef DO_EXPORT if (pBitmapsToExport) { delete pBitmapsToExport; pBitmapsToExport = NULL; } #endif } /******************************************************************************************** > BOOL BitmapListComponent::WriteEPSComments(EPSFilter *pFilter) Author: Will_Cowling (Xara Group Ltd) Created: 12/12/94 Inputs: pFilter - the filter being used to import the EPS file. Returns: TRUE if the Bitmap table was written successfully; FALSE if not. Purpose: Writes out the Bitmap table in the form of EPS comments in the 'header' comments of the EPS file. Errors: Out of disk space, and similar disk errors. SeeAlso: DocComponent::WriteEPSComments; DocComponent ********************************************************************************************/ BOOL BitmapListComponent::WriteEPSComments(EPSFilter *pFilter) { return TRUE; } /******************************************************************************************** > BOOL BitmapListComponent::WriteScript(EPSFilter* pFilter) Author: Rik_Heywood (Xara Group Ltd) Created: 18/1/95 Inputs: pFilter - the EPS filter that is being used to export a file. Returns: TRUE if the Script for this component was written out successfully; FALSE if not (e.g. out of disk space etc) Purpose: This is called after all the Comments, Prolog etc have been output so that DocComponents get a chance to do something right at the start of the real EPS data, but before the tree starts to be exported. (The base class does nothing) SeeAlso: DocComponent::WriteEPSSetup; DocComponent::WriteEPSProlog; DocComponent::ProcessEPSComment; DocComponent; EPSFIlter ********************************************************************************************/ BOOL BitmapListComponent::WriteScript(EPSFilter* pFilter) { #ifdef DO_EXPORT // This only happens in Native EPS if (pFilter->IS_KIND_OF(CamelotNativeEPSFilter)) { // Find out the context to save to EPSExportDC *pDC = pFilter->GetExportDC(); // Make sure that there's a bitmap list to export. if (pBitmapsToExport == NULL) { ERROR3 ( "Why isn't there an export bitmap list (in WriteScript) ?" ); return FALSE; } // Something to mark the start of the bitmap pool pDC->OutputToken(_T("%%BeginCamelotBitmapPool")); pDC->OutputNewLine(); // Tell the filter we are starting to save the bitmap pool ((CamelotNativeEPSFilter*)pFilter)->IsSavingBitmapPool = TRUE; // Find the number of Bitmaps INT32 TotalBitmaps = pBitmapsToExport->GetCount(); // Output a comment saying how many bitmaps we have pDC->OutputToken(_T("%%BitmapPoolCount")); pDC->OutputValue(TotalBitmaps); pDC->OutputNewLine(); INT32 BitmapNum = 0; // Find the first bitmap in the list again ExportBitmap* pExportBitmap = pBitmapsToExport->EnumerateBitmaps(); while (pExportBitmap != NULL) { ERROR3IF(pExportBitmap->RecordNumber != BitmapNum, "Bad bitmap number found when saving bitmap pool"); // Save the bitmap out ExportBitmapPoolItem(BitmapNum, pFilter, pDC, pExportBitmap->pBmp); BitmapNum++; // Find the next one pExportBitmap = pBitmapsToExport->EnumerateBitmaps(pExportBitmap); } // Tell the filter we are starting to save the bitmap pool ((CamelotNativeEPSFilter*)pFilter)->IsSavingBitmapPool = FALSE; // Something to mark the start of the bitmap pool pDC->OutputToken(_T("%%EndCamelotBitmapPool")); pDC->OutputNewLine(); } #endif return TRUE; } /******************************************************************************************** > BOOL BitmapListComponent::ExportBitmapPoolItem(INT32 BitmapNum, EPSFilter* pFilter, EPSExportDC* pDC, KernelBitmap* pBitmap) Author: Rik_Heywood (Xara Group Ltd) Created: 19/1/95 Inputs: BitmapNum - The number of the Kernel bitmap in the pool pFilter - The filter that things are being saved in pDC - The DC that the saving is happening in pBitmap - The Kernel Bitmap to be saved Returns: TRUE if it worked, FALSE if not Purpose: Does the actual saving for a bitmap pool item. This uses the cbmp token to represent the Camelot BitMap Pool object. ********************************************************************************************/ BOOL BitmapListComponent::ExportBitmapPoolItem(INT32 BitmapNum, EPSFilter* pFilter, EPSExportDC* pDC, KernelBitmap* pBitmap) { #ifdef DO_EXPORT ERROR2IF(pBitmap->HasBeenDeleted(), FALSE, "Trying to export a deleted bitmap"); if (pFilter->IS_KIND_OF(CamelotNativeEPSFilter)) { // ...then the bitmap object token. pDC->OutputValue(BitmapNum); // Output the number of the bitmap pDC->OutputValue(INT32(0)); // Bitmap pool type (ready for expansion) pDC->OutputToken(_T("cbmp")); // Bitmap pool token pDC->OutputNewLine(); // ...and then the bitmap data itself. pFilter->ExportBitmap(*pBitmap); // Tell caller we rendered ourselves ok return TRUE; } #endif return FALSE; } /******************************************************************************************** > ProcessEPSResult BitmapListComponent::ProcessEPSComment(EPSFilter *pFilter, const char *pComment) Author: Will_Cowling (Xara Group Ltd) Created: 12/12/94 Inputs: pFilter - the EPS filter that is being used to import a file. pComment - pointer to the comment to process. Returns: EPSCommentUnknown - This EPS comment is not recognised by the document component. EPSCommentError - This EPS comment was recognised by this document component, but it contained an error. EPSCommentOK - This EPS comment was recognised as a legal comment by this document component, and was processed successfully. Purpose: Process an EPS comment - if this is a Bitmap table comment, this component will claim it and try to decode it. Errors: Badly formed EPS comment. SeeAlso: DocComponent::ProcessEPSComment ********************************************************************************************/ ProcessEPSResult BitmapListComponent::ProcessEPSComment(EPSFilter *pFilter, const char *pComment) { // Ignore all comments return EPSCommentUnknown; } /******************************************************************************************** > void BitmapListComponent::EndOfEPSComment(EPSFilter *pFilter) Author: Will_Cowling (Xara Group Ltd) Created: 12/12/94 Inputs: pFilter - the EPS filter that is being used to import a file. Purpose: Informs the document component that the comment it has been decoding has now finished, and it should take whatever action required to act on the comment. SeeAlso: DocComponent::EndOfPESComment ********************************************************************************************/ void BitmapListComponent::EndOfEPSComment(EPSFilter *pFilter) { // Do any cleanup we need to here after loading in a Bitmap table... } /******************************************************************************************** > INT32 BitmapListComponent::GetSizeOfExport(Filter *pFilter) Author: Tim_Browse (Xara Group Ltd) Created: 27/01/95 Inputs: pFilter - the export filter that will be used. Returns: An approximation of the size of data that will be exported by this bitmap list, in terms of nodes. (see NodeRenderable::GetSizeOfExport). Purpose: Find out how many nodes will be exported when this bitmap list is exported. The node can use the filter to find out how it will be exported, e.g. bitmap lists should return a value that reflects whether or not bitmap indirection is possible with this filter and so on. NB. This is virtual - the default implementation just returns 1 - only override if this is not accurate. SeeAlso: Node::NeedsToExport; Node::ExportRender; NodeRenderable::GetSizeOfExport ********************************************************************************************/ INT32 BitmapListComponent::GetSizeOfExport(Filter *pFilter) { #ifdef DO_EXPORT // Check if this filter supports bitmap pools if (pFilter->GetBitmapSupportLevel() != IndirectedBitmapSupport) // No - just return 1. return 1; ERROR3IF(pBitmapsToExport == NULL, "Why isn't there an export bitmap list (in GetSizeOfExport) ?"); if (pBitmapsToExport == NULL) return 1; INT32 TotalScanlines = 0; // Find the first bitmap in the list again ExportBitmap* pExportBitmap = pBitmapsToExport->EnumerateBitmaps(); while (pExportBitmap != NULL) { KernelBitmap* pBitmap = pExportBitmap->pBmp; // Get information on this bitmap. BitmapInfo Info; if (!pBitmap->ActualBitmap->GetInfo(&Info)) // Failed for some reason - bodge the answer. return 1; // Add the number of scanlines to our total TotalScanlines += Info.PixelHeight; // Find the next one pExportBitmap = pBitmapsToExport->EnumerateBitmaps(pExportBitmap); } // Return size to caller. if (TotalScanlines == 0) return 1; else return TotalScanlines; #else return 0; #endif } /******************************************************************************************** > virtual BOOL BitmapListComponent::StartComponentCopy(); Author: Will_Cowling (Xara Group Ltd) Created: 12/12/94 Inputs: - Outputs: - Returns: TRUE if it succeeded. FALSE if the copy must be aborted Purpose: This function gets called to prepare for a copy of Bitmaps into the document. It sets up the various arrays and other thangs which the Bitmap copy will need. Errors: ENSURE failure if called when a component copy is already under way. Errors will be reported if memory is unavailable SeeAlso: BitmapListComponent::EndComponentCopy; BitmapListComponent::AbortComponentCopy; BitmapListComponent::CopyBitmapAcross ********************************************************************************************/ BOOL BitmapListComponent::StartComponentCopy() { return(TRUE); } /******************************************************************************************** > virtual BOOL BitmapListComponent::EndComponentCopy(); Author: Will_Cowling (Xara Group Ltd) Created: 12/12/94 Inputs: - Outputs: - Returns: TRUE if it succeeded Purpose: Will commit all changes made by doing the component copy, returning TRUE. Errors: - Notes: May be called multiple times - subsequent calls will be ignored SeeAlso: BitmapListComponent::StartComponentCopy; BitmapListComponent::AbortComponentCopy; BitmapListComponent::CopyBitmapAcross ********************************************************************************************/ BOOL BitmapListComponent::EndComponentCopy() { return(TRUE); } /******************************************************************************************** > virtual void BitmapListComponent::AbortComponentCopy(); Author: Will_Cowling (Xara Group Ltd) Created: 12/12/94 Inputs: - Outputs: - Returns: - Purpose: Will abort all changes made for component copies. This means that things such as the Bitmaps referenced by the nodes you have just copied do not exist, so you must clean up to the state the document was in before you strated copying. Errors: - Notes: May be called even if StartComponentCopy has not been called. May be called multiple times SeeAlso: BitmapListComponent::EndComponentCopy; BitmapListComponent::AbortComponentCopy; BitmapListComponent::CopyBitmapAcross ********************************************************************************************/ void BitmapListComponent::AbortComponentCopy() { } /******************************************************************************************** ********************************************************************************************/ // Remove the following code on all builds but those who want it /******************************************************************************************** ********************************************************************************************/ /******************************************************************************************** > BOOL BitmapListComponent::StartImport(BaseCamelotFilter *pFilter) Author: Neville_Humphrys (Xara Group Ltd) Created: 11/6/96 Inputs: pFilter - the BaseCamelotFilter filter that is being used to import a file. Returns: TRUE if the component was able to prepare for importing; FALSE if not (e.g. out of memory) Purpose: Inform the bitmap list document component that a Native or Web import is about to start. SeeAlso: DocComponent ********************************************************************************************/ BOOL BitmapListComponent::StartImport(BaseCamelotFilter *pFilter) { TRACEUSER( "Neville", _T("BitmapListComponent::StartImport\n") ); if (pFilter == NULL) { ERROR3("BitmapListComponent::StartExport filter is null!"); return TRUE; } // Save this in our link to the BaseCamelotFilter pCamFilter = pFilter; // Set our variable so that we warn about a possible replacement only once WarnedBefore = FALSE; // Set up and start the imported bitmap list pImportedBitmaps = new ImportedBitmaps(); if (pImportedBitmaps == NULL) return FALSE; return TRUE; } /******************************************************************************************** > BOOL BitmapListComponent::EndImport(BaseCamelotFilter *pFilter, BOOL Success) Author: Neville_Humphrys (Xara Group Ltd) Created: 11/6/96 Inputs: pFilter - the BaseCamelotFilter filter that is being used to import a file. Success - TRUE => The import was successful; FALSE => The import failed - abandon any changes. Returns: TRUE if the component was able to end the importing; FALSE if not (e.g. out of memory) Purpose: Inform the bitmap list document component that a Native or Web import has just finished. SeeAlso: DocComponent ********************************************************************************************/ BOOL BitmapListComponent::EndImport(BaseCamelotFilter *pFilter, BOOL Success) { TRACEUSER( "Neville", _T("BitmapListComponent::EndImport\n") ); if (pFilter == NULL) { ERROR3("BitmapListComponent::EndImport filter is null!"); return TRUE; } // As we have finished with it now, destroy the list of imported bitmaps if (pImportedBitmaps) { delete pImportedBitmaps; pImportedBitmaps = NULL; } // Null our link to the BaseCamelotFilter pCamFilter = NULL; // Set our variable so that we warn about a possible replacement only once WarnedBefore = FALSE; return TRUE; } /******************************************************************************************** > KernelBitmap* BitmapListComponent::GetReadBitmapReference(INT32 BitmapRef) Author: Neville_Humphrys (Xara Group Ltd) Created: 11/6/96 Inputs: BitmapRef - The bitmap reference or record number that the record handler has loaded from the record. Outputs: - Returns: pBitmap - A pointer to return the required kernel bitmap Purpose: Try and convert a bitmap reference i.e. record number into a previously imported bitmap definition which should now be an kernel bitmap in the document. SeeAlso: - ********************************************************************************************/ KernelBitmap* BitmapListComponent::GetReadBitmapReference(INT32 BitmapRef) { TRACEUSER( "Neville", _T("GetReadBitmapReference for ref %d\n"), BitmapRef ); // First check to see if the bitmap refers to any of the built in bitmaps. // These will have negative record numbers KernelBitmap* pBitmap = NULL; if (BitmapRef <= 0) { // The only one that exists at present is the default bitmap if (REF_DEFAULTBITMAP_BUILTIN) { // Its the default one so just construct a new kernel bitmap which // refers to this and return this to the caller pBitmap = KernelBitmap::MakeKernelBitmap(NULL, NULL); } else { // If we have a pFilter then ask the default warning handle to append our message if (pCamFilter) { if (!WarnedBefore) { pCamFilter->AppendWarning(_R(IDS_NATIVE_BITMAPWARNING)); WarnedBefore = TRUE; } // We have warned the user about problems so just construct a new kernel bitmap which // is the default one and return this to the caller pBitmap = KernelBitmap::MakeKernelBitmap(NULL, NULL); } else ERROR2(NULL,"BitmapListComponent::GetReadBitmapReference negative BitmapRef is unknown"); } } else { // Try and find the specified record number in our colour list pBitmap = pImportedBitmaps->GetBitmap(BitmapRef); // If not found then this is a problem as a bitmap must have been defined before its being // referenced if (pBitmap == NULL) { // If we have a pFilter then ask the default warning handle to append our message if (pCamFilter) { if (!WarnedBefore) { pCamFilter->AppendWarning(_R(IDS_NATIVE_BITMAPWARNING)); WarnedBefore = TRUE; } // We have warned the user about problems so just construct a new kernel bitmap which // is the default one and return this to the caller pBitmap = KernelBitmap::MakeKernelBitmap(NULL, NULL); } else ERROR2(NULL,"BitmapListComponent::GetReadBitmapReference BitmapRef cannot be found"); } } return pBitmap; } /******************************************************************************************** > BOOL BitmapListComponent::LoadBitmapDefinition(CXaraFileRecordHandler *pXFileRecHandler, CXaraFile * pCXFile, INT32 Tag, UINT32 Size, UINT32 RecordNumber) Author: Neville_Humphrys (Xara Group Ltd) Created: 11/6/96 Inputs: pXFileRecHandler - The CXaraFileRecordHandler that is being used to provide read functions etc. pCXFile - The CXaraFile that is being used to provide read functions etc. Tag - The tag of the record and hence the type of bitmap being imported Size - The size of this bitmap record RecordNumber - The record number for this bitmap record Returns: TRUE if the record was succesfully imported; FALSE if not (e.g. out of memory) Purpose: Try and import a bitmap definition record into the document. SeeAlso: - ********************************************************************************************/ BOOL BitmapListComponent::LoadBitmapDefinition(CXaraFileRecordHandler *pXFileRecHandler, CXaraFile * pCXFile, INT32 Tag, UINT32 Size, UINT32 RecordNumber) { ERROR2IF(pXFileRecHandler == NULL,FALSE,"BitmapListComponent::LoadBitmapDefinition NULL pXFileRecHandler"); ERROR2IF(pCXFile == NULL,FALSE,"BitmapListComponent::LoadBitmapDefinition NULL pCXFile"); ERROR2IF(pImportedBitmaps == NULL,FALSE,"BitmapListComponent::LoadBitmapDefinition NULL pImportedBitmaps"); BOOL ok = TRUE; // Get the underlying file stream class, CCFile, that we are using to load the file CCLexFile* pFile = pCXFile->GetCCFile(); ERROR2IF(pFile == NULL,FALSE,"BitmapListComponent::LoadBitmapDefinition CCFile pointer is NULL"); // Note present position in file FilePos pos = pFile->tellIn(); // Get the underlying BaseCamelotFilter, which we will use to handle the progress bar updates // and other useful things CamelotRecordHandler * pCamRecHandler = (CamelotRecordHandler *)pXFileRecHandler; BaseCamelotFilter *pFilter = pCamRecHandler->GetBaseCamelotFilter(); // We use this for file for the import, but we might need to change it // if we use a BitmapSource CCLexFile* pPseudoFile = pFile; // First get the name of the bitmap and other details stored in the record String_256 BitmapName; if (ok) ok = pCXFile->Read(BitmapName, BitmapName.MaxLength()); // Some bitmaps might have a compressed and uncompressed format // At present, this only happens for bitmaps BOOL Compressed = FALSE; // Work out which filter is required from the tag on the record UINT32 SearchFilter = 0; // Assume we won't need a BitmapSource BitmapSource* pSource = NULL; BOOL ReadPalette = FALSE; switch (Tag) { case TAG_DEFINEBITMAP_BMP: SearchFilter = FILTERID_BMP; break; case TAG_DEFINEBITMAP_GIF: SearchFilter = FILTERID_TI_GIF; break; case TAG_DEFINEBITMAP_JPEG: SearchFilter = FILTERID_IMPORT_JPEG; break; case TAG_DEFINEBITMAP_PNG: SearchFilter = FILTERID_PNG; break; case TAG_DEFINEBITMAP_BMPZIP: SearchFilter = FILTERID_BMP; Compressed = TRUE; break; case TAG_DEFINEBITMAP_JPEG8BPP: SearchFilter = FILTERID_IMPORT_JPEG; Compressed = TRUE; ReadPalette = TRUE; break; default: // Not a known tag, so fall through below and use the default bitmap // warn the user and skip the definition //ERROR1(FALSE, _R(IDS_DONT_SUPPORT_BITMAP_TYPE)); break; } // If we have a filter to search for then find it. Filter *pBmpFilter = NULL; if (SearchFilter != 0) { // Try and find the bitmap filter to use to load that bitmap in // Go get the first filter in the list pBmpFilter = Filter::GetFirst(); while ((pBmpFilter != NULL) && (pBmpFilter->FilterID != SearchFilter)) { // Try the next filter pBmpFilter = Filter::GetNext(pBmpFilter); } } // Check that the Filter existed KernelBitmap *pBitmap = NULL; if (pBmpFilter == NULL) { // We have no filter present to load it. In the case of RALPH and even in Camelot, // the best course of action will be to use a default bitmap instead. // In the case of Camelot, warn the user that this has happened. pBitmap = KernelBitmap::MakeKernelBitmap(NULL, NULL); // Code below will clean this up so that:- // - we skip the bitmap definition // - we add the record number to the loaded list so that records which access this definition // get something rather than an error. // If we have a pFilter then ask the default warning handle to append our message if (pFilter) { if (!WarnedBefore) { pFilter->AppendWarning(_R(IDS_NATIVE_BITMAPWARNING)); WarnedBefore = TRUE; } } else { // Shouldn't happen, as pFilter should never be null // But Warn the user about the problem, just in case it does happen InformWarning(_R(IDW_CANNOTLOADBITMAPDEF)); } //ERROR1(FALSE, _R(IDT_CANT_FIND_FILTER)); } else { // Load the bitmap definition in using that filter TRACEUSER( "Neville", _T("LoadBitmapDefinition Name %s RecordNumber %d\n"),(TCHAR*)BitmapName, RecordNumber); // Now use that filter to load in the bitmap //INT32 BitmapType = 0; //BitmapInfo Info; BOOL IsNew = FALSE; BaseBitmapFilter *pBitmapFilter = (BaseBitmapFilter *)pBmpFilter; UINT32 NumberOfPaletteEntries = 0; RGBTRIPLE * pPalette = NULL; if (ReadPalette) { // If we are an 8bpp JPEG then we must have saved out the palette // So load that in before anybody else gets a look in // First, read the number of entries (this is number of entries - 1) BYTE Entries = 0; if (ok) ok = pCXFile->Read(&Entries); NumberOfPaletteEntries = Entries + 1; if (ok && NumberOfPaletteEntries > 0) { pPalette = (RGBTRIPLE*)CCMalloc(NumberOfPaletteEntries * sizeof(RGBTRIPLE)); RGBTRIPLE * pPal = pPalette; // Now read the palette entries in for (UINT32 i = 0; i < NumberOfPaletteEntries; i++) { if (ok) ok = pCXFile->Read(&pPal->rgbtRed); if (ok) ok = pCXFile->Read(&pPal->rgbtGreen); if (ok) ok = pCXFile->Read(&pPal->rgbtBlue); pPal++; } } } // WEBSTER - markn 10/2/97 // New flag so that pPseudoFile only gets deleted when it should BOOL DeletePseudoFile = FALSE; // Do we need to create a BitmapSource from this import? if (pBitmapFilter->IsFormatLossy()) { // Create a new bitmap source the size of the current record minus a bit OFFSET SourceSize = Size - (pFile->tellIn() - pos); pSource = pBitmapFilter->CreateBitmapSource(SourceSize); if (pSource == NULL || !pSource->IsOK()) { ok = FALSE; } // Now create a file that can fill it if (ok) { pPseudoFile = (CCLexFile*)new CCBufferFile(pFile); if (pPseudoFile == NULL) { ok = FALSE; } else DeletePseudoFile = TRUE; // WEBSTER - markn 10/2/97 - New flag so that pPseudoFile only gets deleted when it should } // and provide the filter with something to work with if (ok) pSource->AttachToBufferFile((CCBufferFile*)pPseudoFile); } // Import that bitmap // If we have a palette then we need to convert the 24bpp image into an 8bpp image // using the supplied palette if (ok) ok = KernelBitmap::ImportBitmap(pPseudoFile, pBitmapFilter, pFilter, Compressed, pPalette, NumberOfPaletteEntries, &pBitmap, &IsNew); if (ok && IsNew) { // Set the name in it pBitmap->ActualBitmap->SetName(BitmapName); // Associate the new bitmap with its source...if there is one if (pSource != NULL) { pBitmap->SetOriginalSource(pSource, pBitmapFilter); } } else { // Throw away the source as we already have it or don't need it if (pSource != NULL) { delete pSource; } } if (pPalette != NULL) { CCFree(pPalette); pPalette = NULL; } // If we have a BitmapSource we should have had a file to use it with // Delete it if (pSource != NULL) { ERROR3IF(pPseudoFile == NULL, "pPseudoFile == NULL"); // WEBSTER - markn 10/2/97 // New flag so that pPseudoFile only gets deleted when it should if (DeletePseudoFile && pPseudoFile != NULL) { delete pPseudoFile; pPseudoFile = NULL; } } } if (!ok) { TRACEALL( _T("==============Failed to load bitmap in, try and recover situation\n") ); // Try some limited error recovery // First set the flag to true so it thinks everything went ok ok = TRUE; // If it has thrown a file exception error then we will need to reset the good flag // so file access still works ok pFile->SetGoodState(); // We should now fall through and skip to the end of this record/start of next // ready to read in the next bit of data. // REM Any errors will be set, we could inform error at this point but the user should get // a more friendly, a bitmap failed to load properly, using defaults. } // Only do this if everything went ok if (ok) { // Note the current position in the file FilePos newpos = pFile->tellIn(); TRACEUSER( "Neville", _T("newpos %d, pos %d, newpos-pos %d should = Size %d\n"),newpos,pos,newpos-pos,Size); if (newpos - pos != (INT32)Size) { // The bitmap filter has been naughty and left the file // pointer sitting somewhere different to where it should. // We need to now fix this to where it should be pFile->seekIn(pos + Size); } } // If have a genuine bitmap then add it to the loaded list // If the bitmap is null then the reference will use the default instead. if (pBitmap != NULL) pImportedBitmaps->AddBitmap(pBitmap, RecordNumber); return ok; } /******************************************************************************************** ********************************************************************************************/ /******************************************************************************************** > BOOL BitmapListComponent::StartExport(BaseCamelotFilter *pFilter) Author: Neville_Humphrys (Xara Group Ltd) Created: 11/6/96 Returns: TRUE if the component was able to prepare for exporting; FALSE if not (e.g. out of memory) Inputs: pFilter - the BaseCamelotFilter filter that is being used to export a file. Purpose: Inform the bitmap list document component that a Web or Native export is about to start. SeeAlso: DocComponent ********************************************************************************************/ BOOL BitmapListComponent::StartExport(BaseCamelotFilter *pFilter) { #ifdef DO_EXPORT TRACEUSER( "Neville", _T("BitmapListComponent::StartExport\n") ); // Mark all bitmaps as unsaved if (pFilter == NULL) { ERROR3("BitmapListComponent::StartExport filter is null!"); return TRUE; } // Set up and start the exported bitmap list pExportedBitmaps = new ExportedBitmaps(); if (pExportedBitmaps == NULL) return FALSE; #endif return TRUE; } /******************************************************************************************** > BOOL BitmapListComponent::EndExport(BaseCamelotFilter *pFilter, BOOL Success) Author: Neville_Humphrys (Xara Group Ltd) Created: 11/6/96 Inputs: pFilter - the BaseCamelotFilter filter that is being used to import a file. Success - True if everything went swimmingly, False if just a clean up is required. Purpose: Inform the bitmap list document component that a Web or Native export has just finished. Returns: TRUE if the component was able to end the importing; FALSE if not (e.g. out of memory) SeeAlso: DocComponent ********************************************************************************************/ BOOL BitmapListComponent::EndExport(BaseCamelotFilter *pFilter, BOOL Success) { #ifdef DO_EXPORT // ERROR2IF(pExportedBitmaps == NULL, FALSE, "BitmapListComponent::EndExport no pExportedBitmaps!"); // If we error about the pExportedBitmaps then we assume that the EndImport has been called. // This may not be the case if we are in clean up mode. So just handle it! TRACEUSER( "Neville", _T("BitmapListComponent::EndExport\n") ); if (pFilter == NULL) { ERROR3("BitmapListComponent::EndExport filter is null!"); return TRUE; } // Check if Web or Native, if Web do nothing // If Native and we are not just in clean up mode, Save out any unsaved bitmaps //if (!pFilter->IsWebFilter() && Success) //{ //TRACEUSER( "Neville", _T("BitmapListComponent::EndExport exporting unsaved bitmaps\n")); /* // Count the number of Bitmaps INT32 TotalBitmaps = 0; KernelBitmap* pBitmap = (KernelBitmap*) pBitmaps->GetHead(); while (pBitmap != NULL) { // Find the next one if (pBitmap->GetUsageCount() > 0) TotalBitmaps++; // Only count this bitmap if it really used pBitmap = (KernelBitmap*) pBitmaps->GetNext(pBitmap); } //} */ // As we have finished with it now, destroy the list of exported bitmaps if (pExportedBitmaps) { delete pExportedBitmaps; pExportedBitmaps = NULL; } #if 0 if(Success) SGLibOil::ExportWav(pFilter); #endif #endif return TRUE; } /******************************************************************************************** > INT32 BitmapListComponent::GetWriteBitmapReference(KernelBitmap* pBitmap, BaseCamelotFilter *pFilter) Author: Neville_Humphrys (Xara Group Ltd) Created: 11/6/96 Inputs: pBitmap - The document bitmap to save pFilter - The filter to use for saving Outputs: - Returns: The bitmap reference for the kernel bitmap ready for writing in a record. This will be zero if a problem has occurred. May return -1 if it does not need to save anything i.e if the bitmap is not in use. Purpose: Return the bitmap reference to the caller, who will then use it to write the bitmap in the record that they are preparing to save to a Web or Native file. In the process of getting the bitmap reference, the bitmap definition record for the bitmap reference will be generated and saved to the file. In the web format, the bitmap may have been reduced in resolution, colour resolution or cropped to try and reduce the size saved out. NOTE: As this does save information into the record stream, it *MUST* be called before the caller has called StartRecord() as otherwise the records will become intertwined! SeeAlso: DocComponent ********************************************************************************************/ INT32 BitmapListComponent::GetWriteBitmapReference(KernelBitmap* pBitmap, BaseCamelotFilter *pFilter) { #ifdef DO_EXPORT ERROR2IF(pBitmap == NULL,0L,"BitmapListComponent::GetWriteBitmapReference null pBitmap"); ERROR2IF(pFilter == NULL,0L,"BitmapListComponent::GetWriteBitmapReference null pFilter"); INT32 RecordNumber = 0L; // Check for a deleted bitmap if (pBitmap->HasBeenDeleted()) { ERROR2IF(pBitmap->GetParentBitmapList() == NULL, 0L, "Deleted bitmap has no parent list"); // Use the default bitmap instead pBitmap = pBitmap->GetParentBitmapList()->FindDefaultBitmap(); // There should always be a default bitmap in the list ERROR2IF(pBitmap == NULL, 0L, "Couldn't find the default bitmap"); } // Check if the bitmap is the default one // We could save this as a unique -ve reference but this implies we have the bitmap // bound into ALL exes i.e. RALPH and the viewer. Which makes them 77k bigger. Not many // people will use the default bitmap and if they do will not assume that it is assumed. // They will want and expect the document to contain the bitmap so that it is standalone. // Also, what happens if we change the default. Then we need the old and the new default // bound in! //if (pBitmap->IsDefaultBitmap()) //{ // If so then there is no point in saving out the definition, just save out // our unique identifier for this bitmap i.e. pass this back to the caller // return REF_DEFAULTBITMAP_BUILTIN; //} // Save out that bitmap definition into the file using the bitmap compression value // possibly requested by the user RecordNumber = SaveBitmapDefinition(pBitmap, pFilter); return RecordNumber; #else return 0; #endif } /******************************************************************************************** > BOOL BitmapListComponent::WriteBitmapPropertiesRecord(KernelBitmap* pBitmap, BaseCamelotFilter *pFilter, INT32 BmpRef) Author: Andy_Hills (Xara Group Ltd) Created: 31/10/00 Inputs: pBitmap - The document bitmap to save pFilter - The filter to use for saving BmpRef - The bitmap reference Outputs: - Returns: TRUE on success. Purpose: Helper function for SaveBitmapDefinition. Write out 'bitmap properties' record. This contains: * A bitmap reference (INT32). This specifies the bitmap to which the properties apply. (This will usually be the bitmap record which immediately preceded this bmp properties record.) * A single flag byte. The LSB stores the value of the 'smooth when scaled up' flag - 1 for yes, 0 for no. Other bits could be used to record other boolean bmp properties; for now these are set to 0. * 7 more bytes for future use. Some of this space should be used to store GIF animation info (which is presently not saved). The remainder of the space is reserved for possible future additions to the bmp properties dialogue. SeeAlso: SaveBitmapDefinition ********************************************************************************************/ BOOL BitmapListComponent::WriteBitmapPropertiesRecord(KernelBitmap* pBitmap, BaseCamelotFilter *pFilter, INT32 BmpRef) { BOOL ok = TRUE; // populate the record BYTE Flags = 0x00; if (pBitmap->GetInterpolation()) Flags |= 0x01; // Find out whether we need to make an XPE record or not... PORTNOTE("other","KernelBitmap::GetXPEInfo removed") #ifndef EXCLUDE_FROM_XARALX KernelBitmap* pMaster = NULL; IXMLDOMDocumentPtr pEditList = NULL; pBitmap->GetXPEInfo(pMaster, pEditList); if (pMaster!=NULL && pEditList!=NULL) { // Get master bitmap reference number (writing out the bitmap if necessary) INT32 MasterRecord = 0; MasterRecord = GetWriteBitmapReference(pMaster, pFilter); // Only write out new record style if we really have to... // (Helps forward compatibility) if (MasterRecord!=0) { // Create a new style XPE bitmap properties record CXaraFileRecord Rec(TAG_XPE_BITMAP_PROPERTIES); BSTR bstrValue; HRESULT hr; hr = pEditList->get_xml(&bstrValue); if (SUCCEEDED(hr)) { ok = Rec.Init(); if (ok) ok = Rec.WriteReference(BmpRef); // bitmap reference if (ok) ok = Rec.WriteBYTE(Flags); // flags // TODO: write GIF animation properties here // reserved bytes for( INT32 i=0; i<7; i++ ) { if (ok) ok = Rec.WriteBYTE(0); } // Now write out XPE stuff if (ok) ok = Rec.WriteReference(MasterRecord); // Master bitmap record number if (ok) ok = Rec.WriteUnicode(pBitmap->GetName()); // Oil Bitmap name if (ok) ok = Rec.WriteBSTR(bstrValue); // UNICODE xml string edits list // Write the record if (ok) ok = pFilter->Write(&Rec); return ok; } } } #endif // Fallback to the original BITMAP PROPERTIES record style // Create an old style properties record CXaraFileRecord Rec(TAG_BITMAP_PROPERTIES,TAG_BITMAP_PROPERTIES_SIZE); ok = Rec.Init(); if (ok) ok = Rec.WriteReference(BmpRef); // bitmap reference if (ok) ok = Rec.WriteBYTE(Flags); // flags // TODO: write GIF animation properties here // reserved bytes for( INT32 i=0; i<7; i++ ) { if (ok) ok = Rec.WriteBYTE(0); } // Write the record if (ok) ok = pFilter->Write(&Rec); return ok; } /******************************************************************************************** > INT32 BitmapListComponent::SaveBitmapDefinition(KernelBitmap* pBitmap, BaseCamelotFilter *pFilter) Author: Neville_Humphrys (Xara Group Ltd) Created: 12/6/96 Inputs: pBitmap - The document bitmap to save pFilter - The filter to use for saving Outputs: - Returns: The bitmap reference for the kernel bitmap ready for writing in a record. This will be zero if a problem has occurred. May return -1 if it does not need to save anything i.e if the bitmap is not in use. Purpose: This actually saves out the bitmap definition into the file and returns the bitmap reference or record number to the caller. They will then be able to use it to write the bitmap in the record that they are preparing to save to a Web or Native file. SeeAlso: DocComponent ********************************************************************************************/ INT32 BitmapListComponent::SaveBitmapDefinition(KernelBitmap* pBitmap, BaseCamelotFilter *pFilter) { #ifdef DO_EXPORT ERROR2IF(pBitmap == NULL,0L,"BitmapListComponent::GetWriteBitmapReference null pBitmap"); ERROR2IF(pFilter == NULL,0L,"BitmapListComponent::GetWriteBitmapReference null pFilter"); INT32 RecordNumber = 0L; // Check for a deleted bitmap if (pBitmap->HasBeenDeleted()) { ERROR2IF(pBitmap->GetParentBitmapList() == NULL, 0L, "Deleted bitmap has no parent list"); // Use the default bitmap instead pBitmap = pBitmap->GetParentBitmapList()->FindDefaultBitmap(); // There should always be a default bitmap in the list ERROR2IF(pBitmap == NULL, 0L, "Couldn't find the default bitmap"); } // **** // **** Saved this bitmap before? // **** // Only write this record out if we have not done so already // Check by seeing if the bitmap is already in our exported bitmap list ExportBitmap* pExportBitmap = NULL; pExportBitmap = pExportedBitmaps->GetBitmap(pBitmap); // If it is then do not save this bitmap if (pExportBitmap) { // Just return the record number as the bitmap reference to the caller return pExportBitmap->RecordNumber; } PORTNOTE("other", "Removed live effects stuff") #ifndef EXCLUDE_FROM_XARALX // Check to see whether we can save a simple placeholder, relying on the // XPE to regenerate the bitmap from master and edits when it's reloaded. if (pFilter->GetSaveXPEBitmaps() == FALSE) { KernelBitmap* pMaster = NULL; IXMLDOMDocumentPtr pEdits = NULL; pBitmap->GetXPEInfo(pMaster, pEdits); if (pMaster != NULL && pEdits != NULL) { // Yes, we have a valid set of XPE info so we can regenerate on loading UINT32 recnum = pFilter->WriteXPEBitmapPlaceHolder(pBitmap->GetName()); if (recnum!=0) { BOOL bOK = FALSE; // write out a bitmap properties record bOK = WriteBitmapPropertiesRecord(pBitmap, pFilter, recnum); if (!bOK) return 0L; // Now add this exported bitmap definition record to our exported list for later reuse pExportedBitmaps->AddBitmap(pBitmap, recnum); return recnum; } } } #endif BOOL ok = TRUE; // Find out what bitmap compression was requested by the user // Could use BMPZIP which could be deemed to mean no compression // > 100 means use PNG // 0-100 use JPEG with this quality setting // Of course, only do this if we are in web mode INT32 Compression = pFilter->GetBitmapCompression(); // Get details of the bitmap BitmapInfo Info; String_256 BitmapName; pBitmap->ActualBitmap->GetInfo(&Info); BitmapName = pBitmap->ActualBitmap->GetName(); // double Dpi = Info.PixelDepth; UINT32 Height = Info.PixelHeight; UINT32 NumberOfPaletteEntries = Info.NumPaletteEntries; // 0 for no palette UINT32 SearchFilter = 0; INT32 Tag = TAG_DEFINEBITMAP_BMP; // See if we have a BitmapSource for the bitmap we're exporting BitmapSource* pSource = NULL; BaseBitmapFilter* pDummyFilter; BOOL bUseOriginalSource = pBitmap->GetOriginalSource(&pSource, &pDummyFilter); BOOL WritePalette = FALSE; if (!bUseOriginalSource) { // We don't already have a compressed source so pick a filter UINT32 Bpp = Info.PixelDepth; // Check if the bitmap has a transparent colour or masking colour present. // If so then we may need to change our saving strategy INT32 TransparentColour = -1; if (Bpp <= 8) pBitmap->ActualBitmap->GetTransparencyIndex(&TransparentColour); switch (Bpp) { case 1: case 4: // Cannot use JPEG as only for 8,24bpp // Both GIF and PNG support transparency // So always use the PNG filter. Tag = TAG_DEFINEBITMAP_PNG; SearchFilter = FILTERID_PNG; break; case 8: // JPEG does not support transparency, so if this is set then use PNG if (TransparentColour == -1) { // If it is 8bpp and there is a no transparent colour present // then we can JPEG the bitmap or PNG it. Using Accusoft this will save // out the bitmap as a 24bpp JPEGd bitmap. // If compression is between 0 and 100 then use JPEG // otherwise use PNG if (Compression >= 0 && Compression <= 100) { // Check if greyscale or not. If greyscale then legal JPEG so save as normal // otherwise save as special 8BPP JPEG record if (pBitmap->IsGreyscale()) { Tag = TAG_DEFINEBITMAP_JPEG; SearchFilter = FILTERID_EXPORT_JPEG; } else { Tag = TAG_DEFINEBITMAP_JPEG8BPP; SearchFilter = FILTERID_EXPORT_JPEG; WritePalette = TRUE; } } else { Tag = TAG_DEFINEBITMAP_PNG; SearchFilter = FILTERID_PNG; } } else { // If it is 8bpp and there is a transparent colour present // then we must use PNG to save out this colour Tag = TAG_DEFINEBITMAP_PNG; SearchFilter = FILTERID_PNG; } break; case 24: // If compression is between 0 and 100 then use JPEG // otherwise use PNG if (Compression >= 0 && Compression <= 100) { Tag = TAG_DEFINEBITMAP_JPEG; SearchFilter = FILTERID_EXPORT_JPEG; } else { Tag = TAG_DEFINEBITMAP_PNG; SearchFilter = FILTERID_PNG; } break; case 32: // No choice but to use PNG or BMP in all cases as these are the only // formats that support 32bpp. Tag = TAG_DEFINEBITMAP_PNG; SearchFilter = FILTERID_PNG; break; default: ERROR2(0,"BitmapListComponent::SaveBitmapDefinition bad pixel depth"); } } else { // We have a BitmapSource... // but we don't have the right filter...get rid of this hack! // FilterManager* pFilterManager = Camelot->GetFilterManager(); // pFilter = pFilterManager->FindComplementaryFilter(pDummyFilter); Tag = TAG_DEFINEBITMAP_JPEG; SearchFilter = FILTERID_EXPORT_JPEG; // Now check if we have done a 24bpp to 8bpp conversion job on this // The way we can tell this is if the bitmap is 8bpp and not greyscale UINT32 Bpp = Info.PixelDepth; if (Bpp == 8 && !pBitmap->IsGreyscale()) { Tag = TAG_DEFINEBITMAP_JPEG8BPP; WritePalette = TRUE; } } // Try and find the bitmap filter to use to load that bitmap in // Go get the first filter in the list Filter *pBmpFilter = Filter::GetFirst(); while ((pBmpFilter != NULL) && (pBmpFilter->FilterID != SearchFilter)) { // Try the next filter pBmpFilter = Filter::GetNext(pBmpFilter); } // Check that the Filter existed ERROR2IF(pBmpFilter == NULL,0,"BitmapListComponent::SaveBitmapDefinition can't find export filter!"); // Start writing our record data out to file UINT32 Size = 0; // If there is a string name, then add it to this size // REMEMBER: We save out unicode strings and so we need to double the length of the returned string length // but only if we are not being compiled as Unicode Size += (BitmapName.Length() + 1) * SIZEOF_XAR_UTF16; if (WritePalette) { // If we are an 8bpp JPEG then we must save out the palette so that on loading we can // convert the 24bpp JPEG back into 8bpp using this palette Size += 1; // For the number of palette entries Size += NumberOfPaletteEntries * sizeof(RGBTRIPLE); } RecordNumber = pFilter->StartStreamedRecord(Tag, Size); //RecordNumber = pFilter->StartRecord(Tag, Size); // If we had a problem starting the record up then exit now if (RecordNumber <= 0) return RecordNumber; // Write out the name to disc ok = pFilter->Write(BitmapName); // Possibly write palette information into the record if (WritePalette) { TRACEUSER( "Neville", _T("8bpp JPEG write palette size %d to file\n"), NumberOfPaletteEntries ); // If we are an 8bpp JPEG then we must save out the palette so that on loading we can // convert the 24bpp JPEG back into 8bpp using this palette // Saves number of palette entries followed by the palette in RGB triples pBitmap->WritePalette(pFilter); } // Write out the bitmap data to file // First get the CCFile that we are using for writing out the data CCLexFile* pFile = pFilter->GetCCFile(); // The WriteBitmapToFile function is only available in bitmap filters so we need // to convert our pointer to that type of filter BaseBitmapFilter *pBitmapFilter = (BaseBitmapFilter *)pBmpFilter; // On the first pass this will be null as we are trying to work out the export size // so that we get the progress bar correct. if (pFile) { // Ensure all current data is flushed to file otherwise some filters // may screw up the file. pFile->flush(); // Check to see if we haven't already got it compressed if (bUseOriginalSource) { // We have,so write out the source & don't degrade it ERROR2IF(pSource == NULL, 0L, "pSource == NULL"); pFilter->WriteBitmapSource(*pSource, Height); } else { // We are on the real pass so go and export that bitmap data to file pBitmapFilter->WriteBitmapToFile(pBitmap, pFilter, pFile, Compression); } } else { if (WritePalette) { // If we are on the fake pass and saving the palette then include the number of // palette entries in the count. pFilter->IncProgressBarCount(NumberOfPaletteEntries); } // We are on the fake pass so add the height of the bitmap onto the progress bar count // as this is what we will use the update the progress bar pFilter->IncProgressBarCount(Height); } // Ask for the record to be ended and hence items like the size in the record header // to be cleaned up and hence made correct if (ok) ok = pFilter->EndStreamedRecord(); // write out a bitmap properties record if (ok) ok = WriteBitmapPropertiesRecord(pBitmap, pFilter, RecordNumber); // If we have had a problem at any of the stages then return that to the caller if (!ok) return 0L; // Now add this exported bitmap definition record to our exported list for later reuse if (ok) ok = pExportedBitmaps->AddBitmap(pBitmap, RecordNumber); return RecordNumber; #else return 0; #endif }