giffiltr.cpp

Go to the documentation of this file.
00001 // $Id: giffiltr.cpp 1461 2006-07-18 09:50:40Z luke $
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 GIF import/export filter 
00100 
00101 
00102 #include "camtypes.h"
00103 #include "giffiltr.h"
00104 //#include "andy.h"
00105 //#include "oilfltrs.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00106 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00107 //#include "dibutil.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00108 #include "grndbmp.h"
00109 #include "nodebmp.h"
00110 #include "bmpfiltr.h"
00111 #include "progress.h"
00112 #include "oilbitmap.h"  // Windows specific bitmap information
00113 //#include "docview.h"  // DocView - in camtypes.h [AUTOMATICALLY REMOVED]
00114 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00115 
00116 //#include "richard2.h" // resource strings _R(IDS_GIFFILTR_FAILED_MASK)
00117 //#include "accures.h"  // Accusoft filter ids and messages 
00118 //#include "bmpres.h"       // general bitmap filter based resources (_R(IDE_TIGIFFILTER_MASKFAILED)/MASK)
00119 //#include "will3.h"        // for _R(IDS_GENOPTPALMSGID)
00120 
00121 #include "maskfilt.h"   // MaskedFilter class
00122 #include "bmpsdlg.h"
00123 #include "frameops.h"   // GIFAnimationExportParam
00124 //#include "spread.h"       // Pasteboard rect - in camtypes.h [AUTOMATICALLY REMOVED]
00125 #include "bmapprev.h"   // tab preview dialog
00126 #include "palman.h"     // MakePaletteBrowserCompatible
00127 #include "sprdmsg.h"    // SpreadMsg::ANIMATIONPROPERTIESCHANGED
00128 #include "impexpop.h"
00129 
00130 #include "exphint.h"
00131 
00132 #include "camdoc.h"
00133 #include "menuops.h"
00134 
00135 //#include "outptdib.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00136 //#include "cxfrec.h"       // for CXaraFileRecord - in camtypes.h [AUTOMATICALLY REMOVED]
00137 
00138 #include "mrhbits.h"    //  For CBMPBits::RenderSelectionToBMP
00139 #include "selall.h"     //  For OPTOKEN_EDITSELECTALL
00140 #include "bmpprefs.h"
00141 //#include "animparams.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00142 #include "tmplmngr.h"
00143 
00144 DECLARE_SOURCE("$Revision: 1461 $");
00145 
00146 CC_IMPLEMENT_DYNAMIC(TI_GIFFilter, MaskedFilter)
00147 CC_IMPLEMENT_MEMDUMP(GIFImportOptions, BitmapImportOptions)
00148 CC_IMPLEMENT_DYNCREATE(GIFExportOptions, MaskedFilterExportOptions)
00149 
00150 CC_IMPLEMENT_DYNCREATE(AnimatedGIFImage, ListItem)
00151 
00152 #define new CAM_DEBUG_NEW
00153 
00154 static UINT32 g_DefaultGIFType = 0;
00155 
00156 OutputGIF   TI_GIFFilter::DestGIF;
00157 FilterType  TI_GIFFilter::s_FilterType = GIF;   // Type of filter in use (TI_GIF .. TI_GIF_TRANSINTER)
00158 
00159 CENTISECONDS        GIFExportOptions::g_AnimationDelay          = 10;           // Delay in CentiSeconds
00160 GIFDisposalMethod   GIFExportOptions::g_AnimationRestoreType    = GDM_LEAVE;    // How to restore after each frame
00161 UINT32              GIFExportOptions::g_AnimationLoopCount      = 1;            // Number of loops
00162 KernelBitmap**      GIFExportOptions::m_pBitmapList             = NULL;
00163 UINT32              GIFExportOptions::m_ListSize                = 0;
00164 
00165 /********************************************************************************************
00166 
00167 >   static BOOL GIFExportOptions::Declare()
00168 
00169     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com> (from Peter)
00170     Created:    29/10/96
00171     Returns:    TRUE if successfully declared preferences
00172                 FALSE otherwise
00173     Purpose:    To declare preferences associated with these export options
00174 
00175 ********************************************************************************************/
00176 BOOL GIFExportOptions::Declare()
00177 {
00178     if (Camelot.DeclareSection(_T("Filters"), 10))
00179     {
00180         Camelot.DeclarePref( NULL, _T("ExportGIFtype"), &g_DefaultGIFType, 0, 3 );
00181         Camelot.DeclarePref( NULL, _T("AnimationDelay"), &g_AnimationDelay, 0, 65535 );
00182         Camelot.DeclarePref( NULL, _T("AnimationRestoreType"), (INT32*)&g_AnimationRestoreType, 0, 3 );
00183         Camelot.DeclarePref( NULL, _T("AnimationLoopCount"), &g_AnimationLoopCount, 0, 65535 );
00184     }
00185 
00186     // All ok
00187     return TRUE;
00188 }
00189 
00190 
00191 
00192 /********************************************************************************************
00193 >   GIFExportOptions::GIFExportOptions()
00194 
00195     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
00196     Created:    29/10/96
00197     Purpose:    Default constructor for a GIFExportOptions object to provide GIF export
00198                 options
00199 ********************************************************************************************/
00200 
00201 GIFExportOptions::GIFExportOptions() :
00202     DelayIndex(0),
00203     RestoreIndex(0),
00204     m_GlobalPalette(TRUE),
00205     m_LeftOffset(0),
00206     m_TopOffset(0),
00207     m_AnimDelay(g_AnimationDelay),
00208     m_AnimDispose((GIFDisposalMethod) g_AnimationRestoreType),
00209     m_AnimLoop(g_AnimationLoopCount),
00210     m_AnimSize(0, 0),
00211     DelayValueIsDefault(FALSE)
00212 {
00213     g_AnimationLoopCount = 1;
00214 }
00215 
00216 
00217 
00218 /********************************************************************************************
00219 >   GIFExportOptions::GIFExportOptions(const FilterType FilterID, const StringBase* pFilterName)
00220 
00221     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
00222     Created:    29/10/96
00223     Purpose:    Constructor for a GIFExportOptions object to provide GIF export
00224                 options
00225 ********************************************************************************************/
00226 
00227 GIFExportOptions::GIFExportOptions(const FilterType FilterID, const StringBase* pFilterName)
00228   : MaskedFilterExportOptions(_R(IDD_EXPORTBMPOPTS), FilterID, pFilterName),
00229     DelayIndex(0),
00230     RestoreIndex(0),
00231     m_GlobalPalette(TRUE),
00232     m_LeftOffset(0),
00233     m_TopOffset(0),
00234     m_AnimDelay(g_AnimationDelay),
00235     m_AnimDispose((GIFDisposalMethod) g_AnimationRestoreType),
00236     m_AnimLoop(g_AnimationLoopCount),
00237     m_AnimSize(0, 0),
00238     DelayValueIsDefault(FALSE)
00239 {
00240     g_AnimationLoopCount = 1;
00241 }
00242 
00243 
00244 
00245 /********************************************************************************************
00246 
00247 >   virtual BOOL GIFExportOptions::CopyFrom(BitmapExportOptions *pSource) 
00248 
00249     Author:     Stefan_Stoykov (Xara Group Ltd) <camelotdev@xara.com>
00250     Created:    19/05/97
00251     Inputs:     pSource - the other BitmapExportOptions object to copy the data from
00252     Purpose:    Sets the contents of this object from the passed object
00253     See Also:   BitmapExportOptions::MakeCopy()
00254 
00255 ********************************************************************************************/
00256 BOOL GIFExportOptions::CopyFrom(BitmapExportOptions *pSource) 
00257 {
00258     // copy the base class first
00259     if (!MaskedFilterExportOptions::CopyFrom(pSource))
00260         return FALSE;
00261 
00262     // must be the same class, otherwise the base class  function above returns FALSE
00263     GIFExportOptions *pOther = (GIFExportOptions *)pSource;
00264 
00265     m_AnimDelay         = pOther->m_AnimDelay;
00266     m_AnimDispose       = pOther->m_AnimDispose;
00267     m_AnimLoop          = pOther->m_AnimLoop;
00268     DelayValueIsDefault = pOther->DelayValueIsDefault;
00269     DelayIndex          = pOther->DelayIndex;
00270     RestoreIndex        = pOther->RestoreIndex;
00271     m_GlobalPalette     = pOther->m_GlobalPalette;
00272     m_LeftOffset        = pOther->m_LeftOffset;
00273     m_TopOffset         = pOther->m_TopOffset;
00274     m_AnimSize          = pOther->m_AnimSize;
00275 
00276     return TRUE;
00277 };
00278 
00279 
00280 BOOL GIFExportOptions::FileTypeChangeCopyFrom(BitmapExportOptions *pOther)
00281 {
00282     if( !MaskedFilterExportOptions::FileTypeChangeCopyFrom(pOther) )
00283         return FALSE;
00284 
00285     //  Since we are not copying from another GIFOptions-based object, then the variables
00286     //  in this object must be assigned some default values.
00287     m_AnimDelay             = g_AnimationDelay;
00288     m_AnimDispose           = (GIFDisposalMethod)g_AnimationRestoreType;
00289     m_AnimLoop              = g_AnimationLoopCount;
00290 
00291     g_AnimationLoopCount    = 1;
00292     DelayValueIsDefault     = FALSE;
00293     DelayIndex              = 0;
00294     RestoreIndex            = 0;
00295 
00296     m_GlobalPalette         = TRUE;
00297     m_LeftOffset            = 0;
00298     m_TopOffset             = 0;
00299 
00300     // Graeme (14-9-00) - Limit the colour depth to be no more than 8bpp. Otherwise we get
00301     // problems with changing file types in the export dialogue.
00302     if ( GetDepth () > 8 )
00303     {
00304         SetDepth ( 8 );
00305     }
00306 
00307     return TRUE;
00308 }
00309 
00310 
00311 /********************************************************************************************
00312 
00313 >   virtual BOOL GIFExportOptions::Equal(BitmapExportOptions *pSource) 
00314 
00315     Author:     Stefan_Stoykov (Xara Group Ltd) <camelotdev@xara.com>
00316     Created:    19/05/97
00317     Inputs:     pSource - the other BitmapExportOptions object to copy the data from
00318     Purpose:    Compares the contents of this and pOther objects
00319     Returns:    TRUE, if objects are equal, FALSE otherwise
00320     See Also:   BitmapExportOptions::MakeCopy()
00321 
00322 ********************************************************************************************/
00323 /*
00324 BOOL GIFExportOptions::Equal(BitmapExportOptions *pSource) 
00325 {
00326     BOOL ok = TRUE;
00327 
00328     // compare the base classes first
00329     ok = MaskedFilterExportOptions::Equal(pSource);
00330 
00331     // must be the same class, otherwise the base class  function above returns FALSE
00332     GIFExportOptions *pOther = (GIFExportOptions *)pSource;
00333 
00334     if (ok) ok = (m_AnimDelay   == pOther->m_AnimDelay);
00335     if (ok) ok = (m_AnimDispose == pOther->m_AnimDispose);
00336     if (ok) ok = (m_AnimLoop== pOther->m_AnimLoop);
00337     if (ok) ok = (g_AnimationLoopCount  == pOther->g_AnimationLoopCount);
00338     if (ok) ok = (DelayValueIsDefault   == pOther->DelayValueIsDefault);
00339     if (ok) ok = (DelayIndex== pOther->DelayIndex);
00340     if (ok) ok = (RestoreIndex  == pOther->RestoreIndex);
00341     return ok;
00342 };
00343 */
00344 
00345 /********************************************************************************************
00346 
00347 >   virtual BOOL GIFExportOptions::RetrieveDefaults()
00348 
00349     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
00350     Created:    29/10/96
00351     Purpose:    See BitmapExportOptions for interface details
00352     Notes:      Gets GIF specific preferences
00353 
00354 ********************************************************************************************/
00355 BOOL GIFExportOptions::RetrieveDefaults()
00356 {
00357     if (!MaskedFilterExportOptions::RetrieveDefaults())
00358     {
00359         return FALSE;
00360     }
00361 
00362     ERROR2IF(g_AnimationRestoreType != GDM_NONE && g_AnimationRestoreType != GDM_LEAVE &&
00363             g_AnimationRestoreType != GDM_BACKTOBACK && g_AnimationRestoreType != GDM_PREVIOUS,
00364             FALSE, "Invalid g_AnimationRestoreType");
00365 
00366     // Ensure that the depth is no more than 8 bits.
00367     if ( GetDepth () > 8 )
00368     {
00369         this->SetDepth ( 8 );
00370     }
00371 
00372     m_AnimDelay     = g_AnimationDelay;
00373     m_AnimDispose   = g_AnimationRestoreType;
00374     m_AnimLoop      = g_AnimationLoopCount;
00375 
00376 //  SetMakeTransparent((g_DefaultGIFType >> 1) & 1);
00377     SetMakeInterlaced(g_DefaultGIFType & 1);
00378 
00379     return TRUE;
00380 }
00381 
00382 
00383 /********************************************************************************************
00384 
00385 >   virtual BOOL GIFExportOptions::SetAsDefaults() const
00386 
00387     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
00388     Created:    29/10/96
00389     Purpose:    Provides additional implementation to set GIF specific info as defaults
00390     See Also:   BitmapExportOptions::SetAsDefaults()
00391 
00392 ********************************************************************************************/
00393 BOOL GIFExportOptions::SetAsDefaults() const
00394 {
00395     if (!MaskedFilterExportOptions::SetAsDefaults())
00396     {
00397         return FALSE;
00398     }
00399 
00400     g_AnimationDelay        = m_AnimDelay;
00401     
00402     g_AnimationRestoreType  = m_AnimDispose;
00403     g_AnimationLoopCount    = m_AnimLoop;
00404 
00405     g_DefaultGIFType = WantTransparent() ? 2 : 0;
00406     g_DefaultGIFType |= WantInterlaced() ? 1 : 0;
00407 
00408     return TRUE;
00409 }
00410 
00411 
00412 
00413 /********************************************************************************************
00414 >   virtual BOOL GIFExportOptions::Write(CXaraFileRecord* pRec)
00415 
00416     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00417     Created:    21/2/00
00418     Inputs:     pRec    ---     record to write
00419     Returns:    TRUE if successful.
00420     Purpose:    Writes this object to the given record.
00421     SeeAlso:    GIFExportOptions::Read
00422 ********************************************************************************************/
00423 
00424 BOOL GIFExportOptions::Write(CXaraFileRecord* pRec)
00425 {
00426     return MaskedFilterExportOptions::Write(pRec) &&
00427            pRec->WriteUINT32(DelayIndex) &&
00428            pRec->WriteUINT32(RestoreIndex) &&
00429            pRec->WriteBYTE((BYTE) !!m_GlobalPalette) &&
00430            pRec->WriteUINT32(m_LeftOffset) &&
00431            pRec->WriteUINT32(m_TopOffset) &&
00432            pRec->WriteUINT32((UINT32) m_AnimDelay) &&
00433            pRec->WriteINT16((INT16) m_AnimDispose) &&
00434            pRec->WriteUINT32(m_AnimLoop) &&
00435            pRec->WriteCoord((const DocCoord&) m_AnimSize) &&
00436            pRec->WriteBYTE((BYTE) !!DelayValueIsDefault);
00437 }
00438 
00439 
00440 
00441 /********************************************************************************************
00442 >   virtual BOOL GIFExportOptions::Read(CXaraFileRecord* pRec)
00443 
00444     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00445     Created:    21/2/00
00446     Inputs:     pRec    ---     record to read
00447     Returns:    TRUE if successful.
00448     Purpose:    Reads this object from the given record.
00449     SeeAlso:    GIFExportOptions::Write
00450 ********************************************************************************************/
00451 
00452 BOOL GIFExportOptions::Read(CXaraFileRecord* pRec)
00453 {
00454     m_GlobalPalette = DelayValueIsDefault = FALSE;
00455     return MaskedFilterExportOptions::Read(pRec) &&
00456            pRec->ReadUINT32((UINT32*) &DelayIndex) &&
00457            pRec->ReadUINT32((UINT32*) &RestoreIndex) &&
00458            pRec->ReadBYTE((BYTE*) &m_GlobalPalette) &&
00459            pRec->ReadUINT32((UINT32*) &m_LeftOffset) &&
00460            pRec->ReadUINT32((UINT32*) &m_TopOffset) &&
00461            pRec->ReadUINT32((UINT32*) &m_AnimDelay) &&
00462            pRec->ReadINT16((INT16*) &m_AnimDispose) &&
00463            pRec->ReadUINT32((UINT32*) &m_AnimLoop) &&
00464            pRec->ReadCoord((DocCoord*) &m_AnimSize) &&
00465            pRec->ReadBYTE((BYTE*) &DelayValueIsDefault);
00466 }
00467 
00468 
00469 
00470 /********************************************************************************************
00471 
00472 >   CENTISECONDS GIFExportOptions::GetAnimationDelay() const
00473 
00474     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
00475     Created:    29/10/96
00476     Returns:    The delay desired for animated GIFs
00477     Purpose:    Support function to obtain export options
00478 
00479 ********************************************************************************************/
00480 CENTISECONDS GIFExportOptions::GetAnimationDelay() 
00481 {
00482     //  return m_AnimDelay;
00483     UINT32 Delay = m_pBitmapList[DelayIndex]->GetDelay();
00484     DelayIndex++;
00485     return Delay;
00486 }
00487 
00488 
00489 /********************************************************************************************
00490 
00491 >   BOOL GIFExportOptions::SetAnimationDelay(CENTISECONDS Delay)
00492 
00493     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
00494     Created:    29/10/96
00495     Inputs:     Delay : The desired delay to be set in the animated GIF
00496     Returns:    TRUE if set successfully
00497                 FALSE otherwise
00498     Purpose:    Support function to set up information for the ensuing export
00499     See Also:   GetAnimationDelay()
00500 
00501 ********************************************************************************************/
00502 BOOL GIFExportOptions::SetAnimationDelay(CENTISECONDS Delay)
00503 {
00504     m_AnimDelay = Delay;
00505     return TRUE;
00506 }
00507 
00508 
00509 /********************************************************************************************
00510 
00511 >   GIFDisposalMethod GIFExportOptions::GetAnimationRestore() const
00512 
00513     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
00514     Created:    29/10/96
00515     Returns:    The disposal method to be used in animated GIFs
00516     Purpose:    Support function to obtain export options
00517 
00518 ********************************************************************************************/
00519 GIFDisposalMethod GIFExportOptions::GetAnimationRestore()
00520 {
00521     // return m_AnimDispose;
00522     GIFDisposalMethod Restore = m_pBitmapList[RestoreIndex]->GetActualBitmap()->GetAnimationRestoreType();
00523     RestoreIndex++;
00524     return Restore;
00525 }
00526 
00527 
00528 /********************************************************************************************
00529 
00530 >   BOOL GIFExportOptions::SetAnimationRestore(const GIFDisposalMethod& DisposalMethod)
00531 
00532     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
00533     Created:    29/10/96
00534     Inputs:     DisposalMethod : The desired DisposalMethod to be set in the animated GIF
00535     Returns:    TRUE if set successfully
00536                 FALSE otherwise
00537     Purpose:    Support function to set up information for the ensuing export
00538     See Also:   GetAnimationRestore(), enum GIFDisposalMethod
00539 
00540 ********************************************************************************************/
00541 BOOL GIFExportOptions::SetAnimationRestore(const GIFDisposalMethod& DisposalMethod)
00542 {
00543     m_AnimDispose = DisposalMethod;
00544     return TRUE;
00545 }
00546 
00547 
00548 /********************************************************************************************
00549 
00550 >   UINT32 GIFExportOptions::GetAnimationLoopCount() const
00551 
00552     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
00553     Created:    29/10/96
00554     Returns:    How loopy our animated GIF will be
00555     Purpose:    Support function to obtain export options
00556     See Also:   SetAnimationLoopCount()
00557 
00558 ********************************************************************************************/
00559 UINT32 GIFExportOptions::GetAnimationLoopCount() const
00560 {
00561     return m_AnimLoop;
00562 }
00563 
00564 
00565 /********************************************************************************************
00566 
00567 >   BOOL GIFExportOptions::SetAnimationLoopCount(UINT32 LoopCount)
00568 
00569     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
00570     Created:    29/10/96
00571     Inputs:     LoopCount : For Animated GIFs: 0 = Repeat forever, 1 = One shot animation.
00572                 n = Plays animation n times.
00573     Returns:    TRUE if set successfully
00574                 FALSE otherwise
00575     Purpose:    Support function to set up information for the ensuing export
00576     See Also:   GetAnimationLoopCount()
00577 
00578 ********************************************************************************************/
00579 BOOL GIFExportOptions::SetAnimationLoopCount(UINT32 LoopCount, BOOL Value)
00580 {
00581     if(Value)
00582     {
00583         m_AnimLoop = ZERO;
00584         return TRUE;
00585     }
00586     else
00587     {
00588         m_AnimLoop = LoopCount;
00589         return TRUE;
00590     }
00591 }
00592 
00593 
00594 
00595 
00596 
00597 /********************************************************************************************
00598 
00599     Preference:     ExportGIFtype
00600     Section:        Filters
00601     Range:          0 to 3
00602     Purpose:        Allows a default GIF type to be remembered for the next export GIF
00603                     operation.
00604     SeeAlso:        -
00605 
00606 ********************************************************************************************/
00607 
00608 
00609 /********************************************************************************************
00610 
00611 >   TI_GIFFilter::TI_GIFFilter()
00612 
00613     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00614     Created:    24/4/95
00615     Purpose:    Constructor for an TI_GIFFilter object.  The object should be initialised
00616                 before use.
00617     SeeAlso:    TI_GIFFilter::Init
00618 
00619 ********************************************************************************************/
00620 
00621 TI_GIFFilter::TI_GIFFilter() : MaskedFilter()
00622 {
00623     ImportMsgID = _R(IDN_IMPORTMSG_GIF);
00624     Flags.CanImport = TRUE;
00625 #ifndef STANDALONE
00626     Flags.CanExport = TRUE;
00627     Flags.CanExportMultipleImages = TRUE;
00628 #else
00629     Flags.CanExport = FALSE;
00630     Flags.CanExportMultipleImages = FALSE;
00631 #endif
00632     FilterID = FILTERID_TI_GIF;
00633 
00634     ExportMsgID = _R(IDN_EXPORTMSG_GIF);            // "Preparing GIF file..."
00635 
00636     ExportingMsgID = _R(IDN_EXPORTINGMSG_GIF);      // "Exporting GIF file..."
00637 
00638     // Special Mask prepartion stage ID
00639     Export2ndStageMsgID = _R(IDN_MASKINGMSG_GIF);   // "Preparing mask for GIF file..."
00640 
00641     ExportRegion = NULL;
00642 
00643     // Initalise flags
00644     m_DoingAnimation = FALSE;
00645     m_AnimationFrame = 0;
00646     m_LeftOffset = 0;
00647     m_TopOffset = 0;
00648 
00649     m_PreviousMethod = GDM_BACKTOBACK;
00650 }
00651 
00652 /********************************************************************************************
00653 
00654 >   BOOL TI_GIFFilter::Init()
00655 
00656     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00657     Created:    24/4/95
00658     Returns:    TRUE if the filter was initialised ok, FALSE otherwise.
00659     Purpose:    Initialise an TI_GIFFilter object.
00660     Errors:     Will fail if not enough memory to initialise.
00661     SeeAlso:    EPSStack
00662 
00663 ********************************************************************************************/
00664 
00665 BOOL TI_GIFFilter::Init()
00666 {
00667     // Get the OILFilter object
00668     pOILFilter = new GIFOILFilter(this);
00669     if (pOILFilter==NULL)
00670         return FALSE;
00671 
00672     // Load the description strings
00673     FilterName.Load(_R(IDN_FILTERNAME_GIF));
00674     FilterInfo.Load(_R(IDN_GIF_FILTERINFO));
00675 
00676     if (!GIFExportOptions::Declare())
00677     {
00678         return FALSE;
00679     }
00680 
00681     // All ok
00682     return TRUE;
00683 }
00684 
00685 
00686 /********************************************************************************************
00687 
00688 >   virtual BitmapImportOptions* TI_GIFFilter::CreateImportOptions() const
00689 
00690     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
00691     Created:    29/10/96
00692     Purpose:    Overrides base class to provide GIF specific options
00693 
00694 ********************************************************************************************/
00695 BitmapImportOptions* TI_GIFFilter::CreateImportOptions() const
00696 {
00697     GIFImportOptions* pOptions = new GIFImportOptions;
00698     return (BitmapImportOptions*)pOptions;
00699 }
00700 
00701 
00702 
00703 /********************************************************************************************
00704 
00705 >   virtual BOOL TI_GIFFilter::BOOL ReadFromFile(OILBitmap* pOilBitmap,
00706                                                  BaseCamelotFilter* pFilter,
00707                                                  CCLexFile* pFile, BOOL IsCompressed);
00708 
00709 
00710     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00711     Created:    20/6/96
00712     Inputs:     pOilBitmap  pointer to the oil bitmap data to be filled in
00713                 pFilter         - the BaseCamelotFilter which provides functions like progress update
00714                                   (not used at the moment 20/01/97)
00715                 pFile           - the CCFile class to use to read the data from
00716                 IsCompressed    - Flag to say the bitmap is compressed or not.  
00717     Outputs:    Will have filled in BMInfo  pointer to the bitmap header to fill in
00718                                     BMBytes pointer to the bitmap data to fill in
00719     Purpose:    Actually does the process of reading a bitmap from a file.
00720                 Inherited classes override this to read in different file formats.
00721                 It is used by the web/native filters to pull out a bitmap definition from
00722                 inside a bitmap definition record.
00723                 It is also used for extracting previews.
00724                 IsCompressed is only used for BMP/BMPZIP type bitmaps at present.
00725                 Assumes:
00726                     pFile has already been opened up for reading
00727                     pFilter has been set up for reading the data e.g. progress bar 
00728     Returns:    TRUE if worked, FALSE if failed.
00729 
00730 ********************************************************************************************/
00731 
00732 BOOL TI_GIFFilter::ReadFromFile( OILBitmap* pOilBitmap, BaseCamelotFilter* pFilter,
00733                                  CCLexFile* pFile, BOOL IsCompressed)
00734 {
00735     ERROR2IF(pOilBitmap == NULL,FALSE,"TI_GIFFilter::ReadFromFile null OilBitmap pointer");
00736     // no pFilter means we don't get a progress WEBSTER-Martin-20/01/97
00737     // as we are calling this from BaseFileDialog::GetPreviewBitmapFromFile we don't have
00738     // a BaseCamelotFilter. However GIFUtil::ReadImage expects a 100% progress bar.
00739     // ERROR2IF(pFilter == NULL,FALSE,"TI_GIFFilter::ReadFromFile null pFilter pointer");
00740     ERROR2IF(pFile == NULL,FALSE,"TI_GIFFilter::ReadFromFile null pFile pointer");
00741 
00742     if (!pFilter)
00743         BeginSlowJob(-1);   // GIFUtil::ReadImage expects a progress bar.
00744 
00745     // Try to import bitmap as usual binary BMP file.
00746     CWxBitmap* pWBitmap = (CWxBitmap*) pOilBitmap;
00747     
00748     LPBITMAPINFO *pInfo = &(pWBitmap->BMInfo);
00749     LPBYTE *pBytes = &(pWBitmap->BMBytes);
00750 
00751     // Set a default transparent colour
00752     INT32 TransColour = -1;
00753     SetTransColour(TransColour);
00754 
00755     // Blank the offsets just in case
00756     m_LeftOffset = 0;
00757     m_TopOffset = 0;
00758 
00759     // Read from file, no header and using pFilter for progress bar updates
00760     // 20/01/97 In fact pFilter is not used so NULL ptr ok
00761     if (!GIFUtil::ReadFromFile(pFile, pInfo, pBytes, &TransColour, NULL, pFilter))
00762     {
00763         if (!pFilter)
00764             EndSlowJob();
00765         return FALSE;
00766     }
00767 
00768     SetTransColour(TransColour);
00769     UINT32 Bpp = pWBitmap->GetBPP();
00770     if (TransColour != -1 && Bpp <= 8)
00771         pOilBitmap->SetTransparencyIndex(TransColour);
00772 
00773     SetLastBitmap();        // can only import one bitmap at the moment
00774 
00775     if (!pFilter)
00776         EndSlowJob();
00777 
00778     // Everything went ok and we imported the bitmap ok
00779     return TRUE;
00780 }
00781 
00782 /********************************************************************************************
00783 
00784 >   BOOL TI_GIFFilter::ReadFromFile(OILBitmap* pOilBitmap)
00785 
00786     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00787     Created:    18/8/95
00788     Inputs:     pOilBitmap  pointer to the oil bitmap data to be filled in
00789     Outputs:    Will have filled in BMInfo  pointer to the bitmap header to fill in
00790                                     BMBytes pointer to the bitmap data to fill in
00791     Purpose:    Actually does the process of reading a bitmap from a file.
00792                 Inherited classes override this to read in different file formats.
00793                 
00794     Returns:    TRUE if worked, FALSE if failed.
00795 
00796 ********************************************************************************************/
00797 
00798 BOOL TI_GIFFilter::ReadFromFile(OILBitmap* pOilBitmap)
00799 {
00800     ERROR2IF(pOilBitmap == NULL,FALSE,"TI_GIFFilter::ReadFromFile null OilBitmap pointer");
00801     
00802     // Try to import the bitmap as a GIF file.
00803         
00804     CCLexFile* pImportFile = GetImportFile();
00805     ERROR2IF(pImportFile==NULL,FALSE,"TI_GIFFilter::ReadFromFile - No import file");
00806 
00807     UINT32 ImportMsgId = GetImportMsgID();      
00808     String_64 ProgressString(ImportMsgId);
00809     ProgressString = GetImportProgressString(pImportFile, ImportMsgId);
00810 
00811     // Set a default transparent colour
00812     INT32 TransColour = -1;
00813     SetTransColour(TransColour);
00814     INT32 nBitmapToRead = GetBitmapNumber();
00815 
00816     CWxBitmap* pWBitmap = (CWxBitmap*)pOilBitmap;
00817     
00818     LPBITMAPINFO *pInfo = &(pWBitmap->BMInfo);
00819     LPBYTE *pBytes = &(pWBitmap->BMBytes);
00820     // Receives the Bitmap delay/Restore value from the Import.
00821     UINT32 Delay=0;
00822     GIFDisposalMethod Restore = GDM_LEAVE;
00823 
00824     // Blank the offsets just in case
00825     m_LeftOffset = 0;
00826     m_TopOffset = 0;
00827 
00828     // The GIF filter liked it very much and so use it, showing progress bar
00829     if (GIFUtil::ReadFromFile(pImportFile, pInfo, pBytes, &TransColour,nBitmapToRead, &ProgressString, NULL,
00830                               &Delay, &Restore, &m_LeftOffset, &m_TopOffset))
00831     {
00832         // Set the Delay\Restore value of the OILBitmap.
00833         pOilBitmap->SetBitmapAnimDelay(Delay);
00834         pOilBitmap->SetAnimationRestoreType(Restore);
00835 
00836         // Set the offset positions
00837         pOilBitmap->SetLeftOffset(m_LeftOffset);
00838         pOilBitmap->SetTopOffset(m_TopOffset);
00839 
00840         // Pass on the transparent colour that we found in the loading process
00841         // -1 if none found.  
00842         SetTransColour(TransColour);
00843         pOilBitmap->SetTransparencyIndex(TransColour);
00844         if (nBitmapToRead == -1)
00845             SetLastBitmap();
00846         else
00847             SetBitmapNumber(nBitmapToRead);
00848         return TRUE;
00849     }
00850     
00851     return FALSE;
00852 }
00853 
00854 /********************************************************************************************
00855 
00856 >   BOOL TI_GIFFilter::GetDragAndDropTranslation(ImportPosition *pPos, DocRect BoundsRect, 
00857                                                  Coord* Offset)
00858 
00859     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> based on Tim function
00860     Created:    15/5/97
00861     Inputs:     pSpread - the spread to check against.
00862                 BoundsRect - the bounding rectangle to check (in spread coordinates).
00863     Outputs:    Offset -
00864     Returns:    TRUE if the bounding rectangle is smaller than the spread => Offset now
00865                      contains the translation necessary to position the objects correctly.
00866                 FALSE if bounding rectangle is bigger than the spread, or pPos was NULL.
00867                       In either case, a FALSE return results in Offset containing (0,0).
00868     Purpose:    Given an drag'n'drop point (in pPos), calculate the translation necessary
00869                 to position the imported objects at this position on the spread.  It ensures
00870                 that bounding rectangles smaller than the spread are wholly contained within
00871                 the spread.  i.e. if you drag a file right to the edge of a spread, the 
00872                 translation will move it closer to the centre of the spread so that it is
00873                 wholly contained within the spread.
00874 
00875                 Used by the import filters for drag'n'drop to ensure that after the
00876                 imported objects are translated to the drop point, they are all still
00877                 on the spread.
00878     SeeAlso:    Filter::DoImport
00879 
00880 ********************************************************************************************/
00881 
00882 BOOL TI_GIFFilter::GetDragAndDropTranslation(ImportPosition *pPos, DocRect BoundsRect, 
00883                                              Coord* Offset)
00884 {
00885     // First check to se if we actually have a drag and drop point.
00886     if (pPos == NULL || pPos->pSpread == NULL)
00887     {
00888         // No - set offset to 0 and return FALSE to indicate we can't cope with this.
00889         Offset->x = 0;
00890         Offset->y = 0;
00891         return FALSE;
00892     }
00893 
00894     // Get the spread's bounding rectangle and convert it to spread coords.
00895     DocRect SpreadRect = pPos->pSpread->GetPasteboardRect();
00896     pPos->pSpread->DocCoordToSpreadCoord(&SpreadRect);
00897 
00898     // Now check that the bounding rectangle is small enough to fit on the spread...
00899     if ((BoundsRect.Width() > SpreadRect.Width()) ||
00900         (BoundsRect.Height() > SpreadRect.Height()))
00901     {
00902         // No - set offset to 0 and return FALSE to indicate we can't cope with this.
00903         Offset->x = 0;
00904         Offset->y = 0;
00905         return FALSE;
00906     }
00907 
00908     // Bounding box should be centred on drop point
00909     // This is the default way of doing it. We actually want the bounding box of the animation
00910     // centered on the drop point with the inidividual frames positioned inside this.
00911     // The x and y offsets are handled latter so we must just position the rectangle to the left
00912     // of the main animations' bounding box
00913     UINT32 GIFWidth = GIFUtil::GetGlobalWidth();
00914     UINT32 GIFHeight = GIFUtil::GetGlobalHeight();
00915     if (GIFWidth > 0 && GIFHeight > 0)
00916     {
00917         // GIFs have no concept of DPI so assume 96
00918         const double dpi = 96.0;
00919         const INT32 PixelSize = (INT32) ((72000.0 / dpi) + 0.5);    // Size of output pixel in millipoints
00920 
00921         // We have been told how many pixels the animation is in size so we should just
00922         // multiply by 72000 millipoints per inch and then divide by the pixels per inch or dpi.
00923         MILLIPOINT AnimationWidth = (INT32) (((GIFWidth * 72000.0) / dpi) + 0.5);
00924         MILLIPOINT AnimationHeight = (INT32) (((GIFHeight * 72000.0) / dpi) + 0.5);
00925         // Add these offsets onto the one that is passed in
00926         DocCoord Centre;
00927         Centre.x = (AnimationWidth) / 2;
00928         Centre.y = (AnimationHeight) / 2;
00929 
00930         // If the height or width is an odd number then we may be positioning on half pixel
00931         // boundaries. So snap to the nearest whole pixel boundary.
00932         Centre.x -= Centre.x % PixelSize;
00933         Centre.y -= Centre.y % PixelSize;
00934 
00935         Offset->x = -Centre.x;
00936         Offset->y = -Centre.y;
00937 
00938         // The bitmaps will now be so that their bottom left hand corner is at the corner
00939         // of the animation. So we need to move it up so that its top left hand corner is
00940         // at the top left of the animation.
00941         Offset->y += AnimationHeight - (BoundsRect.hi.y - BoundsRect.lo.y);
00942     }
00943     else
00944     {
00945         // No - set offset to 0 and return FALSE to indicate we can't cope with this.
00946         Offset->x = 0;
00947         Offset->y = 0;
00948     }
00949 
00950     // Transform the bounding rect to see if it's off the spread.
00951     BoundsRect.Translate(Offset->x, Offset->y);
00952 
00953     // If it's off the spread - limit it to the edge of the spread:
00954 
00955     // (a) Horizontal adjustment
00956     if (BoundsRect.lo.x < SpreadRect.lo.x)
00957         Offset->x += (SpreadRect.lo.x - BoundsRect.lo.x);
00958     else if (BoundsRect.hi.x > SpreadRect.hi.x)
00959         Offset->x -= (BoundsRect.hi.x - SpreadRect.hi.x);
00960 
00961     // (b) Vertical adjustment
00962     if (BoundsRect.lo.y < SpreadRect.lo.y)
00963         Offset->y += (SpreadRect.lo.y - BoundsRect.lo.y);
00964     else if (BoundsRect.hi.y > SpreadRect.hi.y)
00965         Offset->y -= (BoundsRect.hi.y - SpreadRect.hi.y);
00966 
00967     // Whatever happened, we can fit it on the spread.
00968     return TRUE;
00969 }
00970 
00971 /********************************************************************************************
00972 
00973 >   virtual BOOL TI_GIFFilter::SetFlagsFromBitmap(Layer * pLayer, KernelBitmap * pBitmap,
00974                                                   UINT32 nBitmapToRead)
00975 
00976     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00977     Created:    20/5/97
00978     Inputs:     pLayer          the layer that the bitmap is being put on
00979                 pBitmap         the bitmap being placed on the layer
00980                 nBitmapToRead   the number of the bitmap in the sequence
00981     Returns:    TRUE if was ok, FALSE otherwise.
00982     Purpose:    When loading in multiple bitmaps and placing them on new layers, we should
00983                 give the filter an opportunity to set the layer flags from the bitmap. In the
00984                 case of a GIF filter this would allow it to set the solid and overlay flags.
00985 
00986 ********************************************************************************************/
00987 
00988 BOOL TI_GIFFilter::SetFlagsFromBitmap(Layer * pLayer, KernelBitmap * pBitmap,
00989                                       UINT32 nBitmapToRead)
00990 {
00991     if (pBitmap && pLayer)
00992     {
00993         // transfer the disposal method from the bitmap to the layer
00994         GIFDisposalMethod method = pBitmap->GetAnimationRestoreType();
00995         // First frame is always restore background
00996         if (nBitmapToRead == 1)
00997             m_PreviousMethod = GDM_BACKTOBACK;
00998         
00999         // REM use the previous frame's restore method, not this one!
01000         switch (m_PreviousMethod)
01001         {
01002             case GDM_NONE:
01003             case GDM_LEAVE:
01004                 // Always set frame overlay
01005                 pLayer->SetOverlay(TRUE);
01006                 // As we are setting overlay, solid is not required
01007                 pLayer->SetSolid(FALSE);
01008                 // This seems to work but may need some extra clauses....
01009                 //if (nBitmapToRead == 1)
01010                 //  pLayer->SetSolid(TRUE);
01011                 //else
01012                 //  pLayer->SetSolid(FALSE);
01013                 break;
01014             case GDM_PREVIOUS:
01015             case GDM_BACKTOBACK:
01016                 // Always set frame overlay false and solid false
01017                 pLayer->SetOverlay(FALSE);
01018                 pLayer->SetSolid(FALSE);
01019                 break;
01020         }
01021 
01022         // Note the new restore method for the next frame
01023         m_PreviousMethod = method;
01024 
01025         // transfer the delay from the bitmap to the layer
01026         UINT32 delay = pBitmap->GetDelay();
01027         pLayer->SetFrameDelay(delay);
01028     }
01029 
01030     return TRUE;
01031 }
01032 
01033 /********************************************************************************************
01034 
01035 >   BOOL TI_GIFFilter::AddOffsetFromBitmap(DocCoord * pOffset)
01036 
01037     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01038     Created:    15/5/97
01039     Inputs:     pOffset         the present offset in the bitmap
01040     Returns:    TRUE if was ok, FALSE otherwise.
01041     Purpose:    When loading in a bitmap, the bitmap definition may conatin an offset. We need
01042                 to add this to the offset that we are given so that the bitmap is loaded at
01043                 the correct position.
01044                 This uses the class variables that were set up during the GIF loading process
01045                 to add the offset onto the import position.
01046 
01047 ********************************************************************************************/
01048 
01049 BOOL TI_GIFFilter::AddOffsetFromBitmap(DocCoord * pOffset)
01050 {
01051     if (pOffset && m_LeftOffset >= 0 && m_TopOffset >= 0)
01052     {
01053         // GIFs have no concept of DPI so assume 96
01054         const UINT32 dpi = 96;
01055         // We have been told how many pixels to offset by so we should just
01056         // multiply by 72000 millipoints per inch and then divide by the pixels per inch or dpi.
01057         MILLIPOINT ExtraOffsetX = (m_LeftOffset * 72000) / dpi;
01058         MILLIPOINT ExtraOffsetY = (m_TopOffset * 72000) / dpi;
01059         // Add these offsets onto the one that is passed in
01060         pOffset->x += ExtraOffsetX;
01061         // Remember, we have been told the offset from the top, so we need to move downwards
01062         pOffset->y -= ExtraOffsetY;
01063     }
01064 
01065     return TRUE;
01066 }
01067 
01068 /********************************************************************************************
01069 
01070 >   virtual BOOL TI_GIFFilter::SetAnimationPropertiesFromLoaded(Spread * pSpread)
01071 
01072     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01073     Created:    8/7/97
01074     Inputs:     pSpread     the spread that the bitmaps have been put on
01075     Returns:    TRUE if was ok, FALSE otherwise.
01076     Purpose:    When loading in multiple bitmaps and placing them on new layers, we should
01077                 give the filter an opportunity after all the bitmaps have been loaded, to go
01078                 and look at the bitmaps and set the animation properties accordingly.
01079                 In the case of a GIF filter this would allow it to set the dithering to none
01080                 and the palette to something closer to what has been loaded.
01081                 Assumes that each bitmap has been added to a separate layer and that the
01082                 referenced bitmap in the layer is set to this loaded bitmap.
01083 
01084 ********************************************************************************************/
01085 
01086 BOOL TI_GIFFilter::SetAnimationPropertiesFromLoaded(Spread * pSpread)
01087 {
01088     ERROR2IF(pSpread == NULL,FALSE,"SetAnimationPropertiesFromLoaded pSpread = NULL");
01089     
01090     // Find out about the palettes that the bitmaps have
01091     BOOL SamePalettes       = FALSE;
01092     BOOL OurBrowserPalette  = FALSE;
01093     BOOL AllHaveBitmaps     = FALSE;
01094     BOOL AllWithinCount     = FALSE;
01095     UINT32 PaletteEntries       = 0;
01096     CheckSingleBitmapsOnSpread(pSpread, &SamePalettes, &OurBrowserPalette, &AllHaveBitmaps,
01097                                &AllWithinCount, &PaletteEntries);
01098 
01099     // Grab the present animation properties from the spread
01100     AnimPropertiesParam *pProperties = &pSpread->GetSpreadAnimPropertiesParam();
01101     if (pProperties != NULL)
01102     {
01103         // Make any changes that we require
01104         pProperties->SetDither(XARADITHER_NONE);
01105         
01106         if (SamePalettes && OurBrowserPalette)
01107         {
01108             // Set ourselves a global browser palette
01109             pProperties->SetPaletteCols(PALCOL_BROWSER);
01110             pProperties->SetPalette(PAL_GLOBAL);
01111         }
01112         else if (SamePalettes)
01113         {
01114             // Set ourselves a global optimised palette
01115             pProperties->SetPaletteCols(PALCOL_OPTIMIZED);
01116             pProperties->SetPalette(PAL_GLOBAL);
01117             if (PaletteEntries > 0)
01118                 pProperties->SetNumColsInPalette(PaletteEntries);
01119         }
01120         else
01121         {
01122             // Set ourselves a local optimised palette
01123             pProperties->SetPaletteCols(PALCOL_OPTIMIZED);
01124             pProperties->SetPalette(PAL_LOCAL);
01125             // Ensure that the optimised palette contains
01126             if (PaletteEntries > 0)
01127                 pProperties->SetNumColsInPalette(PaletteEntries);
01128         }
01129 
01130         // Put back the new animation properties
01131         pSpread->SetSpreadAnimPropertiesParam(*pProperties);
01132 
01133         // Tell anybody that is interested about the changes    
01134         BROADCAST_TO_ALL(SpreadMsg(pSpread, SpreadMsg::ANIMATIONPROPERTIESCHANGED));
01135     }
01136 
01137     return TRUE;
01138 }
01139 
01140 /********************************************************************************************
01141 
01142 >   virtual void TI_GIFFilter::CleanUpAfterExport()
01143 
01144     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01145     Created:    25/9/95
01146     Purpose:    Cleans up the memory allocated at the end of Exporting or when exporting has
01147                 been aborted for some reason. Does its cleaning up and then calls the
01148                 baseclass version to do its stuff,  - used
01149                 when the import process ends, either normally or abnormally. Override if
01150                 extra things are required.
01151     SeeAlso:    BaseBitmapFilter::PrepareToExport(); BaseBitmapFilter::CleanUpAfterExport();
01152     Scope:      Protected
01153 
01154 ********************************************************************************************/
01155 
01156 void TI_GIFFilter::CleanUpAfterExport()
01157 {
01158     // Called right at the end of th