1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: egif.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_goodies.hxx"
34 #include <vcl/graph.hxx>
35 #include <vcl/svapp.hxx>
36 #include <vcl/msgbox.hxx>
37 #include <vcl/window.hxx>
38 #include <svtools/solar.hrc>
39 #include <svtools/fltcall.hxx>
40 #include <svtools/FilterConfigItem.hxx>
41 #include "giflzwc.hxx"
42 #include "strings.hrc"
43 #include "dlgegif.hrc"
44 #include "dlgegif.hxx"
53 BitmapReadAccess
* pAcc
;
60 sal_Int32 nInterlaced
;
64 void MayCallback( ULONG nPercent
);
65 void WriteSignature( BOOL bGIF89a
);
66 void WriteGlobalHeader( const Size
& rSize
);
67 void WriteLoopExtension( const Animation
& rAnimation
);
68 void WriteLogSizeExtension( const Size
& rSize100
);
69 void WriteImageExtension( long nTimer
, Disposal eDisposal
);
70 void WriteLocalHeader();
73 void WriteTerminator();
75 BOOL
CreateAccess( const BitmapEx
& rBmpEx
);
78 void WriteAnimation( const Animation
& rAnimation
);
79 void WriteBitmapEx( const BitmapEx
& rBmpEx
, const Point
& rPoint
, BOOL bExtended
,
80 long nTimer
= 0, Disposal eDisposal
= DISPOSE_NOT
);
82 com::sun::star::uno::Reference
< com::sun::star::task::XStatusIndicator
> xStatusIndicator
;
89 BOOL
WriteGIF( const Graphic
& rGraphic
, SvStream
& rGIF
,
90 FilterConfigItem
* pConfigItem
);
93 // ------------------------------------------------------------------------
95 BOOL
GIFWriter::WriteGIF( const Graphic
& rGraphic
, SvStream
& rGIF
,
96 FilterConfigItem
* pFilterConfigItem
)
98 if ( pFilterConfigItem
)
100 xStatusIndicator
= pFilterConfigItem
->GetStatusIndicator();
101 if ( xStatusIndicator
.is() )
104 xStatusIndicator
->start( aMsg
, 100 );
109 const MapMode
aMap( rGraphic
.GetPrefMapMode() );
110 BOOL bLogSize
= ( aMap
.GetMapUnit() != MAP_PIXEL
);
113 aSize100
= Application::GetDefaultDevice()->LogicToLogic( rGraphic
.GetPrefSize(), aMap
, MAP_100TH_MM
);
121 if ( pFilterConfigItem
)
122 nInterlaced
= pFilterConfigItem
->ReadInt32( String( RTL_CONSTASCII_USTRINGPARAM( "Interlaced" ) ), 0 );
124 pGIF
->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN
);
126 if( rGraphic
.IsAnimated() )
128 const Animation
& rAnimation
= rGraphic
.GetAnimation();
130 WriteSignature( TRUE
);
134 WriteGlobalHeader( rAnimation
.GetDisplaySizePixel() );
138 WriteLoopExtension( rAnimation
);
141 WriteAnimation( rAnimation
);
147 const BOOL bGrafTrans
= rGraphic
.IsTransparent();
152 aBmpEx
= rGraphic
.GetBitmapEx();
154 aBmpEx
= BitmapEx( rGraphic
.GetBitmap() );
159 WriteSignature( bGrafTrans
|| bLogSize
);
163 WriteGlobalHeader( aBmpEx
.GetSizePixel() );
166 WriteBitmapEx( aBmpEx
, Point(), bGrafTrans
);
173 WriteLogSizeExtension( aSize100
);
178 if ( xStatusIndicator
.is() )
179 xStatusIndicator
->end();
184 // ------------------------------------------------------------------------
186 void GIFWriter::WriteBitmapEx( const BitmapEx
& rBmpEx
, const Point
& rPoint
,
187 BOOL bExtended
, long nTimer
, Disposal eDisposal
)
189 if( CreateAccess( rBmpEx
) )
195 WriteImageExtension( nTimer
, eDisposal
);
214 // ------------------------------------------------------------------------
216 void GIFWriter::WriteAnimation( const Animation
& rAnimation
)
218 const USHORT nCount
= rAnimation
.Count();
222 const double fStep
= 100. / nCount
;
225 nMaxPercent
= (ULONG
) fStep
;
227 for( USHORT i
= 0; i
< nCount
; i
++ )
229 const AnimationBitmap
& rAnimBmp
= rAnimation
.Get( i
);
231 WriteBitmapEx( rAnimBmp
.aBmpEx
, rAnimBmp
.aPosPix
, TRUE
,
232 rAnimBmp
.nWait
, rAnimBmp
.eDisposal
);
233 nMinPercent
= nMaxPercent
;
234 nMaxPercent
= (ULONG
) ( nMaxPercent
+ fStep
);
239 // ------------------------------------------------------------------------
241 void GIFWriter::MayCallback( ULONG nPercent
)
243 if ( xStatusIndicator
.is() )
245 if( nPercent
>= nLastPercent
+ 3 )
247 nLastPercent
= nPercent
;
248 if ( nPercent
<= 100 )
249 xStatusIndicator
->setValue( nPercent
);
254 // ------------------------------------------------------------------------
256 BOOL
GIFWriter::CreateAccess( const BitmapEx
& rBmpEx
)
260 Bitmap
aMask( rBmpEx
.GetMask() );
262 aAccBmp
= rBmpEx
.GetBitmap();
263 bTransparent
= FALSE
;
267 if( aAccBmp
.Convert( BMP_CONVERSION_8BIT_TRANS
) )
269 aMask
.Convert( BMP_CONVERSION_1BIT_THRESHOLD
);
270 aAccBmp
.Replace( aMask
, BMP_COL_TRANS
);
274 aAccBmp
.Convert( BMP_CONVERSION_8BIT_COLORS
);
277 aAccBmp
.Convert( BMP_CONVERSION_8BIT_COLORS
);
279 pAcc
= aAccBmp
.AcquireReadAccess();
288 // ------------------------------------------------------------------------
290 void GIFWriter::DestroyAccess()
292 aAccBmp
.ReleaseAccess( pAcc
);
296 // ------------------------------------------------------------------------
298 void GIFWriter::WriteSignature( BOOL bGIF89a
)
302 pGIF
->Write( bGIF89a
? "GIF89a" : "GIF87a" , 6 );
304 if( pGIF
->GetError() )
309 // ------------------------------------------------------------------------
311 void GIFWriter::WriteGlobalHeader( const Size
& rSize
)
316 const UINT16 nWidth
= (UINT16
) rSize
.Width();
317 const UINT16 nHeight
= (UINT16
) rSize
.Height();
318 const BYTE cFlags
= 128 | ( 7 << 4 );
320 // Werte rausschreiben
324 *pGIF
<< (BYTE
) 0x00;
325 *pGIF
<< (BYTE
) 0x00;
327 // Dummy-Palette mit zwei Eintraegen (Schwarz/Weiss) schreiben;
328 // dieses nur wegen Photoshop-Bug, da die keine Bilder ohne
329 // globale Farbpalette lesen koennen
331 *pGIF
<< (UINT16
) 255;
332 *pGIF
<< (UINT16
) 65535;
334 if( pGIF
->GetError() )
339 // ------------------------------------------------------------------------
341 void GIFWriter::WriteLoopExtension( const Animation
& rAnimation
)
343 DBG_ASSERT( rAnimation
.Count() > 0, "Animation has no bitmaps!" );
345 USHORT nLoopCount
= (USHORT
) rAnimation
.GetLoopCount();
347 // falls nur ein Durchlauf stattfinden soll,
348 // wird keine LoopExtension geschrieben;
349 // Default ist dann immer ein Durchlauf
350 if( nLoopCount
!= 1 )
352 // Netscape interpretiert den LoopCount
353 // als reine Anzahl der _Wiederholungen_
357 const BYTE cLoByte
= (const BYTE
) nLoopCount
;
358 const BYTE cHiByte
= (const BYTE
) ( nLoopCount
>> 8 );
360 *pGIF
<< (BYTE
) 0x21;
361 *pGIF
<< (BYTE
) 0xff;
362 *pGIF
<< (BYTE
) 0x0b;
363 pGIF
->Write( "NETSCAPE2.0", 11 );
364 *pGIF
<< (BYTE
) 0x03;
365 *pGIF
<< (BYTE
) 0x01;
368 *pGIF
<< (BYTE
) 0x00;
372 // ------------------------------------------------------------------------
374 void GIFWriter::WriteLogSizeExtension( const Size
& rSize100
)
376 // PrefSize in 100th-mm als ApplicationExtension schreiben
377 if( rSize100
.Width() && rSize100
.Height() )
379 *pGIF
<< (BYTE
) 0x21;
380 *pGIF
<< (BYTE
) 0xff;
381 *pGIF
<< (BYTE
) 0x0b;
382 pGIF
->Write( "STARDIV 5.0", 11 );
383 *pGIF
<< (BYTE
) 0x09;
384 *pGIF
<< (BYTE
) 0x01;
385 *pGIF
<< (UINT32
) rSize100
.Width();
386 *pGIF
<< (UINT32
) rSize100
.Height();
387 *pGIF
<< (BYTE
) 0x00;
391 // ------------------------------------------------------------------------
393 void GIFWriter::WriteImageExtension( long nTimer
, Disposal eDisposal
)
397 const UINT16 nDelay
= (UINT16
) nTimer
;
400 // Transparent-Flag setzen
404 // Disposal-Wert setzen
405 if( eDisposal
== DISPOSE_BACK
)
406 cFlags
|= ( 2 << 2 );
407 else if( eDisposal
== DISPOSE_PREVIOUS
)
408 cFlags
|= ( 3 << 2 );
410 *pGIF
<< (BYTE
) 0x21;
411 *pGIF
<< (BYTE
) 0xf9;
412 *pGIF
<< (BYTE
) 0x04;
415 *pGIF
<< (BYTE
) pAcc
->GetBestPaletteIndex( BMP_COL_TRANS
);
416 *pGIF
<< (BYTE
) 0x00;
418 if( pGIF
->GetError() )
423 // ------------------------------------------------------------------------
425 void GIFWriter::WriteLocalHeader()
429 const UINT16 nPosX
= (UINT16
) nActX
;
430 const UINT16 nPosY
= (UINT16
) nActY
;
431 const UINT16 nWidth
= (UINT16
) pAcc
->Width();
432 const UINT16 nHeight
= (UINT16
) pAcc
->Height();
433 BYTE cFlags
= (BYTE
) ( pAcc
->GetBitCount() - 1 );
435 // Interlaced-Flag setzen
439 // Flag fuer lokale Farbpalette setzen
442 // alles rausschreiben
443 *pGIF
<< (BYTE
) 0x2c;
450 if( pGIF
->GetError() )
455 // ------------------------------------------------------------------------
457 void GIFWriter::WritePalette()
459 if( bStatus
&& pAcc
->HasPalette() )
461 const USHORT nCount
= pAcc
->GetPaletteEntryCount();
462 const USHORT nMaxCount
= ( 1 << pAcc
->GetBitCount() );
464 for ( USHORT i
= 0; i
< nCount
; i
++ )
466 const BitmapColor
& rColor
= pAcc
->GetPaletteColor( i
);
468 *pGIF
<< rColor
.GetRed();
469 *pGIF
<< rColor
.GetGreen();
470 *pGIF
<< rColor
.GetBlue();
473 // Rest mit 0 auffuellen
474 if( nCount
< nMaxCount
)
475 pGIF
->SeekRel( ( nMaxCount
- nCount
) * 3 );
477 if( pGIF
->GetError() )
482 // ------------------------------------------------------------------------
484 void GIFWriter::WriteAccess()
486 GIFLZWCompressor aCompressor
;
487 const long nWidth
= pAcc
->Width();
488 const long nHeight
= pAcc
->Height();
489 BYTE
* pBuffer
= NULL
;
490 const ULONG nFormat
= pAcc
->GetScanlineFormat();
494 BOOL bNative
= ( BMP_FORMAT_8BIT_PAL
== nFormat
);
497 pBuffer
= new BYTE
[ nWidth
];
499 if( bStatus
&& ( 8 == pAcc
->GetBitCount() ) && pAcc
->HasPalette() )
501 aCompressor
.StartCompression( *pGIF
, pAcc
->GetBitCount() );
503 for( i
= 0; i
< nHeight
; i
++ )
511 nT
= i
- ( ( nHeight
+ 7 ) >> 3 );
516 nT
-= ( nHeight
+ 3 ) >> 3;
517 nY
= ( nT
<< 2 ) + 2;
521 nT
-= ( ( nHeight
+ 1 ) >> 2 );
522 nY
= ( nT
<< 1 ) + 1;
531 aCompressor
.Compress( pAcc
->GetScanline( nY
), nWidth
);
534 for( long nX
= 0L; nX
< nWidth
; nX
++ )
535 pBuffer
[ nX
] = (BYTE
) pAcc
->GetPixel( nY
, nX
);
537 aCompressor
.Compress( pBuffer
, nWidth
);
540 if ( pGIF
->GetError() )
543 MayCallback( nMinPercent
+ ( nMaxPercent
- nMinPercent
) * i
/ nHeight
);
549 aCompressor
.EndCompression();
551 if ( pGIF
->GetError() )
558 // ------------------------------------------------------------------------
560 void GIFWriter::WriteTerminator()
564 *pGIF
<< (BYTE
) 0x3b;
566 if( pGIF
->GetError() )
571 // ------------------------------------------------------------------------
573 extern "C" BOOL __LOADONCALLAPI
GraphicExport( SvStream
& rStream
, Graphic
& rGraphic
,
574 FilterConfigItem
* pConfigItem
, BOOL
)
576 return GIFWriter().WriteGIF( rGraphic
, rStream
, pConfigItem
);
579 // ------------------------------------------------------------------------
581 extern "C" BOOL __LOADONCALLAPI
DoExportDialog( FltCallDialogParameter
& rPara
)
587 ByteString
aResMgrName( "egi" );
590 pResMgr
= ResMgr::CreateResMgr( aResMgrName
.GetBuffer(), Application::GetSettings().GetUILocale() );
594 rPara
.pResMgr
= pResMgr
;
595 bRet
= ( DlgExportEGIF( rPara
).Execute() == RET_OK
);
605 // ------------------------------------------------------------------------
611 static HINSTANCE hDLLInst
= 0;
613 extern "C" int CALLBACK
LibMain( HINSTANCE hDLL
, WORD
, WORD nHeap
, LPSTR
)
625 // ------------------------------------------------------------------------
627 extern "C" int CALLBACK
WEP( int )