1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svtools.hxx"
26
27 #define _GIFPRIVATE
28
29 #include "decode.hxx"
30 #include "gifread.hxx"
31
32 // -----------
33 // - Defines -
34 // -----------
35
36 #define NO_PENDING( rStm ) ( ( rStm ).GetError() != ERRCODE_IO_PENDING )
37
38 // -------------
39 // - GIFReader -
40 // -------------
41
GIFReader(SvStream & rStm)42 GIFReader::GIFReader( SvStream& rStm ) :
43 aGPalette ( 256 ),
44 aLPalette ( 256 ),
45 rIStm ( rStm ),
46 pAcc8 ( NULL ),
47 pAcc1 ( NULL ),
48 nLastPos ( rStm.Tell() ),
49 nLogWidth100 ( 0UL ),
50 nLogHeight100 ( 0UL ),
51 nLoops ( 1 ),
52 eActAction ( GLOBAL_HEADER_READING ),
53 bGCTransparent ( sal_False ),
54 bImGraphicReady ( sal_False )
55 {
56 maUpperName = UniString::CreateFromAscii( "SVIGIF", 6 );
57 pSrcBuf = new sal_uInt8[ 256 ];
58 ClearImageExtensions();
59 }
60
61 // ------------------------------------------------------------------------
62
~GIFReader()63 GIFReader::~GIFReader()
64 {
65 aImGraphic.SetContext( NULL );
66
67 if( pAcc1 )
68 aBmp1.ReleaseAccess( pAcc1 );
69
70 if( pAcc8 )
71 aBmp8.ReleaseAccess( pAcc8 );
72
73 delete[] pSrcBuf;
74 }
75
76 // ------------------------------------------------------------------------
77
ClearImageExtensions()78 void GIFReader::ClearImageExtensions()
79 {
80 nGCDisposalMethod = 0;
81 bGCTransparent = sal_False;
82 nTimer = 0;
83 }
84
85 // ------------------------------------------------------------------------
86
CreateBitmaps(long nWidth,long nHeight,BitmapPalette * pPal,sal_Bool bWatchForBackgroundColor)87 sal_Bool GIFReader::CreateBitmaps( long nWidth, long nHeight, BitmapPalette* pPal,
88 sal_Bool bWatchForBackgroundColor )
89 {
90 const Size aSize( nWidth, nHeight );
91
92 if( bGCTransparent )
93 {
94 const Color aWhite( COL_WHITE );
95
96 aBmp1 = Bitmap( aSize, 1 );
97
98 if( !aAnimation.Count() )
99 aBmp1.Erase( aWhite );
100
101 pAcc1 = aBmp1.AcquireWriteAccess();
102
103 if( pAcc1 )
104 {
105 cTransIndex1 = (sal_uInt8) pAcc1->GetBestPaletteIndex( aWhite );
106 cNonTransIndex1 = cTransIndex1 ? 0 : 1;
107 }
108 else
109 bStatus = sal_False;
110 }
111
112 if( bStatus )
113 {
114 aBmp8 = Bitmap( aSize, 8, pPal );
115
116 if( !!aBmp8 && bWatchForBackgroundColor && aAnimation.Count() )
117 aBmp8.Erase( (*pPal)[ nBackgroundColor ] );
118 else
119 aBmp8.Erase( Color( COL_WHITE ) );
120
121 pAcc8 = aBmp8.AcquireWriteAccess();
122 bStatus = ( pAcc8 != NULL );
123 }
124
125 return bStatus;
126 }
127
128 // ------------------------------------------------------------------------
129
ReadGlobalHeader()130 sal_Bool GIFReader::ReadGlobalHeader()
131 {
132 char pBuf[ 7 ];
133 sal_uInt8 nRF;
134 sal_uInt8 nAspect;
135 sal_Bool bRet = sal_False;
136
137 rIStm.Read( pBuf, 6 );
138 if( NO_PENDING( rIStm ) )
139 {
140 pBuf[ 6 ] = 0;
141 if( !strcmp( pBuf, "GIF87a" ) || !strcmp( pBuf, "GIF89a" ) )
142 {
143 rIStm.Read( pBuf, 7 );
144 if( NO_PENDING( rIStm ) )
145 {
146 SvMemoryStream aMemStm;
147
148 aMemStm.SetBuffer( pBuf, 7, sal_False, 7 );
149 aMemStm >> nGlobalWidth;
150 aMemStm >> nGlobalHeight;
151 aMemStm >> nRF;
152 aMemStm >> nBackgroundColor;
153 aMemStm >> nAspect;
154
155 bGlobalPalette = (sal_Bool) ( nRF & 0x80 );
156
157 if( bGlobalPalette )
158 ReadPaletteEntries( &aGPalette, 1 << ( ( nRF & 7 ) + 1 ) );
159 else
160 nBackgroundColor = 0;
161
162 if( NO_PENDING( rIStm ) )
163 bRet = sal_True;
164 }
165 }
166 else
167 bStatus = sal_False;
168 }
169
170 return bRet;
171 }
172
173 // ------------------------------------------------------------------------
174
ReadPaletteEntries(BitmapPalette * pPal,sal_uLong nCount)175 void GIFReader::ReadPaletteEntries( BitmapPalette* pPal, sal_uLong nCount )
176 {
177 const sal_uLong nLen = 3UL * nCount;
178 sal_uInt8* pBuf = new sal_uInt8[ nLen ];
179
180 rIStm.Read( pBuf, nLen );
181 if( NO_PENDING( rIStm ) )
182 {
183 sal_uInt8* pTmp = pBuf;
184
185 for( sal_uLong i = 0UL; i < nCount; )
186 {
187 BitmapColor& rColor = (*pPal)[ (sal_uInt16) i++ ];
188
189 rColor.SetRed( *pTmp++ );
190 rColor.SetGreen( *pTmp++ );
191 rColor.SetBlue( *pTmp++ );
192 }
193
194 // nach Moeglichkeit noch einige Standardfarben unterbringen
195 if( nCount < 256UL )
196 {
197 (*pPal)[ 255UL ] = Color( COL_WHITE );
198
199 if( nCount < 255UL )
200 (*pPal)[ 254UL ] = Color( COL_BLACK );
201 }
202 }
203
204 delete[] pBuf;
205 }
206
207 // ------------------------------------------------------------------------
208
ReadExtension()209 sal_Bool GIFReader::ReadExtension()
210 {
211 sal_uInt8 cFunction;
212 sal_uInt8 cSize;
213 sal_uInt8 cByte;
214 sal_Bool bRet = sal_False;
215 sal_Bool bOverreadDataBlocks = sal_False;
216
217 // Extension-Label
218 rIStm >> cFunction;
219 if( NO_PENDING( rIStm ) )
220 {
221 // Block-Laenge
222 rIStm >> cSize;
223
224 switch( cFunction )
225 {
226 // 'Graphic Control Extension'
227 case( 0xf9 ) :
228 {
229 sal_uInt8 cFlags;
230
231 rIStm >> cFlags;
232 rIStm >> nTimer;
233 rIStm >> nGCTransparentIndex;
234 rIStm >> cByte;
235
236 if ( NO_PENDING( rIStm ) )
237 {
238 nGCDisposalMethod = ( cFlags >> 2) & 7;
239 bGCTransparent = ( cFlags & 1 ) ? sal_True : sal_False;
240 bStatus = ( cSize == 4 ) && ( cByte == 0 );
241 bRet = sal_True;
242 }
243 }
244 break;
245
246 // Application-Extension
247 case ( 0xff ) :
248 {
249 if ( NO_PENDING( rIStm ) )
250 {
251 // default diese Extension ueberlesen
252 bOverreadDataBlocks = sal_True;
253
254 // Appl.-Extension hat Laenge 11
255 if ( cSize == 0x0b )
256 {
257 ByteString aAppId;
258 ByteString aAppCode;
259
260 rIStm.Read( aAppId.AllocBuffer( 8 ), 8 );
261 rIStm.Read( aAppCode.AllocBuffer( 3 ), 3 );
262 rIStm >> cSize;
263
264 // NetScape-Extension
265 if( aAppId == "NETSCAPE" && aAppCode == "2.0" && cSize == 3 )
266 {
267 rIStm >> cByte;
268
269 // Loop-Extension
270 if ( cByte == 0x01 )
271 {
272 rIStm >> cByte;
273 nLoops = cByte;
274 rIStm >> cByte;
275 nLoops |= ( (sal_uInt16) cByte << 8 );
276 rIStm >> cByte;
277
278 bStatus = ( cByte == 0 );
279 bRet = NO_PENDING( rIStm );
280 bOverreadDataBlocks = sal_False;
281
282 // Netscape interpretiert den LoopCount
283 // als reine Anzahl der _Wiederholungen_;
284 // bei uns ist es die Gesamtanzahl der
285 // Durchlaeufe
286 if( nLoops )
287 nLoops++;
288 }
289 else
290 rIStm.SeekRel( -1 );
291 }
292 else if ( aAppId == "STARDIV " && aAppCode == "5.0" && cSize == 9 )
293 {
294 rIStm >> cByte;
295
296 // Loop-Extension
297 if ( cByte == 0x01 )
298 {
299 rIStm >> nLogWidth100 >> nLogHeight100;
300 rIStm >> cByte;
301 bStatus = ( cByte == 0 );
302 bRet = NO_PENDING( rIStm );
303 bOverreadDataBlocks = sal_False;
304 }
305 else
306 rIStm.SeekRel( -1 );
307 }
308
309 }
310 }
311 }
312 break;
313
314 // alles andere ueberlesen
315 default:
316 bOverreadDataBlocks = sal_True;
317 break;
318 }
319
320 // Sub-Blocks ueberlesen
321 if ( bOverreadDataBlocks )
322 {
323 bRet = sal_True;
324 while( cSize && bStatus && !rIStm.IsEof() )
325 {
326 sal_uInt16 nCount = (sal_uInt16) cSize + 1;
327 char* pBuffer = new char[ nCount ];
328
329 bRet = sal_False;
330 rIStm.Read( pBuffer, nCount );
331 if( NO_PENDING( rIStm ) )
332 {
333 cSize = (sal_uInt8) pBuffer[ cSize ];
334 bRet = sal_True;
335 }
336 else
337 cSize = 0;
338
339 delete[] pBuffer;
340 }
341 }
342 }
343
344 return bRet;
345 }
346
347 // ------------------------------------------------------------------------
348
ReadLocalHeader()349 sal_Bool GIFReader::ReadLocalHeader()
350 {
351 sal_uInt8 pBuf[ 9 ];
352 sal_Bool bRet = sal_False;
353
354 rIStm.Read( pBuf, 9 );
355 if( NO_PENDING( rIStm ) )
356 {
357 SvMemoryStream aMemStm;
358 BitmapPalette* pPal;
359 sal_uInt8 nFlags;
360
361 aMemStm.SetBuffer( (char*) pBuf, 9, sal_False, 9 );
362 aMemStm >> nImagePosX;
363 aMemStm >> nImagePosY;
364 aMemStm >> nImageWidth;
365 aMemStm >> nImageHeight;
366 aMemStm >> nFlags;
367
368 // Falls Interlaced, ersten Startwert vorgeben
369 bInterlaced = ( ( nFlags & 0x40 ) == 0x40 );
370 nLastInterCount = 7;
371 nLastImageY = 0;
372
373 if( nFlags & 0x80 )
374 {
375 pPal = &aLPalette;
376 ReadPaletteEntries( pPal, 1 << ( (nFlags & 7 ) + 1 ) );
377 }
378 else
379 pPal = &aGPalette;
380
381 // Falls alles soweit eingelesen werden konnte, kann
382 // nun das lokale Bild angelegt werden;
383 // es wird uebergeben, ob der BackgroundColorIndex evtl.
384 // beruecksichtigt werden soll ( wenn Globale Farbtab. und
385 // diese auch fuer dieses Bild gilt )
386 if( NO_PENDING( rIStm ) )
387 {
388 CreateBitmaps( nImageWidth, nImageHeight, pPal, bGlobalPalette && ( pPal == &aGPalette ) );
389 bRet = sal_True;
390 }
391 }
392
393 return bRet;
394 }
395
396 // ------------------------------------------------------------------------
397
ReadNextBlock()398 sal_uLong GIFReader::ReadNextBlock()
399 {
400 sal_uLong nRet = 0UL;
401 sal_uLong nRead;
402 sal_uInt8 cBlockSize;
403
404 rIStm >> cBlockSize;
405
406 if ( rIStm.IsEof() )
407 nRet = 4UL;
408 else if ( NO_PENDING( rIStm ) )
409 {
410 if ( cBlockSize == 0 )
411 nRet = 2UL;
412 else
413 {
414 rIStm.Read( pSrcBuf, cBlockSize );
415
416 if( NO_PENDING( rIStm ) )
417 {
418 if( bOverreadBlock )
419 nRet = 3UL;
420 else
421 {
422 sal_Bool bEOI;
423 HPBYTE pTarget = pDecomp->DecompressBlock( pSrcBuf, cBlockSize, nRead, bEOI );
424
425 nRet = ( bEOI ? 3 : 1 );
426
427 if( nRead && !bOverreadBlock )
428 FillImages( pTarget, nRead );
429
430 rtl_freeMemory( pTarget );
431 }
432 }
433 }
434 }
435
436 return nRet;
437 }
438
439 // ------------------------------------------------------------------------
440
FillImages(HPBYTE pBytes,sal_uLong nCount)441 void GIFReader::FillImages( HPBYTE pBytes, sal_uLong nCount )
442 {
443 for( sal_uLong i = 0UL; i < nCount; i++ )
444 {
445 if( nImageX >= nImageWidth )
446 {
447 if( bInterlaced )
448 {
449 long nT1, nT2;
450
451 // falls Interlaced, werden die Zeilen kopiert
452 if( nLastInterCount )
453 {
454 long nMinY = Min( (long) nLastImageY + 1, (long) nImageHeight - 1 );
455 long nMaxY = Min( (long) nLastImageY + nLastInterCount, (long) nImageHeight - 1 );
456
457 // letzte gelesene Zeile kopieren, wenn Zeilen
458 // nicht zusanmmenfallen ( kommt vorm wenn wir am Ende des Bildes sind )
459 if( ( nMinY > nLastImageY ) && ( nLastImageY < ( nImageHeight - 1 ) ) )
460 {
461 HPBYTE pScanline8 = pAcc8->GetScanline( nYAcc );
462 sal_uLong nSize8 = pAcc8->GetScanlineSize();
463 HPBYTE pScanline1 = 0;
464 sal_uLong nSize1 = 0;
465
466 if( bGCTransparent )
467 {
468 pScanline1 = pAcc1->GetScanline( nYAcc );
469 nSize1 = pAcc1->GetScanlineSize();
470 }
471
472 for( long j = nMinY; j <= nMaxY; j++ )
473 {
474 memcpy( pAcc8->GetScanline( j ), pScanline8, nSize8 );
475
476 if( bGCTransparent )
477 memcpy( pAcc1->GetScanline( j ), pScanline1, nSize1 );
478 }
479 }
480 }
481
482 nT1 = ( ++nImageY ) << 3;
483 nLastInterCount = 7;
484
485 if( nT1 >= nImageHeight )
486 {
487 nT2 = nImageY - ( ( nImageHeight + 7 ) >> 3 );
488 nT1 = ( nT2 << 3 ) + 4;
489 nLastInterCount = 3;
490
491 if( nT1 >= nImageHeight )
492 {
493 nT2 -= ( nImageHeight + 3 ) >> 3;
494 nT1 = ( nT2 << 2 ) + 2;
495 nLastInterCount = 1;
496
497 if( nT1 >= nImageHeight )
498 {
499 nT2 -= ( nImageHeight + 1 ) >> 2;
500 nT1 = ( nT2 << 1 ) + 1;
501 nLastInterCount = 0;
502 }
503 }
504 }
505
506 nLastImageY = (sal_uInt16) nT1;
507 nYAcc = nT1;
508 }
509 else
510 {
511 nLastImageY = ++nImageY;
512 nYAcc = nImageY;
513 }
514
515 // Zeile faengt von vorne an
516 nImageX = 0;
517 }
518
519 if( nImageY < nImageHeight )
520 {
521 const sal_uInt8 cTmp = pBytes[ i ];
522
523 if( bGCTransparent )
524 {
525 if( cTmp == nGCTransparentIndex )
526 pAcc1->SetPixelIndex( nYAcc, nImageX++, cTransIndex1 );
527 else
528 {
529 pAcc8->SetPixelIndex( nYAcc, nImageX, cTmp );
530 pAcc1->SetPixelIndex( nYAcc, nImageX++, cNonTransIndex1 );
531 }
532 }
533 else
534 pAcc8->SetPixelIndex( nYAcc, nImageX++, cTmp );
535 }
536 else
537 {
538 bOverreadBlock = sal_True;
539 break;
540 }
541 }
542 }
543
544 // ------------------------------------------------------------------------
545
CreateNewBitmaps()546 void GIFReader::CreateNewBitmaps()
547 {
548 AnimationBitmap aAnimBmp;
549
550 aBmp8.ReleaseAccess( pAcc8 );
551 pAcc8 = NULL;
552
553 if( bGCTransparent )
554 {
555 aBmp1.ReleaseAccess( pAcc1 );
556 pAcc1 = NULL;
557 aAnimBmp.aBmpEx = BitmapEx( aBmp8, aBmp1 );
558 }
559 else
560 aAnimBmp.aBmpEx = BitmapEx( aBmp8 );
561
562 aAnimBmp.aPosPix = Point( nImagePosX, nImagePosY );
563 aAnimBmp.aSizePix = Size( nImageWidth, nImageHeight );
564 aAnimBmp.nWait = ( nTimer != 65535 ) ? nTimer : ANIMATION_TIMEOUT_ON_CLICK;
565 aAnimBmp.bUserInput = sal_False;
566
567 if( nGCDisposalMethod == 2 )
568 aAnimBmp.eDisposal = DISPOSE_BACK;
569 else if( nGCDisposalMethod == 3 )
570 aAnimBmp.eDisposal = DISPOSE_PREVIOUS;
571 else
572 aAnimBmp.eDisposal = DISPOSE_NOT;
573
574 aAnimation.Insert( aAnimBmp );
575
576 if( aAnimation.Count() == 1 )
577 {
578 aAnimation.SetDisplaySizePixel( Size( nGlobalWidth, nGlobalHeight ) );
579 aAnimation.SetLoopCount( nLoops );
580 }
581 }
582
583 // ------------------------------------------------------------------------
584
GetIntermediateGraphic()585 const Graphic& GIFReader::GetIntermediateGraphic()
586 {
587 // Intermediate-Graphic nur erzeugen, wenn schon
588 // Daten vorliegen, aber die Graphic noch nicht
589 // vollstaendig eingelesen wurde
590 if ( bImGraphicReady && !aAnimation.Count() )
591 {
592 Bitmap aBmp;
593
594 aBmp8.ReleaseAccess( pAcc8 );
595
596 if ( bGCTransparent )
597 {
598 aBmp1.ReleaseAccess( pAcc1 );
599 aImGraphic = BitmapEx( aBmp8, aBmp1 );
600
601 pAcc1 = aBmp1.AcquireWriteAccess();
602 bStatus = bStatus && ( pAcc1 != NULL );
603 }
604 else
605 aImGraphic = aBmp8;
606
607 pAcc8 = aBmp8.AcquireWriteAccess();
608 bStatus = bStatus && ( pAcc8 != NULL );
609 }
610
611 return aImGraphic;
612 }
613
614 // ------------------------------------------------------------------------
615
ProcessGIF()616 sal_Bool GIFReader::ProcessGIF()
617 {
618 sal_Bool bRead = sal_False;
619 sal_Bool bEnd = sal_False;
620
621 if ( !bStatus )
622 eActAction = ABORT_READING;
623
624 // Stream an die richtige Stelle bringen
625 rIStm.Seek( nLastPos );
626
627 switch( eActAction )
628 {
629 // naechsten Marker lesen
630 case( MARKER_READING ):
631 {
632 sal_uInt8 cByte;
633
634 rIStm >> cByte;
635
636 if( rIStm.IsEof() )
637 eActAction = END_READING;
638 else if( NO_PENDING( rIStm ) )
639 {
640 bRead = sal_True;
641
642 if( cByte == '!' )
643 eActAction = EXTENSION_READING;
644 else if( cByte == ',' )
645 eActAction = LOCAL_HEADER_READING;
646 else if( cByte == ';' )
647 eActAction = END_READING;
648 else
649 eActAction = ABORT_READING;
650 }
651 }
652 break;
653
654 // ScreenDescriptor lesen
655 case( GLOBAL_HEADER_READING ):
656 {
657 if( ( bRead = ReadGlobalHeader() ) == sal_True )
658 {
659 ClearImageExtensions();
660 eActAction = MARKER_READING;
661 }
662 }
663 break;
664
665
666 // Extension lesen
667 case( EXTENSION_READING ):
668 {
669 if( ( bRead = ReadExtension() ) == sal_True )
670 eActAction = MARKER_READING;
671 }
672 break;
673
674
675 // Image-Descriptor lesen
676 case( LOCAL_HEADER_READING ):
677 {
678 if( ( bRead = ReadLocalHeader() ) == sal_True )
679 {
680 nYAcc = nImageX = nImageY = 0;
681 eActAction = FIRST_BLOCK_READING;
682 }
683 }
684 break;
685
686
687 // ersten Datenblock lesen
688 case( FIRST_BLOCK_READING ):
689 {
690 sal_uInt8 cDataSize;
691
692 rIStm >> cDataSize;
693
694 if( rIStm.IsEof() )
695 eActAction = ABORT_READING;
696 else if( cDataSize > 12 )
697 bStatus = sal_False;
698 else if( NO_PENDING( rIStm ) )
699 {
700 bRead = sal_True;
701 pDecomp = new GIFLZWDecompressor( cDataSize );
702 eActAction = NEXT_BLOCK_READING;
703 bOverreadBlock = sal_False;
704 }
705 else
706 eActAction = FIRST_BLOCK_READING;
707 }
708 break;
709
710 // naechsten Datenblock lesen
711 case( NEXT_BLOCK_READING ):
712 {
713 sal_uInt16 nLastX = nImageX;
714 sal_uInt16 nLastY = nImageY;
715 sal_uLong nRet = ReadNextBlock();
716
717 // Return: 0:Pending / 1:OK; / 2:OK und letzter Block: / 3:EOI / 4:HardAbort
718 if( nRet )
719 {
720 bRead = sal_True;
721
722 if ( nRet == 1UL )
723 {
724 bImGraphicReady = sal_True;
725 eActAction = NEXT_BLOCK_READING;
726 bOverreadBlock = sal_False;
727 }
728 else
729 {
730 if( nRet == 2UL )
731 {
732 delete pDecomp;
733 CreateNewBitmaps();
734 eActAction = MARKER_READING;
735 ClearImageExtensions();
736 }
737 else if( nRet == 3UL )
738 {
739 eActAction = NEXT_BLOCK_READING;
740 bOverreadBlock = sal_True;
741 }
742 else
743 {
744 delete pDecomp;
745 CreateNewBitmaps();
746 eActAction = ABORT_READING;
747 ClearImageExtensions();
748 }
749 }
750 }
751 else
752 {
753 nImageX = nLastX;
754 nImageY = nLastY;
755 }
756 }
757 break;
758
759 // ein Fehler trat auf
760 case( ABORT_READING ):
761 {
762 bEnd = sal_True;
763 eActAction = END_READING;
764 }
765 break;
766
767 default:
768 break;
769 }
770
771 // Stream an die richtige Stelle bringen,
772 // falls Daten gelesen werden konnten
773 // entweder alte Position oder aktuelle Position
774 if( bRead || bEnd )
775 nLastPos = rIStm.Tell();
776
777 return bRead;
778 }
779
780 // ------------------------------------------------------------------------
781
ReadGIF(Graphic & rGraphic)782 ReadState GIFReader::ReadGIF( Graphic& rGraphic )
783 {
784 ReadState eReadState;
785
786 bStatus = sal_True;
787
788 while( ProcessGIF() && ( eActAction != END_READING ) ) {}
789
790 if( !bStatus )
791 eReadState = GIFREAD_ERROR;
792 else if( eActAction == END_READING )
793 eReadState = GIFREAD_OK;
794 else
795 {
796 if ( rIStm.GetError() == ERRCODE_IO_PENDING )
797 rIStm.ResetError();
798
799 eReadState = GIFREAD_NEED_MORE;
800 }
801
802 if( aAnimation.Count() == 1 )
803 {
804 rGraphic = aAnimation.Get( 0 ).aBmpEx;
805
806 if( nLogWidth100 && nLogHeight100 )
807 {
808 rGraphic.SetPrefSize( Size( nLogWidth100, nLogHeight100 ) );
809 rGraphic.SetPrefMapMode( MAP_100TH_MM );
810 }
811 }
812 else
813 rGraphic = aAnimation;
814
815 return eReadState;
816 }
817
818
819 // -------------
820 // - ImportGIF -
821 // -------------
822
ImportGIF(SvStream & rStm,Graphic & rGraphic)823 sal_Bool ImportGIF( SvStream & rStm, Graphic& rGraphic )
824 {
825 GIFReader* pGIFReader = (GIFReader*) rGraphic.GetContext();
826 sal_uInt16 nOldFormat = rStm.GetNumberFormatInt();
827 ReadState eReadState;
828 sal_Bool bRet = sal_True;
829
830 rStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
831
832 if( !pGIFReader )
833 pGIFReader = new GIFReader( rStm );
834
835 rGraphic.SetContext( NULL );
836 eReadState = pGIFReader->ReadGIF( rGraphic );
837
838 if( eReadState == GIFREAD_ERROR )
839 {
840 bRet = sal_False;
841 delete pGIFReader;
842 }
843 else if( eReadState == GIFREAD_OK )
844 delete pGIFReader;
845 else
846 {
847 rGraphic = pGIFReader->GetIntermediateGraphic();
848 rGraphic.SetContext( pGIFReader );
849 }
850
851 rStm.SetNumberFormatInt( nOldFormat );
852
853 return bRet;
854 }
855