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 ********************************************************************************************/