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 the export process or when the epxort has been aborted
01159     // Clean up any objects unique to this class.
01160     // Free up any DIBs that we might have left lying around on the export
01161     if (pDestBMInfo && pDestBMBytes)
01162     {
01163         FreeDIB( pDestBMInfo, pDestBMBytes );
01164         pDestBMInfo = NULL;
01165         pDestBMBytes = NULL;    
01166     }
01167 
01168     // reset the filter settings, as the preview export might have messed with them
01169 
01170     // the depth we ask GDraw to render is always 32-bit, so we can get transparency
01171     // we have to convert for other formats when writing the actual bytes to the file
01172     SetDepthToRender(32);
01173 
01174     // We haven't written the header yet
01175     WrittenHeader = FALSE;
01176 
01177     // We are a first pass render and not doing the mask, by default
01178     SecondPass = FALSE;
01179     DoingMask = FALSE;
01180 
01181     // Now call the baseclass version to do its stuff
01182     BaseBitmapFilter::CleanUpAfterExport();
01183 }
01184 
01185 /********************************************************************************************
01186 
01187 >   BOOL TI_GIFFilter::GetExportOptions(BitmapExportOptions* pOptions)
01188 
01189     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
01190     Created:    29/10/96
01191     Purpose:    See BaseBitmapClass for interface details
01192     Notes:      Initializes GIF specific members
01193     Scope:      Protected
01194 
01195 ********************************************************************************************/
01196 BOOL TI_GIFFilter::GetExportOptions(BitmapExportOptions* pOptions)
01197 {
01198 
01199 //[MD]
01200 
01201 #ifndef STANDALONE
01202     ERROR2IF(pOptions == NULL, FALSE, "NULL Args");
01203 
01204     GIFExportOptions* pGIFOptions = (GIFExportOptions*)pOptions;
01205     ERROR3IF(!pGIFOptions->IS_KIND_OF(GIFExportOptions), "pGIFOptions isn't");
01206 
01207     // the depth we ask GDraw to render is always 32-bit, so we can get transparency
01208     // we have to convert for other formats when writing the actual bytes to the file
01209     SetDepthToRender(32);
01210 
01211     // We haven't written the header yet
01212     WrittenHeader = FALSE;
01213 
01214     // We are a first pass render and not doing the mask, by default
01215     SecondPass = FALSE;
01216     DoingMask = FALSE;
01217 
01218     // Default will range from 0 to 4 types which correspond to the combinations of
01219     // on/off interlaced and on/off transparent
01220     
01221     // Determine the filter type currently in use in Accusoft format
01222     s_FilterType = (pGIFOptions->GetSelectionType() == SOMEBITMAPS) ? TI_GIF_ANIM : TI_GIF;
01223     pGIFOptions->SetFilterType(s_FilterType);
01224     m_DoingAnimation = (pGIFOptions->GetSelectionType() == SOMEBITMAPS);
01225     
01226     // This is ok as we are using a modal dialog box    
01227     BOOL Ok = FALSE;
01228     
01229     if (s_FilterType == TI_GIF)
01230     {
01231         OpDescriptor* pOpDes = OpDescriptor::FindOpDescriptor(OPTOKEN_GIFTABDLG);
01232         if (pOpDes != NULL)
01233         {
01234             // set up the data for the export options dialog
01235             OpParam Param((void *)pOptions, (void *)this);
01236 
01237             // invoke the dialog
01238             pOpDes->Invoke(&Param);
01239 
01240             // SMFIX
01241             // we have brought the dlg up so get the options from the dlg as the graphic type may have changed
01242             pOptions = BmapPrevDlg::m_pExportOptions;
01243 
01244             // check for valid options
01245             //  This may get messed up, so have to use the second line below.
01246             Ok = BmapPrevDlg::m_bClickedOnExport;
01247         }
01248         else
01249         {   
01250             ERROR3("Unable to find OPTOKEN_BMAPPREVDLG");
01251         } 
01252     }
01253     else
01254     {
01255 #ifndef EXCLUDE_FROM_XARALX
01256         // invoke the dialog
01257         Ok = BmpPrefsDlg::InvokeDialog( pOptions);
01258 #endif
01259     }
01260 
01261     // Return with the ok/cancel state used on the dialog box
01262     return Ok;
01263 
01264 #else
01265     return FALSE;
01266 #endif
01267 }
01268 
01269 
01270 // SMFIX sjk 5/12/00 there used to be some junk in the call to GetExportOptions that assumed the
01271 // filter type being used which could be changed by the GetExportOptions call itself
01272 // therefore all this sort of stuff should be called on the correct known filter using this
01273 // call afterwards
01274 void TI_GIFFilter::PostGetExportOptions(BitmapExportOptions* pOptions)
01275 {
01276     // should be of this type
01277     GIFExportOptions* pGIFOptions = (GIFExportOptions*)pOptions;
01278     ERROR3IF(!pGIFOptions->IS_KIND_OF(GIFExportOptions), "pGIFOptions isn't");
01279 
01280     // do the baseclass options
01281     MaskedFilter::PostGetExportOptions(pOptions);
01282 
01283     // do the specific to this class options
01284     SetDepthToRender(pGIFOptions->GetDepth());
01285 
01286     m_DoingAnimation = (pGIFOptions->GetSelectionType() == SOMEBITMAPS);
01287 
01288     // Filter type can be changed by the export options dialog box from say 
01289     // TI_GIF to TI_GIF_INTERLACED
01290     UINT32 Silliness = pGIFOptions->WantTransparent() ? 2 : 0;
01291     Silliness |= pGIFOptions->WantInterlaced() ? 1 : 0;
01292     if (Silliness >= 0 && Silliness < 4)
01293     {
01294         Compression = Silliness;
01295         // Compression ranges from 0 .. 3 so map this onto our filter types
01296 //      FilterID = Silliness + TI_GIF;
01297         switch (Silliness)
01298         {
01299         case 0: s_FilterType = TI_GIF; break;
01300         case 1: s_FilterType = TI_GIF_INTERLACED; break;
01301         case 2: s_FilterType = TI_GIF_TRANSPARENT; break;
01302         case 3: s_FilterType = TI_GIF_TRANSINTER; break;
01303         case 4: s_FilterType = TI_GIF_ANIM; break;
01304         }
01305 
01306         if (pGIFOptions->WantTransparent() && pGIFOptions->GetSelectionType() == SELECTION)
01307             DoingMask = TRUE;
01308     }
01309 }
01310 
01311 
01312 /********************************************************************************************
01313 
01314 >   virtual UINT32 TI_GIFFilter::GetExportMsgID()
01315 
01316     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01317     Created:    18/09/95
01318     Returns:    The id of the message to put on the progress display whilst exporting.
01319     Purpose:    Used to get the message id to be used during export.
01320                 Overides the baseclass form of the function so that during the two stage
01321                 export process it can change the message.
01322     SeeAlso:    DoExport;
01323 
01324 ********************************************************************************************/
01325 
01326 UINT32 TI_GIFFilter::GetExportMsgID()
01327 {
01328     if (GeneratingOptimisedPalette())
01329         return _R(IDS_GENOPTPALMSGID);              // "Generating optimised palette..."
01330 
01331     GIFExportOptions* pGIFOptions = (GIFExportOptions*)GetBitmapExportOptions();
01332     ERROR2IF(pGIFOptions == NULL, FALSE, "NULL Args");
01333     ERROR3IF(!pGIFOptions->IS_KIND_OF(GIFExportOptions), "pGIFOptions isn't");
01334     
01335     // If we are exporting with transparency on and on first pass use the masking message
01336     // otherwise use the exporting message.
01337     if (pGIFOptions->GetSelectionType() == SELECTION && pGIFOptions->WantTransparent())
01338     {
01339         // Special 4 stage rendering operation
01340         // - Render selected objects to white background
01341         // - Render mask 1bpp
01342         // - Render all objects
01343         // - Save data out to disk
01344         if (!SecondPass)
01345             return Export2ndStageMsgID;         // "Preparing mask for GIF file..."
01346         else
01347             return Filter::GetExportMsgID();    // "Preparing GIF file..."
01348     }
01349     else
01350     {
01351         // Special 3 stage rendering operation
01352         // - Render objects to white background
01353         // - Render mask 1bpp
01354         // - Save data out to disk
01355         if (DoingMask)
01356             return Export2ndStageMsgID;         // "Preparing mask for GIF file..."
01357         else
01358             return Filter::GetExportMsgID();    // "Preparing GIF file..."
01359     }
01360 }
01361 
01362 
01363 /********************************************************************************************
01364 
01365 >   BOOL TI_GIFFilter::EndWriteToFile( )
01366 
01367     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01368     Created:    12/5/95
01369     Inputs:     -
01370     Purpose:    Cleans up after writing the bitmap data out to a file. Inherited classes
01371                 override this to write in different file formats.
01372                 This is slightly different to most other bitmap filters in that it is here
01373                 that the data actually gets written out to file, after doing the transparency
01374                 translation, if required.
01375     Returns:    TRUE if worked, FALSE if failed.
01376 
01377 ********************************************************************************************/
01378 
01379 BOOL TI_GIFFilter::EndWriteToFile( )
01380 {
01381 #ifndef STANDALONE
01382 
01383     if (GeneratingOptimisedPalette())
01384         return TRUE;        // No need to output anything
01385 
01386         //  Can reset the band number now.
01387     m_BandNumber = 0;
01388 
01389     GIFExportOptions* pGIFOptions = (GIFExportOptions*)GetBitmapExportOptions();
01390     ERROR2IF(pGIFOptions == NULL, FALSE, "NULL Args");
01391     ERROR3IF(!pGIFOptions->IS_KIND_OF(GIFExportOptions), "pGIFOptions isn't");
01392 
01393 TRACEUSER( "Neville", _T("TI_GIFFilter::EndWriteToFile\n"));
01394     // Do the transparency translation just before we write out the data as a GIF.
01395     // This involves doing a 1 bpp export of the same area and using this to work
01396     // out which areas are transparent or not.
01397     // Only do this if the user has requested transparency and we outputting at 8bpp
01398 
01399     if (BadExportRender)
01400     {
01401         // Delete our whitearea bitmap
01402         if (pTempBitmapMask != NULL)
01403             CCFree(pTempBitmapMask);
01404 
01405         pTempBitmapMask = NULL;
01406     }
01407 
01408     BOOL ok = TRUE;
01409     BOOL SaveDataOut = TRUE;
01410     BOOL WantTransparent = pGIFOptions->WantTransparent();
01411     BOOL WantInterlaced = pGIFOptions->WantInterlaced();
01412 
01413     // Save the data out if required. Only if we exported ok.
01414     if (SaveDataOut && !BadExportRender)
01415     {
01416         // Now that we know the transparent index we can output the GIF header
01417         if (ok)
01418         {
01419             // Work out whether we should save as GIF87 or GIF89
01420             // If we are using animation or transparency then save out as GIF89
01421             BOOL Enhanced = m_DoingAnimation || WantTransparent;
01422 
01423             if (m_DoingAnimation)
01424             {
01425                 if (m_AnimationFrame == 0)
01426                 {
01427                     // We force a transparent colour of -1 so the transparent index colour is not changed to white in the global colour table.
01428                     ok = DestGIF.OutputGifFileHeader(OutputFile, Enhanced, -1);
01429                     if (ok)
01430                     {
01431                         // Shall we output a Loop block ?
01432 
01433                         // We only put a loop block in if the loop count is 0, or > 1
01434                         // and we subtract 1 from values other than 0, so that the
01435                         // loop count represent the number of times the animation
01436                         // is 'played' rather than 'repeated' ....
01437                         // 
01438                         // ie.  0, loop block with value 0.     Repeat forever.
01439                         //      1, no loop block.               One shot animation.
01440                         //      2, loop block with value 1.     Plays animation 2 times.
01441                         //      3, loop block with value 2.     Plays animation 3 times.
01442                         //      4, loop block with value 3.     Plays animation 4 times.
01443                         //      etc ...
01444                         UINT32 LoopCount = pGIFOptions->GetAnimationLoopCount();
01445                         if (LoopCount != 1)
01446                         {
01447                             if (LoopCount > 1) LoopCount -= 1;
01448 
01449                             // Output a loop block then ...
01450                             ok = DestGIF.OutputAnimationControl(OutputFile, LoopCount);
01451                         }
01452                     }
01453                 }
01454             }
01455             else
01456             {
01457                 ok = DestGIF.OutputGifFileHeader(OutputFile, Enhanced, pGIFOptions->GetTransparencyIndex());
01458             }
01459         }
01460 
01461         // Actually write the destination bitmap out to the file showing an hourglass
01462         // and/or progress bar as we go. Always show the Exporting message.
01463         // Need to do in one go due to interlacing
01464 
01465         // Andy, 13-12-00: removed progress bar.
01466         // It goes by very quickly compared with the main rendering jobbie.
01467         // Also removed corresponding ContinueSlowJob from OutputGIF::BumpPixel
01468         if (ok)
01469         {
01470             String_64 ProgressString(ExportingMsgID);
01471             ProgressString = GetExportProgressString(OutputFile, ExportingMsgID);
01472             //BeginSlowJob(100, FALSE, &ProgressString);
01473         
01474             if (ok && (WantTransparent || m_DoingAnimation || WantInterlaced))
01475             {
01476                 ok = DestGIF.OutputGifImageExtensionHeader(OutputFile, WantInterlaced,
01477                         pGIFOptions->GetTransparencyIndex(),
01478                         m_DoingAnimation ? pGIFOptions->GetAnimationDelay() : 0,
01479                         m_DoingAnimation ? pGIFOptions->GetAnimationRestore() : 0);
01480             }
01481             // if we are doing an animation with an optimised palette then we will need
01482             // save out this palette as a local colour table (the first frame uses the global table)
01483             BOOL OutputLocalColourTable = (m_DoingAnimation && pOptimisedPalette != NULL && m_AnimationFrame != 0);
01484             if (ok)
01485                 ok = DestGIF.OutputGifImageBits(OutputFile, DestGIF.GetDestBitmapBits(), WantInterlaced, OutputLocalColourTable);
01486 
01487             //EndSlowJob();
01488         }
01489     }
01490 
01491     return ok;
01492 
01493 #else   
01494 
01495     return TRUE;
01496 
01497 #endif
01498 
01499 }
01500 
01501 
01502 /********************************************************************************************
01503 
01504 >   virtual BOOL TI_GIFFilter::SaveExportBitmapsToFile(CCLexFile* pFile, PathName* pPath, BitmapExportParam* pParam,
01505                                                        BOOL DontShowFileName = FALSE)
01506 
01507     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01508     Created:    30/04/97
01509     Inputs:     pDiskFile - the file to put the exported data into
01510                 pPath - the pathname of the file to be exported to
01511                 pParam - the data to use when exporting the bitmaps
01512                 DontShowFileName - if set to true then don't show the filename in the progress string
01513     Purpose:    Exports the bitmaps specified by the BitmapExportParam object to a multi-
01514                 image capable filter. Each of the bitmaps will be saved to file using the
01515                 settings specified.
01516     Returns:    TRUE if worked, FALSE if failed.
01517     SeeAlso:    GrabFrame Filter::DoExportBitmaps;
01518 
01519 ********************************************************************************************/
01520 
01521 BOOL TI_GIFFilter::SaveExportBitmapsToFile(CCLexFile* pFile, PathName* pPath, BitmapExportParam* pParam,
01522                                            BOOL DontShowFileName)
01523 {
01524 #if defined(DO_EXPORT) && !defined(EXCLUDE_FROM_XARALX)
01525     ERROR2IF(pFile == NULL || pPath == NULL, FALSE,"NULL Parameters");
01526     ERROR2IF(pParam == NULL,FALSE,"TI_GIFFilter::DoExportBitmaps null BitmapExportParam specified");
01527 
01528     BOOL ok = TRUE;
01529 
01530     // Make sure the Region pointer is NULL for the time being
01531     ExportRegion = NULL;
01532 
01533     ERROR2IF(!pParam->IS_KIND_OF(GIFAnimationExportParam), FALSE, "pParam isn't GIFAnimationExportParam");
01534     GIFAnimationExportParam* pGIFOptions = (GIFAnimationExportParam*)pParam;
01535     UINT32 BitmapCount                  = pGIFOptions->GetBitmapCount();        // Number of bitmaps in animation
01536     KernelBitmap * pBitmap              = NULL;
01537     WEB_PALETTE GlobalLocalPal          = pGIFOptions->GetPalette();            // Global or local palette
01538     PALETTE_COLOURS PaletteColours      = pGIFOptions->GetPaletteCols();        // Browser or Optimised palette
01539     BOOL SaveLocalPalette               = FALSE;                                // Default to global palette
01540     if (GlobalLocalPal == PAL_LOCAL) // && PaletteColours == PAL_OPTIMIZED)
01541         SaveLocalPalette = TRUE;
01542 
01543     Spread * pSpread = Document::GetSelectedSpread();
01544 
01545     LPBITMAPINFO pOldInfo               = NULL;
01546     LPBYTE pOldBytes                    = NULL;
01547     LPBITMAPINFO pDiffInfo              = NULL;
01548     LPBYTE pDiffBytes                   = NULL;
01549     LPBITMAPINFOHEADER pTrueInfoHeader  = NULL;
01550 
01551     // The list of bitmap frames that we need to output as part of the animatation
01552     List BitmapFrameList;
01553     AnimatedGIFImage * pPrevGIFImage = NULL;
01554     for (UINT32 Index = 0; ok && (Index < BitmapCount); Index++)
01555     {
01556         // Get the bitmap pointer
01557         pBitmap = pGIFOptions->GetBitmap(Index);
01558 
01559         LPBITMAPINFO    pInfo   = NULL;
01560         LPBYTE          pBytes  = NULL;
01561         if (pBitmap)
01562         {
01563             pInfo   = pBitmap->GetBitmapInfo();
01564             pBytes  = pBitmap->GetBitmapBits();
01565         }   
01566         if (pBitmap && pInfo && pBytes)
01567         {
01568             // Get the useful information on the bitmap
01569             UINT32          Bpp     = pBitmap->GetBPP();
01570             INT32           TransColour = -1;
01571             if (Bpp <= 8)
01572             {
01573                  pBitmap->GetTransparencyIndex(&TransColour);
01574                  if (TransColour == -1 && pInfo->bmiColors[0].rgbRed == 255 && pInfo->bmiColors[0].rgbGreen == 255 && pInfo->bmiColors[0].rgbBlue == 255)
01575                  {
01576                      TRACEUSER( "SimonK", _T("taking 1st palette entry as transp since it is white\n"));
01577                      TransColour = 0;
01578                  }
01579             }
01580 
01581             // Recover the restore type assigned to the bitmap which we will then use
01582             // unless we override it further down
01583             GIFDisposalMethod FrameRestore = pBitmap->GetAnimationRestoreType();
01584 
01585             // Recover the delay from the bitmap itself
01586             CENTISECONDS FrameDelay = pBitmap->GetDelay();
01587 
01588             // If we are on the first bitmap then note the first bitmap's size as the
01589             // overall size of the animation
01590             if (ok && Index == 0)
01591             {
01592                 // BITMAPINFO  consists of:-
01593                 //      BITMAPINFOHEADER    bmiHeader;
01594                 //      RGBQUAD             bmiColors[1];
01595                 // This is the real bitmap info header giving the overall size of the export
01596                 pTrueInfoHeader = pBitmap->GetBitmapInfoHeader();
01597             }
01598 
01599             // If we have a previous frame then minimise the amount of bitmap which we will output
01600             // by working out the difference between the two frames and making everything else the
01601             // transparent colour.
01602             LPBITMAPINFO pOutputInfo    = pInfo;
01603             LPBYTE pOutputBytes         = pBytes;
01604             UINT32 LeftOffset               = 0;
01605             UINT32 TopOffset                = 0;
01606             
01607             // Recover the offsets from the bitmap itself. Only really useful if we are using
01608             // pre-loaded bitmaps as single items on the layer.
01609             LeftOffset                  = pBitmap->GetLeftOffset();
01610             TopOffset                   = pBitmap->GetTopOffset();
01611 
01612             // If we are in local optimised mode then we cannot diff the bitmaps as we are overlaying
01613             // and so a change in palette could be very bad indeed!
01614             BOOL DiffFailed = FALSE;
01615             if (pOldInfo && pOldBytes && !SaveLocalPalette)
01616             {
01617                 // Pass in the present bitmap and get a new one back
01618                 BOOL FoundBadOverlay = FALSE;
01619 
01620                 if (pSpread->GetSpreadAnimPropertiesParam().GetIsBackGroundTransp() /*pGIFOptions->GetIsBackGroundTransp()*/)
01621                 {
01622                     // with a transparent background every overlay is a bad overlay
01623                     FoundBadOverlay = TRUE;
01624                 }
01625                 else
01626                 {
01627                     ok = DIBUtil::GenerateDifferenceBitmap(pOldInfo, pOldBytes, pInfo, pBytes,
01628                                                        &pDiffInfo, &pDiffBytes,
01629                                                        TransColour, &FoundBadOverlay);
01630                 }
01631                 // If we have found that we cannot overlay the previous frame then
01632                 // set the restore type to put the background back and forget about
01633                 // the diff bitmap.
01634                 // We must change the previous bitmap's restore type so access the previous
01635                 // item in the output list
01636                 if (FoundBadOverlay)
01637                 {
01638                     if (pPrevGIFImage)
01639                         pPrevGIFImage->SetFrameRestore(GDM_BACKTOBACK);
01640                     FrameRestore = GDM_BACKTOBACK;
01641                 }
01642                 else if (ok && pDiffInfo && pDiffBytes)
01643                 {
01644                     // If everything went ok then output the difference bitmap
01645                     pOutputInfo = pDiffInfo;
01646                     pOutputBytes = pDiffBytes;
01647                     
01648                     // Ensure that we have an overlay restore type
01649                     FrameRestore = GDM_LEAVE;
01650                     if (pPrevGIFImage)
01651                         pPrevGIFImage->SetFrameRestore(GDM_LEAVE);
01652                 }
01653                 else
01654                 {
01655                     // Possible loaded an animation and now wanting to output it again
01656                     // Use the left and top offsets in the bitmap
01657                     // These should have been set up in CheckIfSingleBitmap();
01658                     TRACEUSER( "Neville", _T("Something went wrong, outputting whole bitmap\n"));
01659                     DiffFailed = TRUE;
01660                     //LeftOffset = pBitmap->GetLeftOffset();
01661                     //TopOffset = pBitmap->GetTopOffset();
01662                     //FrameRestore = pBitmap->GetAnimationRestoreType();
01663                 }
01664             }
01665             else if (pOldInfo && pOldBytes && pSpread->GetSpreadAnimPropertiesParam().GetIsBackGroundTransp())
01666             {
01667                 // dont overlay transp images have them back to back
01668                 if (pPrevGIFImage)
01669                     pPrevGIFImage->SetFrameRestore(GDM_BACKTOBACK);
01670                 FrameRestore = GDM_BACKTOBACK;
01671             }
01672 
01673 
01674             // Work out if we can shrink the bitmap down in size
01675             // Only do this if we are not on the first bitmap. Internet Explorer screws up
01676             // as it seems to assume that the size of the first frame is the size of the animation
01677             // rather than taking the true animation size.
01678             // This may re-allocate the difference bitmap for us to a new smaller size
01679             // In this case it will return a left and top offset for us to use.
01680             if (ok && pOutputInfo && pOutputBytes && Index != 0 &&
01681                 LeftOffset == 0 && TopOffset == 0 && !DiffFailed)
01682             {
01683                 ok = DIBUtil::GenerateSubRegionBitmap(pOutputInfo, pOutputBytes,
01684                                                       &pDiffInfo, &pDiffBytes, TransColour,
01685                                                       &LeftOffset, &TopOffset);
01686                 if (ok && pDiffInfo && pDiffBytes)
01687                 {
01688                     // If everything went ok then output the sub-region bitmap
01689                     pOutputInfo = pDiffInfo;
01690                     pOutputBytes = pDiffBytes;
01691                 }
01692                 // Otherwise just output the whole bitmap
01693             }
01694 
01695             // Add an item to the list of frames to output
01696             AnimatedGIFImage * pGIFImage = new AnimatedGIFImage(TransColour, FrameRestore, FrameDelay,
01697                                                                 LeftOffset, TopOffset,
01698                                                                 pOutputInfo, pOutputBytes,
01699                                                                 pDiffInfo, pDiffBytes);
01700             if (pGIFImage == NULL)
01701             {
01702                 ok = FALSE;
01703                 break;
01704             }
01705 
01706             BitmapFrameList.AddTail(pGIFImage);
01707             
01708             // Remember this bitmap for later use
01709             pOldInfo = pInfo;
01710             pOldBytes = pBytes;
01711 
01712             pPrevGIFImage = pGIFImage;
01713 
01714             // blank these so as 
01715             pDiffInfo   = NULL;
01716             pDiffBytes  = NULL;
01717         }
01718     }
01719 
01720     if (!ok)
01721     {
01722         ERROR3("Failed to make the output list of GIF images");
01723         // Clean out the list of GIF images that we made ready for exporting
01724         BitmapFrameList.DeleteAll();
01725         return FALSE;
01726     }
01727 
01728     // **** Actually output the data to file
01729     
01730     // Used to open the file up before starting DoExport. But this meant a cancel on the export
01731     // options dialog had filled the file, if it was already present. So now up up here if
01732     // not open already. In the PreviewBitmap case the file will already be open.
01733     if (!pFile->isOpen())
01734     {
01735         if (pFile->IsKindOf(CC_RUNTIME_CLASS(CCDiskFile)))
01736         {
01737             ok = OpenExportFile((CCDiskFile*) pFile, pPath);
01738         }
01739         else
01740         {
01741             TRACEUSER( "JustinF", _T("Tried to open non-CCDiskFile in BaseBitmapFilter::DoExportBitmaps\n"));
01742             ok = FALSE;
01743         }
01744     }
01745 
01746     if (!ok)
01747     {
01748         ERROR3("Failed to open the export file for GIF images");
01749         // Clean out the list of GIF images that we made ready for exporting
01750         BitmapFrameList.DeleteAll();
01751         return FALSE;
01752     }
01753 
01754     // Make a note of the Disk file we are to use
01755     OutputFile = pFile;
01756 
01757     // Recover information on the animation 
01758     const BOOL WantInterlaced               = FALSE;        // We never want interlacing
01759     UINT32 LoopCount                            = pGIFOptions->GetAnimLoop();           // Looping for the animation
01760     const CENTISECONDS AnimationDelay       = pGIFOptions->GetGlobalAnimDelay();    // Delay in CentiSeconds
01761 
01762     // Check that we have an animation size information block
01763     ERROR2IF(pTrueInfoHeader==NULL,FALSE,"TI_GIFFilter::WriteToFile BitmapInfoHeader pointer is null");
01764 
01765     UINT32  Index = 0;
01766     AnimatedGIFImage * pCurrentGIFImage = (AnimatedGIFImage *)BitmapFrameList.GetHead();
01767     while ( ok && pCurrentGIFImage)
01768     {
01769         // Tecover the info from the GIF image item
01770         // This is the real bitmap info header giving the overall size of the export
01771         LPBITMAPINFO pOutputInfo        = pCurrentGIFImage->GetOutputInfo();
01772         LPBYTE pOutputBytes             = pCurrentGIFImage->GetOutputBits();
01773         INT32 TransColour               = pCurrentGIFImage->GetTransColour();
01774         GIFDisposalMethod FrameRestore  = pCurrentGIFImage->GetFrameRestore();
01775         CENTISECONDS FrameDelay         = pCurrentGIFImage->GetFrameDelay();
01776         UINT32 LeftOffset                   = pCurrentGIFImage->GetLeftOffset();
01777         UINT32 TopOffset                    = pCurrentGIFImage->GetTopOffset();
01778 
01779         // BITMAPINFO  consists of:-
01780         //      BITMAPINFOHEADER    bmiHeader;
01781         //      RGBQUAD             bmiColors[1];
01782 
01783         // This is the header for the bitmap that we are actually outputting
01784         LPBITMAPINFOHEADER pInfoHeader = &pOutputInfo->bmiHeader;
01785         ERROR2IF(pInfoHeader==NULL,FALSE,"TI_GIFFilter::WriteToFile BitmapInfoHeader pointer is null");
01786             
01787         LPRGBQUAD pPalette = &(pOutputInfo->bmiColors[0]);
01788         ERROR2IF(pPalette==NULL,FALSE,"TI_GIFFilter::WriteToFile palette pointer is null");
01789 
01790         // If we are on the first bitmap then out the file start information
01791         if (ok && Index == 0)
01792         {
01793             // We force a transparent colour of -1 so the transparent index colour is not changed to white in the global colour table.
01794             ok = DestGIF.OutputGifFileHeader(pFile, pTrueInfoHeader, TRUE, TransColour, NULL, pPalette);
01795             if (!ok)
01796                 break;
01797 
01798             // Shall we output a Loop block ?
01799 
01800             // We only put a loop block in if the loop count is 0, or > 1
01801             // and we subtract 1 from values other than 0, so that the
01802             // loop count represent the number of times the animation
01803             // is 'played' rather than 'repeated' ....
01804             // 
01805             // ie.  0, loop block with value 0.     Repeat forever.
01806             //      1, no loop block.               One shot animation.
01807             //      2, loop block with value 1.     Plays animation 2 times.
01808             //      3, loop block with value 2.     Plays animation 3 times.
01809             //      4, loop block with value 3.     Plays animation 4 times.
01810             //      etc ...
01811             if (LoopCount != 1)
01812             {
01813                 if (LoopCount > 1) LoopCount -= 1;
01814 
01815                 // Output a loop block then ...
01816                 ok = DestGIF.OutputAnimationControl(pFile, LoopCount);
01817                 if (!ok)
01818                     break;
01819             }
01820 
01821             // For now force a restore type of restore background on the first frame 
01822             //AnimationRestore = GDM_BACKTOBACK;
01823         }
01824 
01825         // Actually write the destination bitmap out to the file showing an hourglass
01826         // and/or progress bar as we go. Always show the Exporting message.
01827         // Need to do in one go due to interlacing
01828         if (ok)
01829         {
01830             String_64 ProgressString(ExportingMsgID);
01831             // If the caller has requested it, then supress the filename
01832             // Useful if we are doing Browser preview so that the temp file does not
01833             // get shown.
01834             if (DontShowFileName)
01835                 ProgressString = GetExportProgressString(NULL, ExportingMsgID);
01836             else
01837                 ProgressString = GetExportProgressString(pFile, ExportingMsgID);
01838             BeginSlowJob(100, FALSE, &ProgressString);
01839         
01840             ok = DestGIF.OutputGifImageExtensionHeader( pFile, WantInterlaced,
01841                                                         TransColour,
01842                                                         FrameDelay,
01843                                                         FrameRestore);
01844 
01845             // If we are doing an animation with an optimised palette then we will need to
01846             // save out this palette as a local colour table (the first frame uses the global table)
01847             BOOL OutputLocalColourTable = (SaveLocalPalette && Index != 0);
01848             if (ok)
01849                 ok = DestGIF.OutputGifImageBits(pFile, pOutputBytes,
01850                                                 WantInterlaced, OutputLocalColourTable,
01851                                                 NULL,
01852                                                 pInfoHeader->biWidth, pInfoHeader->biHeight, 
01853                                                 LeftOffset, TopOffset,
01854                                                 pPalette, pInfoHeader->biClrUsed, pInfoHeader->biBitCount);
01855         }
01856 
01857         Index ++;
01858 
01859         // Get the next item in the list
01860         pCurrentGIFImage = (AnimatedGIFImage *)BitmapFrameList.GetNext(pCurrentGIFImage);
01861     }
01862 
01863     // Finish the file off
01864     if (ok)
01865         ok = DestGIF.OutputGifTerminator(pFile);
01866 
01867     // Clean out the list of GIF images that we made ready for exporting
01868     BitmapFrameList.DeleteAll();
01869 
01870     // All done - deallocate dynamic objects, stop the progress display/hourglass
01871     // and return success. (Also closes file. Eh! Does it?).
01872     CleanUpAfterExport();
01873 
01874     return ok;
01875 #endif
01876     return FALSE;
01877 }
01878 
01879 /********************************************************************************************
01880 
01881 >   static BOOL TI_GIFFilter::WriteDataToFile( BOOL End, UINT32 Bpp, UINT32 Compression)
01882 
01883     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01884     Created:    24/4/95
01885     Inputs:     End - TRUE if this is the last block of the file.
01886                 Bpp - output depth in terms of bits per pixel
01887                 Compression - usually True if compression required, False otherwise
01888                               In the GIF case this is used to pass in the transparency and
01889                               interlace state.
01890     Returns:    TRUE if worked, FALSE if errored.
01891     Purpose:    Physically put the bitmap into the disk.
01892                 NOTE - ONLY COPES WITH End=TRUE currently
01893                 AtEnd is ignored now and should always be set to TRUE.
01894                 Unused at present due to static problems when cretaing the 1bpp bitmap. 
01895     SeeAlso:    WriteToFile(); AccusoftFilters::WriteToFile; AccusoftFilters::WriteDataToFile;
01896 
01897 ********************************************************************************************/
01898 
01899 BOOL TI_GIFFilter::WriteDataToFile( BOOL End, UINT32 Bpp, UINT32 Compression)
01900 {
01901     ERROR2(FALSE,"TI_GIFFilter::WriteDataToFile called when not implemented");
01902     return FALSE;
01903 }
01904 
01905 
01906 /********************************************************************************************
01907 
01908 >   INT32 TI_GIFFilter::HowCompatible(PathName& Filename, ADDR HeaderStart, UINT32 HeaderSize, 
01909                                  UINT32 FileSize)
01910 
01911     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01912     Created:    24/4/95
01913     Inputs:     Filename - name of the file.
01914                 HeaderStart - Address of the first few bytes of the file.
01915                 HeaderSize - the number of bytes in the header pointed to by FileStart.
01916                 FileSize - the size of the whole file, in bytes.
01917     Returns:    0 => Not a GIF file.
01918                 10 => It is a GIF file.
01919     Purpose:    Determine if this filter can load the specified file.
01920 
01921 ********************************************************************************************/
01922 
01923 INT32 TI_GIFFilter::HowCompatible(PathName& Filename, ADDR HeaderStart, UINT32 HeaderSize, UINT32 FileSize)
01924 {
01925 TRACEUSER( "Neville", _T("TI_GIFFilter::HowCompatible"));   
01926     // We need to remember what we thought of this file in our class variable.
01927     // So, set it to a nice default value at the start.
01928     GIFHowCompatible = 0;
01929 
01930     // Check that we've got enough data to do our check
01931     // This is really sizeof(GIFINFOHEADER) but this returns 14 instead of 13
01932     // as it rounds to the nearest word boundary
01933     const size_t GIFHeaderSize = sizeof(char)* 6 + sizeof(WORD) * 2 + sizeof(BYTE) * 3;
01934     if (HeaderSize < GIFHeaderSize)
01935     {
01936         // Not enough data - ignore this file.
01937         return 0;
01938     }
01939 
01940     // Check the header for the "GIF" signature.
01941     LPGIFINFOHEADER pHeader = (LPGIFINFOHEADER) HeaderStart;
01942 
01943     if (
01944         ( strncmp( pHeader->giName, "GIF89a", 6 ) == 0 ) ||
01945         ( strncmp( pHeader->giName, "GIF87a", 6 ) == 0 )
01946        )
01947     {
01948         // the other fields in the GIFINFOHEADER don't really hold any useful information
01949         // and really finding GIF87a/89a should be good enough to determine that there is
01950         // a high chance that this is a GIF file.
01951 
01952         // Remember what we thought in our class variable.
01953         GIFHowCompatible = 10;
01954     }
01955     else
01956     {
01957         // No GIF signature - we don't want this file.
01958         GIFHowCompatible = 0;
01959     }
01960                 
01961 TRACEUSER( "Neville", _T("TI_GIFFilter::HowCompatible returning = %d\n"),GIFHowCompatible);
01962     // Return the found value to the caller.
01963     return GIFHowCompatible;
01964 }
01965 
01966 /********************************************************************************************
01967 
01968 >   INT32 TI_GIFFilter::GetGifCompatibility()
01969 
01970     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01971     Created:    24/4/95
01972     Inputs:     -
01973     Returns:    The value we found in the HowCompatible call.
01974                 0 => Not a GIF file.
01975                 10 => It is a GIF file.
01976     Purpose:    Determine if this filter can load the specified file.
01977 
01978 ********************************************************************************************/
01979 
01980 INT32 TI_GIFFilter::GetGifCompatibility()
01981 {
01982     return GIFHowCompatible;
01983 }
01984 
01985 /********************************************************************************************
01986 
01987 >   virtual BOOL TI_GIFFilter::WriteBitmapToFile(KernelBitmap* pKernelBitmap, double Dpi)
01988 
01989     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01990     Created:    25/4/95
01991     Inputs:     Pointer to the bitmap to save.
01992                 Dpi of the bitmap to be saved
01993     Returns:    TRUE if worked, FALSE if errored.
01994     Purpose:    Physically put the bitmap into the disk.  Inherited classes override this to write
01995                 in different file formats.
01996     SeeAlso:    WriteDataToFile(); AccusoftFilters::WriteToFile; AccusoftFilters::WriteDataToFile;
01997 
01998 ********************************************************************************************/
01999 
02000 BOOL TI_GIFFilter::WriteBitmapToFile(KernelBitmap* pKernelBitmap, double Dpi)
02001 {
02002     ERROR2IF(pKernelBitmap == NULL,FALSE,"TI_GIFFilter::WriteBitmapToFile null bitmap pointer specified");
02003 
02004     // Get a pointer to the actual bitmap so that we can get some details from it.
02005     OILBitmap *pOilBitmap = pKernelBitmap->ActualBitmap;
02006     ERROR2IF(pOilBitmap == NULL,FALSE,"TI_GIFFilter::WriteBitmapToFile null oil bitmap pointer");
02007 
02008     // Now get the pointer to the info header and actual bits data.
02009     // Need to use the actual bitmap pointer
02010     CWxBitmap* pWBitmap = (CWxBitmap*)pOilBitmap;
02011     LPBITMAPINFO pInfo = pWBitmap->BMInfo;
02012     LPBYTE pBytes = pWBitmap->BMBytes;
02013 //  UINT32 Bpp = pWBitmap->GetBPP();
02014 
02015     // Now, save the data out showing the correct progress string
02016     String_64 ProgressString(ExportingMsgID);
02017     BOOL ok = FALSE;
02018 
02019     ok = WriteToFile(OutputFile, pInfo, pBytes, &ProgressString);
02020     
02021     return ok;
02022 }
02023 
02024 /********************************************************************************************
02025 
02026 >   virtual BOOL TI_GIFFilter::WriteBitmapToFile(KernelBitmap* pKernelBitmap,
02027                                                  BaseCamelotFilter* pFilter,
02028                                                  CCLexFile* pFile, INT32 Compression);
02029 
02030 
02031     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
02032     Created:    21/6/96
02033     Inputs:     pKernelBitmap   - Pointer to the bitmap to be exported.
02034                 pFilter         - Pointer to the BaseCamelot filter which provides progress functions
02035                 pFile           - Pointer to the CCFile class to use for export
02036                 Compression     - used to flag how much compression of the data is required.
02037     Returns:    TRUE if worked, FALSE if errored.
02038     Purpose:    Physically put the bitmap into the disk.  Inherited classes override this to write
02039                 in different file formats.
02040                 This is used by the native/web format to output the actual bitmap data content
02041                 of a bitmap definition record. The function can assume that the CCFile is open
02042                 and ready for writing and must use the functions provided by pFilter to update
02043                 the progress system.
02044     SeeAlso:    BitmapListComponent::SaveBitmapDefinition;
02045 
02046 ********************************************************************************************/
02047 
02048 BOOL TI_GIFFilter::WriteBitmapToFile(KernelBitmap* pKernelBitmap, BaseCamelotFilter *pFilter,
02049                                          CCLexFile* pFile, INT32 Compression)
02050 {
02051     ERROR2IF(pKernelBitmap == NULL,FALSE, "TI_GIFFilter::WriteBitmapToFile null pKernelBitmap");
02052     ERROR2IF(pFilter == NULL,FALSE, "TI_GIFFilter::WriteBitmapToFile null pFilter");
02053     ERROR2IF(pFile == NULL,FALSE, "TI_GIFFilter::WriteBitmapToFile null pFile");
02054 
02055     // Get a pointer to the actual bitmap so that we can get some details from it.
02056     OILBitmap *pOilBitmap = pKernelBitmap->ActualBitmap;
02057     ERROR2IF(pOilBitmap == NULL,FALSE,"TI_GIFFilter::WriteBitmapToFile null oil bitmap pointer");
02058 
02059     // Now get the pointer to the info header and actual bits data.
02060     // Need to use the actual bitmap pointer
02061     CWxBitmap* pWBitmap = (CWxBitmap*)pOilBitmap;
02062     LPBITMAPINFO Info = pWBitmap->BMInfo;
02063     LPBYTE Bytes = pWBitmap->BMBytes;
02064     UINT32 Bpp = pWBitmap->GetBPP();
02065 
02066     // Now, save the data out showing the correct progress string
02067     BOOL ok = FALSE;
02068     // We must output with no interlacing and no transparency as otherwise things like
02069     // the progress bar update will be screwed, so force the filter type to be simple.
02070     s_FilterType = TI_GIF;
02071 
02072     BOOL Interlace = FALSE; // Don't use interlacing by default
02073     INT32 Transparent = -1; // colour or -1 = no transparency
02074     if (Bpp <= 8)
02075         pOilBitmap->GetTransparencyIndex(&Transparent);
02076 
02077     // Write to file, using pFilter for progress bar updates
02078     ok = WriteToFile(pFile, Info, Bytes, Interlace, Transparent, pFilter);
02079     
02080     return ok;
02081 }
02082 
02083 
02084 /********************************************************************************************
02085 
02086 >   virtual BOOL TI_GIFFilter::IsThisBppOk(UINT32 Bpp)
02087 
02088     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
02089     Created:    27/4/95
02090     Inputs:     Bpp or Colour depth.
02091     Returns:    TRUE if this filter can cope with this colour depth, FALSE otherwise.
02092     Purpose:    Check if this Bitmap filter can cope with saving at this Bpp/Colour depth.
02093     SeeAlso:    OpMenuExport::DoWithParam;
02094 
02095 ********************************************************************************************/
02096 
02097 BOOL TI_GIFFilter::IsThisBppOk(UINT32 Bpp)
02098 {
02099     // Webster - RanbirR
02100     // Animated GIF's do not support 24 colour bitmaps.
02101     // However, allow this format here, since we later convert to 8 Bpp.
02102             
02103     return (Bpp == 24 || Bpp == 8 || Bpp == 4 || Bpp == 1);
02104 }
02105 
02106 /********************************************************************************************
02107 
02108 >   BOOL TI_GIFFilter::WriteToFile ( CCLexFile *File, LPBITMAPINFO Info, LPBYTE Bits,
02109                                      BOOL Interlace, INT32 Transparent,
02110                                      BaseCamelotFilter *pFilter = NULL )
02111 
02112     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
02113     Created:    11/7/96
02114     Inputs:     File        An opened CCFile that can be written to. It should be positioned at the
02115                             start. Caller is responsible for closing it. The file needs to be in
02116                             Binary mode.
02117                 Info        BITMAPINFO structure for the dib.
02118                 Bits        The bitmap data itself
02119                 Interlace   True if want interlacing, false otherwise
02120                 Transparent -1 if no transparent colour required, 0 to maximum palette entry
02121                             to specify the transparent palette entry
02122                 pFilter     is an alternative way of handling the progress bar, assume the
02123                             progress bar has been start and just call the IncProgressBarCount in 
02124                             BaseCamelotFilter to do the progress bar update.
02125                             Defaults to NULL i.e. no progress bar.
02126     Outputs:    -
02127     Returns:    TRUE if worked, FALSE if failed (error will be set accordingly but not reported)
02128     Purpose:    Write a bitmap in memory straight out as a GIF to file with no rendering or
02129                 conversion between different colour depths (apart from 32 to 24) or resolution.
02130                 ***Errors on 16-bit builds***
02131                 A progress hourglass can be shown if required.
02132                 This function is used by the native/web file format to save a bitmap as a GIF
02133                 directly into the file. Hence why it needs to be completely different to the 
02134                 version below which is used for extras like saving animated gifs.
02135                 (caller should close file)
02136     Errors:     Calls SetError on FALSE returns.
02137     Scope:      Static
02138     SeeAlso:    AccusoftFilters::WriteToFile; DIBUtil::WriteToFile;
02139 
02140 ********************************************************************************************/
02141 
02142 BOOL TI_GIFFilter::WriteToFile( CCLexFile *File, LPBITMAPINFO Info, LPBYTE Bits,
02143                                 BOOL Interlace, INT32 Transparent,
02144                                 BaseCamelotFilter *pFilter )
02145 {
02146     ERROR2IF(File==NULL,FALSE,"TI_GIFFilter::WriteToFile File pointer is null");
02147     ERROR2IF(Info==NULL,FALSE,"TI_GIFFilter::WriteToFile BitmapInfo pointer is null");
02148     ERROR2IF(Bits==NULL,FALSE,"TI_GIFFilter::WriteToFile Bits pointer is null");
02149 
02150     // BITMAPINFO  consists of:-
02151     //      BITMAPINFOHEADER    bmiHeader;
02152     //      RGBQUAD             bmiColors[1];
02153     LPBITMAPINFOHEADER pInfoHeader = &Info->bmiHeader;
02154     ERROR2IF(pInfoHeader==NULL,FALSE,"TI_GIFFilter::WriteToFile BitmapInfoHeader pointer is null");
02155         
02156     LPRGBQUAD pPalette = &(Info->bmiColors[0]);
02157     ERROR2IF(pPalette==NULL,FALSE,"TI_GIFFilter::WriteToFile palette pointer is null");
02158 
02159     // Output the GIF data
02160     BOOL ok = TRUE;
02161     if (Transparent == -1)
02162         ok = DestGIF.OutputGifFileHeader(File, pInfoHeader, FALSE, -1, NULL, pPalette);
02163     else
02164         ok = DestGIF.OutputGifFileHeader(File, pInfoHeader, TRUE, Transparent, NULL, pPalette);
02165     if (ok && Transparent != -1)
02166         ok = DestGIF.OutputGifImageExtensionHeader(File, Interlace, Transparent, 0, 0);
02167     if (ok)
02168         ok = DestGIF.OutputGifImageBits(File, Bits, Interlace, FALSE, pFilter);
02169     
02170     if (ok)
02171         ok = DestGIF.OutputGifTerminator(File);
02172 
02173     DestGIF.TidyUp();
02174     
02175     return ok;
02176 }
02177 
02178 /********************************************************************************************
02179 
02180 >   BOOL TI_GIFFilter::WriteToFile ( CCLexFile *File, LPBITMAPINFO Info, LPBYTE Bits,
02181                                      String_64 *ProgressString = NULL)
02182 
02183     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
02184     Created:    26/4/95
02185     Inputs:     File    An opened CCFile that can be written to. It should be positioned at the
02186                         start. Caller is responsible for closing it. The file needs to be in
02187                         Binary mode.
02188                 Info    BITMAPINFO structure for the dib.
02189                 Bits    The bitmap data itself
02190                 ProgressString allows the user to specify whether they require a progress
02191                         hourglass or not. If NULL then none is shown, otherwise an progress bar 
02192                         is shown using the text supplied. Defaults to NULL i.e. no progress bar.
02193     Outputs:    -
02194     Returns:    TRUE if worked, FALSE if failed (error will be set accordingly but not reported)
02195     Purpose:    Write a bitmap in memory straight out as a GIF to file with no rendering or
02196                 conversion between different colour depths (apart from 32 to 24) or resolution.
02197                 ***Errors on 16-bit builds***
02198                 A progress hourglass can be shown if required.
02199                 This function is used by the save bitmap button on the bitmap gallery. All
02200                 other bitmap export uses the OutputDIB class instead as this copes with using
02201                 a render region and converting from 32 to the destination format.
02202                 (caller should close file)
02203     Errors:     Calls SetError on FALSE returns.
02204     Scope:      Static
02205     SeeAlso:    AccusoftFilters::WriteToFile; DIBUtil::WriteToFile;
02206 
02207 ********************************************************************************************/
02208 
02209 BOOL TI_GIFFilter::WriteToFile( CCLexFile *File, LPBITMAPINFO Info, LPBYTE Bits,
02210                                 String_64 *ProgressString)
02211 {
02212     ERROR2IF(File==NULL,FALSE,"TI_GIFFilter::WriteToFile File pointer is null");
02213     ERROR2IF(Info==NULL,FALSE,"TI_GIFFilter::WriteToFile BitmapInfo pointer is null");
02214     ERROR2IF(Bits==NULL,FALSE,"TI_GIFFilter::WriteToFile Bits pointer is null");
02215 
02216     // If the caller has specified a string then assume they require a progress bar
02217     // Start it up.
02218     if (ProgressString != NULL)
02219         BeginSlowJob(100, FALSE, ProgressString);
02220 
02221     // BITMAPINFO  consists of:-
02222     //      BITMAPINFOHEADER    bmiHeader;
02223     //      RGBQUAD             bmiColors[1];
02224     LPBITMAPINFOHEADER pInfoHeader = &Info->bmiHeader;
02225     ERROR2IF(pInfoHeader==NULL,FALSE,"TI_GIFFilter::WriteToFile BitmapInfoHeader pointer is null");
02226         
02227     LPRGBQUAD pPalette = &(Info->bmiColors[0]);
02228     ERROR2IF(pPalette==NULL,FALSE,"TI_GIFFilter::WriteToFile palette pointer is null");
02229 
02230     // Set up our format type flags.
02231     BOOL Interlace = TRUE;  // Use interlace or not
02232     INT32 Transparent = -1; // colour or -1 = no transparency
02233     BOOL MakeTransparent = FALSE;
02234 
02235     switch (s_FilterType)
02236     {
02237         default:
02238         case TI_GIF:
02239             Interlace       = FALSE;
02240             MakeTransparent = FALSE;
02241             break;
02242         case TI_GIF_INTERLACED:
02243             Interlace       = TRUE;
02244             MakeTransparent = FALSE;
02245             break;
02246         case TI_GIF_TRANSPARENT:
02247             Interlace       = FALSE;
02248             MakeTransparent = TRUE;
02249             break;
02250         case TI_GIF_TRANSINTER:
02251             Interlace       = TRUE;
02252             MakeTransparent = TRUE;
02253             break;
02254     }
02255 TRACEUSER( "Neville", _T("TI_GIFFilter::WriteToFile FilterType = %d\n"),s_FilterType);
02256 TRACEUSER( "Neville", _T("TI_GIFFilter::WriteToFile Interlace = %d\n"),Interlace);
02257 TRACEUSER( "Neville", _T("TI_GIFFilter::WriteToFile Transparent = %d\n"),Transparent);
02258 
02259     if (MakeTransparent)
02260     {
02261         // We want to try and output the transparency if possible ...
02262 
02263         // Scan through the palette, and try and find an index with
02264         // the transparency flag set
02265 
02266         Transparent = -1;   // -1 = no transparency
02267         INT32 cols = Info->bmiHeader.biClrUsed;
02268         // If we have zero colours on a bitmap which is 8bpp or less then this is bad.
02269         // This should be translated as the maximum number of colours allowed
02270         if (Info->bmiHeader.biBitCount <= 8 && cols == 0)
02271             cols = 1 << Info->bmiHeader.biBitCount;
02272 
02273         for (INT32 i = 0; i < cols; i++)
02274         {
02275             if (Info->bmiColors[i].rgbReserved == 0xFF)
02276             {
02277                 Transparent = i;
02278                 TRACEUSER( "Neville", _T("GIF output with transp index of %d\n"),Transparent);
02279                 break;
02280             }       
02281         }   
02282 
02283         // WEBSTER - markn 5/2/97
02284         // If we were unable to find the transparent colour, don't save out a transparent image
02285         if (Transparent == -1)
02286             MakeTransparent = FALSE;
02287     }
02288 
02289 TRACEUSER( "Neville", _T("TI_GIFFilter::WriteToFile FilterType = %d\n"),s_FilterType);
02290 TRACEUSER( "Neville", _T("TI_GIFFilter::WriteToFile Interlace = %d\n"),Interlace);
02291 TRACEUSER( "Neville", _T("TI_GIFFilter::WriteToFile Transparent = %d\n"),Transparent);
02292 
02293     // Output the GIF data
02294     BOOL ok = TRUE;
02295     // WEBSTER - markn 5/2/97
02296     // Bug fix - passes the transparent colour index to OutputGifImageExtensionHeader() instead of TRUE
02297     // and also the 'if' statements use the 'MakeTransparent' flag
02298     if (!MakeTransparent)
02299         ok = DestGIF.OutputGifFileHeader(File, pInfoHeader, FALSE, -1, NULL, pPalette);
02300     else
02301     {
02302                 ok = DestGIF.OutputGifFileHeader(File, pInfoHeader, TRUE, Transparent, NULL, pPalette);
02303         if (ok) ok = DestGIF.OutputGifImageExtensionHeader(File, Interlace, Transparent, 0, 0);
02304     }
02305 
02306 //  if (Transparent == -1)
02307 //      ok = DestGIF.OutputGifFileHeader(File, pInfoHeader, FALSE, -1, NULL, pPalette);
02308 //  else
02309 //      ok = DestGIF.OutputGifFileHeader(File, pInfoHeader, TRUE, Transparent, NULL, pPalette);
02310 //  if (ok && Transparent)
02311 //      ok = DestGIF.OutputGifImageExtensionHeader(File, Interlace, TRUE, 0, 0);
02312 
02313     if (ok)
02314         ok = DestGIF.OutputGifImageBits(File, Bits, Interlace, FALSE);
02315     
02316     DestGIF.TidyUp();
02317     
02318     // If started, then stop then progress bar
02319     if (ProgressString != NULL)
02320         EndSlowJob();
02321 
02322     return ok;
02323 }
02324 
02325 
02326 void TI_GIFFilter::AlterPaletteContents( LPLOGPALETTE pPalette )
02327 {
02328     DestGIF.AlterExportPalette( pPalette );
02329 }
02330 
02331 /********************************************************************************************
02332 >   virtual BOOL TI_GIFFilter::WriteFileHeader(void)
02333 
02334     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
02335     Created:    12/6/96
02336     Inputs:     -
02337     Returns:    FALSE if failed else TRUE
02338     Purpose:    To write out the file specific header data
02339 ********************************************************************************************/
02340 BOOL TI_GIFFilter::WriteFileHeader(void)
02341 {
02342     m_AnimationFrame = 0;
02343     return(TRUE);   
02344 }
02345 
02346 
02347 /********************************************************************************************
02348 >   virtual BOOL TI_GIFFilter::WritePreFrame(void)
02349 
02350     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
02351     Created:    12/6/96
02352     Inputs:     -
02353     Returns:    FALSE if failed else TRUE
02354     Purpose:    To write out any frame specific info before the image
02355 ********************************************************************************************/
02356 BOOL TI_GIFFilter::WritePreFrame(void)
02357 {
02358     return DestGIF.ReStartFile(NULL);
02359 }
02360 
02361 
02362 /********************************************************************************************
02363 >   virtual BOOL TI_GIFFilter::WriteFrame(void)
02364 
02365     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
02366     Created:    12/6/96
02367     Inputs:     -
02368     Returns:    FALSE if failed else TRUE
02369     Purpose:    To write out the image itself
02370                 This base class version actually calls the WriteToFile() function so that
02371                 derived classes do not have to implement any of the multi-image stuff
02372 ********************************************************************************************/
02373 BOOL TI_GIFFilter::WriteFrame(void)
02374 {
02375     return MaskedFilter::WriteToFile ( TRUE );
02376 }
02377 
02378 
02379 /********************************************************************************************
02380 >   virtual BOOL TI_GIFFilter::WritePostFrame(void)
02381 
02382     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
02383     Created:    12/6/96
02384     Inputs:     -
02385     Returns:    FALSE if failed else TRUE
02386     Purpose:    To write out any frame specific info after the image
02387 ********************************************************************************************/
02388 BOOL TI_GIFFilter::WritePostFrame(void)
02389 {
02390     BOOL ok = EndWriteToFile();
02391 
02392     if (m_DoingAnimation)
02393         m_AnimationFrame++;
02394 
02395     return ok;
02396 }
02397 
02398 
02399 /********************************************************************************************
02400 >   virtual BOOL TI_GIFFilter::WriteFileEnd(void)
02401 
02402     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
02403     Created:    12/6/96
02404     Inputs:     -
02405     Returns:    FALSE if failed else TRUE
02406     Purpose:    To write out the file specific data at the end of the file
02407                 This base class version calls EndWriteToFile() so that derived classes
02408                 do not have to implement the multi-image stuff
02409 ********************************************************************************************/
02410 BOOL TI_GIFFilter::WriteFileEnd(void)
02411 {
02412     /*BOOL ok =*/ DestGIF.OutputGifTerminator(OutputFile);
02413     return DestGIF.TidyUp();
02414 }
02415 
02416 
02417 /********************************************************************************************
02418 >   virtual BOOL TI_GIFFilter::WritePreSecondPass(void)
02419 
02420     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
02421     Created:    17/6/96
02422     Inputs:     -
02423     Returns:    FALSE if failed else TRUE
02424     Purpose:    Called to do any processing required after the first and before the second
02425                 pass of a two pass export
02426 ********************************************************************************************/
02427 BOOL TI_GIFFilter::WritePreSecondPass(void)
02428 {
02429     return EndWriteToFile();
02430 }
02431 
02432 
02433 
02434 /********************************************************************************************
02435 >   virtual BOOL TI_GIFFilter::WritePostOptimisedPalette(void)
02436 
02437     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
02438     Created:    17/6/96
02439     Inputs:     -
02440     Returns:    FALSE if failed else TRUE
02441     Purpose:    Called after an optimised palette has been generated
02442 ********************************************************************************************/
02443 BOOL TI_GIFFilter::WritePostOptimisedPalette(void)
02444 {
02445     if (m_AnimationFrame > 0)
02446         return DestGIF.ReStartFile(pOptimisedPalette);
02447     else
02448         return TRUE;
02449 }
02450 
02451 
02452 
02453 /********************************************************************************************
02454 >   BOOL TI_GIFFilter::ShouldReuseExistingBitmaps()
02455 
02456     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02457     Created:    17/6/96
02458     Returns:    True if this filter should try and reuse existing bitmaps during import
02459     Purpose:    Determines whether or not to re-use existing bitmap.
02460                 Animation Import will say no, so that frames that are same still appear
02461                 more than once.
02462 ********************************************************************************************/
02463 BOOL TI_GIFFilter::ShouldReuseExistingBitmaps()
02464 {
02465     return (GetBitmapNumber() <= 1);
02466 }
02467 
02468 /********************************************************************************************
02469 
02470 >   virtual OutputDIB* TI_GIFFilter::GetOutputDIB ( void )
02471 
02472     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
02473     Created:    27/6/00
02474     Returns     OutputDIB* - A pointer to DestGIF.
02475     Purpose:    Casts the current output DIB to be a generic OutputDIB class. This allows the
02476                 same code to be re-used in the base class.
02477 
02478 ********************************************************************************************/
02479 
02480 OutputDIB* TI_GIFFilter::GetOutputDIB ( void )
02481 {
02482     // Perform an upcast to allow the pointer to be used in a generic manner.
02483     return static_cast<OutputDIB*> ( &DestGIF );
02484 }
02485 
02486 /********************************************************************************************
02487 
02488 >   virtual BitmapExportOptions* TI_GIFFilter::CreateExportOptions() const
02489 
02490     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
02491     Created:    29/10/96
02492     Returns:    A pointer to a new BitmapExportInfo class
02493     Purpose:    Allows derived classes to override this function to provide their own class
02494                 derived from BitmapExportInfo containing filter specific information.
02495 
02496 ********************************************************************************************/
02497 BitmapExportOptions* TI_GIFFilter::CreateExportOptions() const
02498 {
02499     GIFExportOptions* pGIFOptions = new GIFExportOptions(TI_GIF, &FilterName);
02500 
02501     return (BitmapExportOptions*)pGIFOptions;
02502 }
02503 
02504 
02505 /********************************************************************************************
02506 
02507 >   virtual UINT32 TI_GIFFilter::GetHintType(void)
02508 
02509     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
02510     Created:    27/07/97
02511     Purpose:    Base class sets bad so no hint is set
02512 
02513 ********************************************************************************************/
02514 
02515 UINT32 TI_GIFFilter::GetHintType(void)
02516 {
02517     return(HINTTYPE_GIF);
02518 }
02519 
02520 /********************************************************************************************
02521 
02522   > virtual BOOL TI_GIFFilter::IsDefaultDocRequired(const TCHAR* pcszPathName);
02523 
02524     Author:     Graham_Walmsley (Xara Group Ltd) <camelotdev@xara.com>
02525     Created:    5/11/97
02526     Purpose:    Is called when a TIFF or GIF is opened, to let us say whether we
02527                             need a default document.
02528 
02529                             We need to open GIFs into the Animated template (in case they're
02530                             animated). We do this as follows: we tell the Document system
02531                             that the next template to use is the animation template. Then 
02532                             we return TRUE so that this template is loaded.
02533 
02534                             Not very elegant, but it works.
02535 ********************************************************************************************/
02536 
02537 BOOL TI_GIFFilter::IsDefaultDocRequired(const TCHAR* pcszPathName)
02538 {
02539     //Tell the system to use the default animation template
02540     CCamDoc::SetNextTemplateToUse( CTemplateManager::GetDefaultAnimationTemplate() );
02541 
02542     return TRUE;
02543 }
02544 
02545 
02546 
02547 
02548 /*******************************************************************************************
02550 ********************************************************************************************/
02551 
02552 
02553 
02554 /********************************************************************************************
02555 
02556 >   AnimatedGIFImage::AnimatedGIFImage(const INT32 TransColour, const GIFDisposalMethod FrameRestore,
02557                                        const CENTISECONDS FrameDelay,
02558                                        const UINT32 LeftOffset, const UINT32 TopOffset,
02559                                        const LPBITMAPINFO pInfo, const LPBYTE pBytes,
02560                                        const LPBITMAPINFO pDiffInfo = NULL, const LPBYTE pDiffBytes = NULL)
02561 
02562     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
02563     Created:    2/6/97
02564     Inputs:     TransColour     - the transparent colour for this frame
02565                 FrameRestore    - The restore type for this frame
02566                 FrameDelay      - the delay to apply to this frame
02567                 LeftOffset, TopOffset   - offset for the bitmap
02568                 pInfo, pBytes   - The bitmap to output for this frame
02569                 pDiffInfo, pDiffBytes   - The difference bitmap for this frame
02570     Purpose:    To add a bitmap to the list of frames in the animation sequence.
02571 
02572 ********************************************************************************************/
02573 
02574 AnimatedGIFImage::AnimatedGIFImage(const INT32 TransColour, const GIFDisposalMethod FrameRestore,
02575                                    const CENTISECONDS FrameDelay,
02576                                    const UINT32 LeftOffset, const UINT32 TopOffset,
02577                                    const LPBITMAPINFO pInfo, const LPBYTE pBytes,
02578                                    const LPBITMAPINFO pDiffInfo, const LPBYTE pDiffBytes)
02579 {
02580     m_TransColour   = TransColour;
02581     m_FrameRestore  = FrameRestore;
02582     m_FrameDelay    = FrameDelay;
02583 
02584     m_LeftOffset    = LeftOffset;
02585     m_TopOffset     = TopOffset;
02586 
02587     m_pInfo         = pInfo;
02588     m_pBytes        = pBytes;
02589     m_pDiffInfo     = pDiffInfo;
02590     m_pDiffBytes    = pDiffBytes;
02591 }
02592 
02593 /********************************************************************************************
02594 
02595 >   AnimatedGIFImage::AnimatedGIFImage()
02596 
02597     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
02598     Created:    2/6/97
02599     Purpose:    Default contructor.
02600 
02601 ********************************************************************************************/
02602 
02603 AnimatedGIFImage::AnimatedGIFImage()
02604 {
02605     ERROR3("AnimatedGIFImage::AnimatedGIFImage - call the other constructor");
02606     m_TransColour   = -1;
02607     m_FrameRestore  = GDM_LEAVE;
02608     m_FrameDelay    = 0;
02609 
02610     m_LeftOffset    = 0;
02611     m_TopOffset     = 0;
02612 
02613     m_pInfo         = NULL;
02614     m_pBytes        = NULL;
02615     m_pDiffInfo     = NULL;
02616     m_pDiffBytes    = NULL;
02617 }
02618 
02619 /********************************************************************************************
02620 
02621 >   AnimatedGIFImage::~AnimatedGIFImage()
02622 
02623     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
02624     Created:    2/6/97
02625     Purpose:    Default destructor
02626 
02627 ********************************************************************************************/
02628 
02629 AnimatedGIFImage::~AnimatedGIFImage()
02630 {
02631     // Free up the difference bitmap that may have allocated
02632     if (m_pDiffInfo && m_pDiffBytes)
02633     {
02634         FreeDIB(m_pDiffInfo, m_pDiffBytes);
02635         m_pDiffInfo = NULL;
02636         m_pDiffBytes = NULL;
02637     }
02638 }
02639 
02640 /*******************************************************************************************
02642 ********************************************************************************************/

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