merge the formfield patch from ooo-build
[ooovba.git] / svtools / source / filter.vcl / igif / gifread.cxx
blob1fa752c0397ecf98922c323693b9080668f268fa
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: gifread.cxx,v $
10 * $Revision: 1.8 $
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_svtools.hxx"
34 #define _GIFPRIVATE
36 #include "decode.hxx"
37 #include "gifread.hxx"
39 // -----------
40 // - Defines -
41 // -----------
43 #define NO_PENDING( rStm ) ( ( rStm ).GetError() != ERRCODE_IO_PENDING )
45 // -------------
46 // - GIFReader -
47 // -------------
49 GIFReader::GIFReader( SvStream& rStm ) :
50 aGPalette ( 256 ),
51 aLPalette ( 256 ),
52 rIStm ( rStm ),
53 pAcc8 ( NULL ),
54 pAcc1 ( NULL ),
55 nLastPos ( rStm.Tell() ),
56 nLogWidth100 ( 0UL ),
57 nLogHeight100 ( 0UL ),
58 nLoops ( 1 ),
59 eActAction ( GLOBAL_HEADER_READING ),
60 bGCTransparent ( FALSE ),
61 bImGraphicReady ( FALSE )
63 maUpperName = UniString::CreateFromAscii( "SVIGIF", 6 );
64 pSrcBuf = new BYTE[ 256 ];
65 ClearImageExtensions();
68 // ------------------------------------------------------------------------
70 GIFReader::~GIFReader()
72 aImGraphic.SetContext( NULL );
74 if( pAcc1 )
75 aBmp1.ReleaseAccess( pAcc1 );
77 if( pAcc8 )
78 aBmp8.ReleaseAccess( pAcc8 );
80 delete[] pSrcBuf;
83 // ------------------------------------------------------------------------
85 void GIFReader::ClearImageExtensions()
87 nGCDisposalMethod = 0;
88 bGCTransparent = FALSE;
89 nTimer = 0;
92 // ------------------------------------------------------------------------
94 BOOL GIFReader::CreateBitmaps( long nWidth, long nHeight, BitmapPalette* pPal,
95 BOOL bWatchForBackgroundColor )
97 const Size aSize( nWidth, nHeight );
99 if( bGCTransparent )
101 const Color aWhite( COL_WHITE );
103 aBmp1 = Bitmap( aSize, 1 );
105 if( !aAnimation.Count() )
106 aBmp1.Erase( aWhite );
108 pAcc1 = aBmp1.AcquireWriteAccess();
110 if( pAcc1 )
112 cTransIndex1 = (BYTE) pAcc1->GetBestPaletteIndex( aWhite );
113 cNonTransIndex1 = cTransIndex1 ? 0 : 1;
115 else
116 bStatus = FALSE;
119 if( bStatus )
121 aBmp8 = Bitmap( aSize, 8, pPal );
123 if( !!aBmp8 && bWatchForBackgroundColor && aAnimation.Count() )
124 aBmp8.Erase( (*pPal)[ nBackgroundColor ] );
125 else
126 aBmp8.Erase( Color( COL_WHITE ) );
128 pAcc8 = aBmp8.AcquireWriteAccess();
129 bStatus = ( pAcc8 != NULL );
132 return bStatus;
135 // ------------------------------------------------------------------------
137 BOOL GIFReader::ReadGlobalHeader()
139 char pBuf[ 7 ];
140 BYTE nRF;
141 BYTE nAspect;
142 BOOL bRet = FALSE;
144 rIStm.Read( pBuf, 6 );
145 if( NO_PENDING( rIStm ) )
147 pBuf[ 6 ] = 0;
148 if( !strcmp( pBuf, "GIF87a" ) || !strcmp( pBuf, "GIF89a" ) )
150 rIStm.Read( pBuf, 7 );
151 if( NO_PENDING( rIStm ) )
153 SvMemoryStream aMemStm;
155 aMemStm.SetBuffer( pBuf, 7, FALSE, 7 );
156 aMemStm >> nGlobalWidth;
157 aMemStm >> nGlobalHeight;
158 aMemStm >> nRF;
159 aMemStm >> nBackgroundColor;
160 aMemStm >> nAspect;
162 bGlobalPalette = (BOOL) ( nRF & 0x80 );
164 if( bGlobalPalette )
165 ReadPaletteEntries( &aGPalette, 1 << ( ( nRF & 7 ) + 1 ) );
166 else
167 nBackgroundColor = 0;
169 if( NO_PENDING( rIStm ) )
170 bRet = TRUE;
173 else
174 bStatus = FALSE;
177 return bRet;
180 // ------------------------------------------------------------------------
182 void GIFReader::ReadPaletteEntries( BitmapPalette* pPal, ULONG nCount )
184 const ULONG nLen = 3UL * nCount;
185 BYTE* pBuf = new BYTE[ nLen ];
187 rIStm.Read( pBuf, nLen );
188 if( NO_PENDING( rIStm ) )
190 BYTE* pTmp = pBuf;
192 for( ULONG i = 0UL; i < nCount; )
194 BitmapColor& rColor = (*pPal)[ (USHORT) i++ ];
196 rColor.SetRed( *pTmp++ );
197 rColor.SetGreen( *pTmp++ );
198 rColor.SetBlue( *pTmp++ );
201 // nach Moeglichkeit noch einige Standardfarben unterbringen
202 if( nCount < 256UL )
204 (*pPal)[ 255UL ] = Color( COL_WHITE );
206 if( nCount < 255UL )
207 (*pPal)[ 254UL ] = Color( COL_BLACK );
211 delete[] pBuf;
214 // ------------------------------------------------------------------------
216 BOOL GIFReader::ReadExtension()
218 BYTE cFunction;
219 BYTE cSize;
220 BYTE cByte;
221 BOOL bRet = FALSE;
222 BOOL bOverreadDataBlocks = FALSE;
224 // Extension-Label
225 rIStm >> cFunction;
226 if( NO_PENDING( rIStm ) )
228 // Block-Laenge
229 rIStm >> cSize;
231 switch( cFunction )
233 // 'Graphic Control Extension'
234 case( 0xf9 ) :
236 BYTE cFlags;
238 rIStm >> cFlags;
239 rIStm >> nTimer;
240 rIStm >> nGCTransparentIndex;
241 rIStm >> cByte;
243 if ( NO_PENDING( rIStm ) )
245 nGCDisposalMethod = ( cFlags >> 2) & 7;
246 bGCTransparent = ( cFlags & 1 ) ? TRUE : FALSE;
247 bStatus = ( cSize == 4 ) && ( cByte == 0 );
248 bRet = TRUE;
251 break;
253 // Application-Extension
254 case ( 0xff ) :
256 if ( NO_PENDING( rIStm ) )
258 // default diese Extension ueberlesen
259 bOverreadDataBlocks = TRUE;
261 // Appl.-Extension hat Laenge 11
262 if ( cSize == 0x0b )
264 ByteString aAppId;
265 ByteString aAppCode;
267 rIStm.Read( aAppId.AllocBuffer( 8 ), 8 );
268 rIStm.Read( aAppCode.AllocBuffer( 3 ), 3 );
269 rIStm >> cSize;
271 // NetScape-Extension
272 if( aAppId == "NETSCAPE" && aAppCode == "2.0" && cSize == 3 )
274 rIStm >> cByte;
276 // Loop-Extension
277 if ( cByte == 0x01 )
279 rIStm >> cByte;
280 nLoops = cByte;
281 rIStm >> cByte;
282 nLoops |= ( (USHORT) cByte << 8 );
283 rIStm >> cByte;
285 bStatus = ( cByte == 0 );
286 bRet = NO_PENDING( rIStm );
287 bOverreadDataBlocks = FALSE;
289 // Netscape interpretiert den LoopCount
290 // als reine Anzahl der _Wiederholungen_;
291 // bei uns ist es die Gesamtanzahl der
292 // Durchlaeufe
293 if( nLoops )
294 nLoops++;
296 else
297 rIStm.SeekRel( -1 );
299 else if ( aAppId == "STARDIV " && aAppCode == "5.0" && cSize == 9 )
301 rIStm >> cByte;
303 // Loop-Extension
304 if ( cByte == 0x01 )
306 rIStm >> nLogWidth100 >> nLogHeight100;
307 rIStm >> cByte;
308 bStatus = ( cByte == 0 );
309 bRet = NO_PENDING( rIStm );
310 bOverreadDataBlocks = FALSE;
312 else
313 rIStm.SeekRel( -1 );
319 break;
321 // alles andere ueberlesen
322 default:
323 bOverreadDataBlocks = TRUE;
324 break;
327 // Sub-Blocks ueberlesen
328 if ( bOverreadDataBlocks )
330 bRet = TRUE;
331 while( cSize && bStatus && !rIStm.IsEof() )
333 USHORT nCount = (USHORT) cSize + 1;
334 char* pBuffer = new char[ nCount ];
336 bRet = FALSE;
337 rIStm.Read( pBuffer, nCount );
338 if( NO_PENDING( rIStm ) )
340 cSize = (BYTE) pBuffer[ cSize ];
341 bRet = TRUE;
343 else
344 cSize = 0;
346 delete[] pBuffer;
351 return bRet;
354 // ------------------------------------------------------------------------
356 BOOL GIFReader::ReadLocalHeader()
358 BYTE pBuf[ 9 ];
359 BOOL bRet = FALSE;
361 rIStm.Read( pBuf, 9 );
362 if( NO_PENDING( rIStm ) )
364 SvMemoryStream aMemStm;
365 BitmapPalette* pPal;
366 BYTE nFlags;
368 aMemStm.SetBuffer( (char*) pBuf, 9, FALSE, 9 );
369 aMemStm >> nImagePosX;
370 aMemStm >> nImagePosY;
371 aMemStm >> nImageWidth;
372 aMemStm >> nImageHeight;
373 aMemStm >> nFlags;
375 // Falls Interlaced, ersten Startwert vorgeben
376 bInterlaced = ( ( nFlags & 0x40 ) == 0x40 );
377 nLastInterCount = 7;
378 nLastImageY = 0;
380 if( nFlags & 0x80 )
382 pPal = &aLPalette;
383 ReadPaletteEntries( pPal, 1 << ( (nFlags & 7 ) + 1 ) );
385 else
386 pPal = &aGPalette;
388 // Falls alles soweit eingelesen werden konnte, kann
389 // nun das lokale Bild angelegt werden;
390 // es wird uebergeben, ob der BackgroundColorIndex evtl.
391 // beruecksichtigt werden soll ( wenn Globale Farbtab. und
392 // diese auch fuer dieses Bild gilt )
393 if( NO_PENDING( rIStm ) )
395 CreateBitmaps( nImageWidth, nImageHeight, pPal, bGlobalPalette && ( pPal == &aGPalette ) );
396 bRet = TRUE;
400 return bRet;
403 // ------------------------------------------------------------------------
405 ULONG GIFReader::ReadNextBlock()
407 ULONG nRet = 0UL;
408 ULONG nRead;
409 BYTE cBlockSize;
411 rIStm >> cBlockSize;
413 if ( rIStm.IsEof() )
414 nRet = 4UL;
415 else if ( NO_PENDING( rIStm ) )
417 if ( cBlockSize == 0 )
418 nRet = 2UL;
419 else
421 rIStm.Read( pSrcBuf, cBlockSize );
423 if( NO_PENDING( rIStm ) )
425 if( bOverreadBlock )
426 nRet = 3UL;
427 else
429 BOOL bEOI;
430 HPBYTE pTarget = pDecomp->DecompressBlock( pSrcBuf, cBlockSize, nRead, bEOI );
432 nRet = ( bEOI ? 3 : 1 );
434 if( nRead && !bOverreadBlock )
435 FillImages( pTarget, nRead );
437 rtl_freeMemory( pTarget );
443 return nRet;
446 // ------------------------------------------------------------------------
448 void GIFReader::FillImages( HPBYTE pBytes, ULONG nCount )
450 for( ULONG i = 0UL; i < nCount; i++ )
452 if( nImageX >= nImageWidth )
454 if( bInterlaced )
456 long nT1, nT2;
458 // falls Interlaced, werden die Zeilen kopiert
459 if( nLastInterCount )
461 long nMinY = Min( (long) nLastImageY + 1, (long) nImageHeight - 1 );
462 long nMaxY = Min( (long) nLastImageY + nLastInterCount, (long) nImageHeight - 1 );
464 // letzte gelesene Zeile kopieren, wenn Zeilen
465 // nicht zusanmmenfallen ( kommt vorm wenn wir am Ende des Bildes sind )
466 if( ( nMinY > nLastImageY ) && ( nLastImageY < ( nImageHeight - 1 ) ) )
468 HPBYTE pScanline8 = pAcc8->GetScanline( nYAcc );
469 ULONG nSize8 = pAcc8->GetScanlineSize();
470 HPBYTE pScanline1 = 0;
471 ULONG nSize1 = 0;
473 if( bGCTransparent )
475 pScanline1 = pAcc1->GetScanline( nYAcc );
476 nSize1 = pAcc1->GetScanlineSize();
479 for( long j = nMinY; j <= nMaxY; j++ )
481 memcpy( pAcc8->GetScanline( j ), pScanline8, nSize8 );
483 if( bGCTransparent )
484 memcpy( pAcc1->GetScanline( j ), pScanline1, nSize1 );
489 nT1 = ( ++nImageY ) << 3;
490 nLastInterCount = 7;
492 if( nT1 >= nImageHeight )
494 nT2 = nImageY - ( ( nImageHeight + 7 ) >> 3 );
495 nT1 = ( nT2 << 3 ) + 4;
496 nLastInterCount = 3;
498 if( nT1 >= nImageHeight )
500 nT2 -= ( nImageHeight + 3 ) >> 3;
501 nT1 = ( nT2 << 2 ) + 2;
502 nLastInterCount = 1;
504 if( nT1 >= nImageHeight )
506 nT2 -= ( nImageHeight + 1 ) >> 2;
507 nT1 = ( nT2 << 1 ) + 1;
508 nLastInterCount = 0;
513 nLastImageY = (USHORT) nT1;
514 nYAcc = nT1;
516 else
518 nLastImageY = ++nImageY;
519 nYAcc = nImageY;
522 // Zeile faengt von vorne an
523 nImageX = 0;
526 if( nImageY < nImageHeight )
528 const BYTE cTmp = pBytes[ i ];
530 if( bGCTransparent )
532 if( cTmp == nGCTransparentIndex )
533 pAcc1->SetPixel( nYAcc, nImageX++, cTransIndex1 );
534 else
536 pAcc8->SetPixel( nYAcc, nImageX, cTmp );
537 pAcc1->SetPixel( nYAcc, nImageX++, cNonTransIndex1 );
540 else
541 pAcc8->SetPixel( nYAcc, nImageX++, cTmp );
543 else
545 bOverreadBlock = TRUE;
546 break;
551 // ------------------------------------------------------------------------
553 void GIFReader::CreateNewBitmaps()
555 AnimationBitmap aAnimBmp;
557 aBmp8.ReleaseAccess( pAcc8 );
558 pAcc8 = NULL;
560 if( bGCTransparent )
562 aBmp1.ReleaseAccess( pAcc1 );
563 pAcc1 = NULL;
564 aAnimBmp.aBmpEx = BitmapEx( aBmp8, aBmp1 );
566 else
567 aAnimBmp.aBmpEx = BitmapEx( aBmp8 );
569 aAnimBmp.aPosPix = Point( nImagePosX, nImagePosY );
570 aAnimBmp.aSizePix = Size( nImageWidth, nImageHeight );
571 aAnimBmp.nWait = ( nTimer != 65535 ) ? nTimer : ANIMATION_TIMEOUT_ON_CLICK;
572 aAnimBmp.bUserInput = FALSE;
574 if( nGCDisposalMethod == 2 )
575 aAnimBmp.eDisposal = DISPOSE_BACK;
576 else if( nGCDisposalMethod == 3 )
577 aAnimBmp.eDisposal = DISPOSE_PREVIOUS;
578 else
579 aAnimBmp.eDisposal = DISPOSE_NOT;
581 aAnimation.Insert( aAnimBmp );
583 if( aAnimation.Count() == 1 )
585 aAnimation.SetDisplaySizePixel( Size( nGlobalWidth, nGlobalHeight ) );
586 aAnimation.SetLoopCount( nLoops );
590 // ------------------------------------------------------------------------
592 const Graphic& GIFReader::GetIntermediateGraphic()
594 // Intermediate-Graphic nur erzeugen, wenn schon
595 // Daten vorliegen, aber die Graphic noch nicht
596 // vollstaendig eingelesen wurde
597 if ( bImGraphicReady && !aAnimation.Count() )
599 Bitmap aBmp;
601 aBmp8.ReleaseAccess( pAcc8 );
603 if ( bGCTransparent )
605 aBmp1.ReleaseAccess( pAcc1 );
606 aImGraphic = BitmapEx( aBmp8, aBmp1 );
608 pAcc1 = aBmp1.AcquireWriteAccess();
609 bStatus = bStatus && ( pAcc1 != NULL );
611 else
612 aImGraphic = aBmp8;
614 pAcc8 = aBmp8.AcquireWriteAccess();
615 bStatus = bStatus && ( pAcc8 != NULL );
618 return aImGraphic;
621 // ------------------------------------------------------------------------
623 BOOL GIFReader::ProcessGIF()
625 BOOL bRead = FALSE;
626 BOOL bEnd = FALSE;
628 if ( !bStatus )
629 eActAction = ABORT_READING;
631 // Stream an die richtige Stelle bringen
632 rIStm.Seek( nLastPos );
634 switch( eActAction )
636 // naechsten Marker lesen
637 case( MARKER_READING ):
639 BYTE cByte;
641 rIStm >> cByte;
643 if( rIStm.IsEof() )
644 eActAction = END_READING;
645 else if( NO_PENDING( rIStm ) )
647 bRead = TRUE;
649 if( cByte == '!' )
650 eActAction = EXTENSION_READING;
651 else if( cByte == ',' )
652 eActAction = LOCAL_HEADER_READING;
653 else if( cByte == ';' )
654 eActAction = END_READING;
655 else
656 eActAction = ABORT_READING;
659 break;
661 // ScreenDescriptor lesen
662 case( GLOBAL_HEADER_READING ):
664 if( ( bRead = ReadGlobalHeader() ) == TRUE )
666 ClearImageExtensions();
667 eActAction = MARKER_READING;
670 break;
673 // Extension lesen
674 case( EXTENSION_READING ):
676 if( ( bRead = ReadExtension() ) == TRUE )
677 eActAction = MARKER_READING;
679 break;
682 // Image-Descriptor lesen
683 case( LOCAL_HEADER_READING ):
685 if( ( bRead = ReadLocalHeader() ) == TRUE )
687 nYAcc = nImageX = nImageY = 0;
688 eActAction = FIRST_BLOCK_READING;
691 break;
694 // ersten Datenblock lesen
695 case( FIRST_BLOCK_READING ):
697 BYTE cDataSize;
699 rIStm >> cDataSize;
701 if( rIStm.IsEof() )
702 eActAction = ABORT_READING;
703 else if( cDataSize > 12 )
704 bStatus = FALSE;
705 else if( NO_PENDING( rIStm ) )
707 bRead = TRUE;
708 pDecomp = new GIFLZWDecompressor( cDataSize );
709 eActAction = NEXT_BLOCK_READING;
710 bOverreadBlock = FALSE;
712 else
713 eActAction = FIRST_BLOCK_READING;
715 break;
717 // naechsten Datenblock lesen
718 case( NEXT_BLOCK_READING ):
720 USHORT nLastX = nImageX;
721 USHORT nLastY = nImageY;
722 ULONG nRet = ReadNextBlock();
724 // Return: 0:Pending / 1:OK; / 2:OK und letzter Block: / 3:EOI / 4:HardAbort
725 if( nRet )
727 bRead = TRUE;
729 if ( nRet == 1UL )
731 bImGraphicReady = TRUE;
732 eActAction = NEXT_BLOCK_READING;
733 bOverreadBlock = FALSE;
735 else
737 if( nRet == 2UL )
739 delete pDecomp;
740 CreateNewBitmaps();
741 eActAction = MARKER_READING;
742 ClearImageExtensions();
744 else if( nRet == 3UL )
746 eActAction = NEXT_BLOCK_READING;
747 bOverreadBlock = TRUE;
749 else
751 delete pDecomp;
752 CreateNewBitmaps();
753 eActAction = ABORT_READING;
754 ClearImageExtensions();
758 else
760 nImageX = nLastX;
761 nImageY = nLastY;
764 break;
766 // ein Fehler trat auf
767 case( ABORT_READING ):
769 bEnd = TRUE;
770 eActAction = END_READING;
772 break;
774 default:
775 break;
778 // Stream an die richtige Stelle bringen,
779 // falls Daten gelesen werden konnten
780 // entweder alte Position oder aktuelle Position
781 if( bRead || bEnd )
782 nLastPos = rIStm.Tell();
784 return bRead;
787 // ------------------------------------------------------------------------
789 ReadState GIFReader::ReadGIF( Graphic& rGraphic )
791 ReadState eReadState;
793 bStatus = TRUE;
795 while( ProcessGIF() && ( eActAction != END_READING ) ) {}
797 if( !bStatus )
798 eReadState = GIFREAD_ERROR;
799 else if( eActAction == END_READING )
800 eReadState = GIFREAD_OK;
801 else
803 if ( rIStm.GetError() == ERRCODE_IO_PENDING )
804 rIStm.ResetError();
806 eReadState = GIFREAD_NEED_MORE;
809 if( aAnimation.Count() == 1 )
811 rGraphic = aAnimation.Get( 0 ).aBmpEx;
813 if( nLogWidth100 && nLogHeight100 )
815 rGraphic.SetPrefSize( Size( nLogWidth100, nLogHeight100 ) );
816 rGraphic.SetPrefMapMode( MAP_100TH_MM );
819 else
820 rGraphic = aAnimation;
822 return eReadState;
826 // -------------
827 // - ImportGIF -
828 // -------------
830 BOOL ImportGIF( SvStream & rStm, Graphic& rGraphic )
832 GIFReader* pGIFReader = (GIFReader*) rGraphic.GetContext();
833 USHORT nOldFormat = rStm.GetNumberFormatInt();
834 ReadState eReadState;
835 BOOL bRet = TRUE;
837 rStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
839 if( !pGIFReader )
840 pGIFReader = new GIFReader( rStm );
842 rGraphic.SetContext( NULL );
843 eReadState = pGIFReader->ReadGIF( rGraphic );
845 if( eReadState == GIFREAD_ERROR )
847 bRet = FALSE;
848 delete pGIFReader;
850 else if( eReadState == GIFREAD_OK )
851 delete pGIFReader;
852 else
854 rGraphic = pGIFReader->GetIntermediateGraphic();
855 rGraphic.SetContext( pGIFReader );
858 rStm.SetNumberFormatInt( nOldFormat );
860 return bRet;