source: vendor/trolltech/current/src/kernel/qasyncimageio.cpp

Last change on this file was 2, checked in by dmik, 20 years ago

Imported xplatform parts of the official release 3.3.1 from Trolltech

  • Property svn:keywords set to Id
File size: 35.3 KB
Line 
1/****************************************************************************
2** $Id: qasyncimageio.cpp 2 2005-11-16 15:49:26Z dmik $
3**
4** Implementation of asynchronous image/movie loading classes
5**
6** Created : 970617
7**
8** Copyright (C) 1992-2002 Trolltech AS. All rights reserved.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qasyncimageio.h"
39
40#ifndef QT_NO_ASYNC_IMAGE_IO
41
42#include "qptrlist.h"
43#include "qgif.h"
44#include <stdlib.h>
45
46extern void qt_init_image_handlers();
47extern void qt_init_image_plugins();
48
49#define Q_TRANSPARENT 0x00ffffff
50
51/*!
52 \class QImageConsumer qasyncimageio.h
53 \brief The QImageConsumer class is an abstraction used by QImageDecoder.
54
55 \ingroup images
56 \ingroup graphics
57 \ingroup multimedia
58
59 The QMovie class, or QLabel::setMovie(), are easy to use and for
60 most situations do what you want with regards animated images.
61
62 A QImageConsumer consumes information about changes to the QImage
63 maintained by a QImageDecoder. Think of the QImage as the model or
64 source of the image data, with the QImageConsumer as a view of
65 that data and the QImageDecoder being the controller that
66 orchestrates the relationship between the model and the view.
67
68 You'd use the QImageConsumer class, for example, if you were
69 implementing a web browser with your own image loaders.
70
71 \sa QImageDecoder
72*/
73
74/*!
75 \fn void QImageConsumer::changed(const QRect&)
76
77 Called when the given area of the image has changed.
78*/
79
80/*!
81 \fn void QImageConsumer::end()
82
83 Called when all the data from all the frames has been decoded and
84 revealed as changed().
85*/
86
87/*!
88 \fn void QImageConsumer::frameDone()
89
90 One of the two frameDone() functions will be called when a frame
91 of an animated image has ended and been revealed as changed().
92
93 When this function is called, the current image should be
94 displayed.
95
96 The decoder will not make any further changes to the image until
97 the next call to QImageFormat::decode().
98*/
99
100/*!
101 \overload void QImageConsumer::frameDone( const QPoint& offset, const QRect& rect )
102
103 One of the two frameDone() functions will be called when a frame
104 of an animated image has ended and been revealed as changed().
105
106 When this function is called, the area \a rect in the current
107 image should be moved by \a offset and displayed.
108
109 The decoder will not make any further changes to the image until
110 the next call to QImageFormat::decode().
111*/
112
113/*!
114 \fn void QImageConsumer::setLooping(int n)
115
116 Called to indicate that the sequence of frames in the image
117 should be repeated \a n times, including the sequence during
118 decoding.
119
120 \list
121 \i 0 = Forever
122 \i 1 = Only display frames the first time through
123 \i 2 = Repeat once after first pass through images
124 \i etc.
125 \endlist
126
127 To make the QImageDecoder do this, just delete it and pass the
128 information to it again for decoding (setLooping() will be called
129 again, of course, but that can be ignored), or keep copies of the
130 changed areas at the ends of frames.
131*/
132
133/*!
134 \fn void QImageConsumer::setFramePeriod(int milliseconds)
135
136 Notes that the frame about to be decoded should not be displayed
137 until the given number of \a milliseconds after the time that this
138 function is called. Of course, the image may not have been
139 decoded by then, in which case the frame should not be displayed
140 until it is complete. A value of -1 (the assumed default)
141 indicates that the image should be displayed even while it is only
142 partially loaded.
143*/
144
145/*!
146 \fn void QImageConsumer::setSize(int, int)
147
148 This function is called as soon as the size of the image has been
149 determined.
150*/
151
152
153/*!
154 \class QImageDecoder qasyncimageio.h
155 \brief The QImageDecoder class is an incremental image decoder for all supported image formats.
156
157 \ingroup images
158 \ingroup graphics
159 \ingroup multimedia
160
161 New formats are installed by creating objects of class
162 QImageFormatType; the QMovie class can be used for all installed
163 incremental image formats. QImageDecoder is only useful for
164 creating new ways of feeding data to an QImageConsumer.
165
166 A QImageDecoder is a machine that decodes images. It takes encoded
167 image data via its decode() method and expresses its decoding by
168 supplying information to a QImageConsumer. It implements its
169 decoding by using a QImageFormat created by one of the
170 currently-existing QImageFormatType factory objects.
171
172 QImageFormatType and QImageFormat are the classes that you might
173 need to implement support for additional image formats.
174
175 \legalese
176
177 Qt supports GIF reading if it is configured that way during
178 installation (see qgif.h). If it is, we are required to state that
179 "The Graphics Interchange Format(c) is the Copyright property of
180 CompuServe Incorporated. GIF(sm) is a Service Mark property of
181 CompuServe Incorporated."
182
183 \warning If you are in a country that recognizes software patents
184 and in which Unisys holds a patent on LZW compression and/or
185 decompression and you want to use GIF, Unisys may require you to
186 license that technology. Such countries include Canada, Japan,
187 the USA, France, Germany, Italy and the UK.
188
189 GIF support may be removed completely in a future version of Qt.
190 We recommend using the MNG or PNG format.
191*/
192
193static const int max_header = 32;
194
195
196
197
198
199// See qgif.h for important information regarding this option
200#if defined(QT_BUILTIN_GIF_READER) && QT_BUILTIN_GIF_READER == 1
201class QGIFFormat : public QImageFormat {
202public:
203 QGIFFormat();
204 virtual ~QGIFFormat();
205
206 int decode(QImage& img, QImageConsumer* consumer,
207 const uchar* buffer, int length);
208
209private:
210 void fillRect(QImage&, int x, int y, int w, int h, QRgb col);
211 QRgb color( uchar index ) const;
212
213 // GIF specific stuff
214 QRgb* globalcmap;
215 QRgb* localcmap;
216 QImage backingstore;
217 unsigned char hold[16];
218 bool gif89;
219 int count;
220 int ccount;
221 int expectcount;
222 enum State {
223 Header,
224 LogicalScreenDescriptor,
225 GlobalColorMap,
226 LocalColorMap,
227 Introducer,
228 ImageDescriptor,
229 TableImageLZWSize,
230 ImageDataBlockSize,
231 ImageDataBlock,
232 ExtensionLabel,
233 GraphicControlExtension,
234 ApplicationExtension,
235 NetscapeExtensionBlockSize,
236 NetscapeExtensionBlock,
237 SkipBlockSize,
238 SkipBlock,
239 Done,
240 Error
241 } state;
242 int gncols;
243 int lncols;
244 int ncols;
245 int lzwsize;
246 bool lcmap;
247 int swidth, sheight;
248 int left, top, right, bottom;
249 enum Disposal { NoDisposal, DoNotChange, RestoreBackground, RestoreImage };
250 Disposal disposal;
251 bool disposed;
252 int trans_index;
253 bool gcmap;
254 int bgcol;
255 int interlace;
256 int accum;
257 int bitcount;
258
259 enum { max_lzw_bits=12 }; // (poor-compiler's static const int)
260
261 int code_size, clear_code, end_code, max_code_size, max_code;
262 int firstcode, oldcode, incode;
263 short table[2][1<< max_lzw_bits];
264 short stack[(1<<(max_lzw_bits))*2];
265 short *sp;
266 bool needfirst;
267 int x, y;
268 int frame;
269 bool out_of_bounds;
270 bool digress;
271 void nextY(QImage& img, QImageConsumer* consumer);
272 void disposePrevious( QImage& img, QImageConsumer* consumer );
273};
274
275class QGIFFormatType : public QImageFormatType
276{
277 QImageFormat* decoderFor(const uchar* buffer, int length);
278 const char* formatName() const;
279};
280
281#endif
282
283
284class QImageDecoderPrivate
285{
286public:
287 QImageDecoderPrivate()
288 {
289 count = 0;
290 }
291
292 static void cleanup();
293
294 static void ensureFactories()
295 {
296 if ( !factories ) {
297 factories = new QPtrList<QImageFormatType>;
298// See qgif.h for important information regarding this option
299#if defined(QT_BUILTIN_GIF_READER) && QT_BUILTIN_GIF_READER == 1
300 gif_decoder_factory = new QGIFFormatType;
301#endif
302 qt_init_image_handlers();
303 qAddPostRoutine( cleanup );
304 }
305 }
306
307 static QPtrList<QImageFormatType> * factories;
308
309// See qgif.h for important information regarding this option
310#if defined(QT_BUILTIN_GIF_READER) && QT_BUILTIN_GIF_READER == 1
311 static QGIFFormatType * gif_decoder_factory;
312#endif
313
314 uchar header[max_header];
315 int count;
316};
317
318QPtrList<QImageFormatType> * QImageDecoderPrivate::factories = 0;
319// See qgif.h for important information regarding this option
320#if defined(QT_BUILTIN_GIF_READER) && QT_BUILTIN_GIF_READER == 1
321QGIFFormatType * QImageDecoderPrivate::gif_decoder_factory = 0;
322#endif
323
324
325void QImageDecoderPrivate::cleanup()
326{
327 delete factories;
328 factories = 0;
329// See qgif.h for important information regarding this option
330#if defined(QT_BUILTIN_GIF_READER) && QT_BUILTIN_GIF_READER == 1
331 delete gif_decoder_factory;
332 gif_decoder_factory = 0;
333#endif
334}
335
336
337/*!
338 Constructs a QImageDecoder that will send change information to
339 the QImageConsumer \a c.
340*/
341QImageDecoder::QImageDecoder(QImageConsumer* c)
342{
343 qt_init_image_handlers();
344 d = new QImageDecoderPrivate;
345 Q_CHECK_PTR(d);
346 consumer = c;
347 actual_decoder = 0;
348}
349
350/*!
351 Destroys a QImageDecoder. The image it built is destroyed. The
352 decoder built by the factory for the file format is destroyed. The
353 consumer for which it decoded the image is \e not destroyed.
354*/
355QImageDecoder::~QImageDecoder()
356{
357 delete d;
358 delete actual_decoder;
359}
360
361/*!
362 \fn const QImage& QImageDecoder::image()
363
364 Returns the image currently being decoded.
365*/
366
367static bool plugins_loaded = FALSE;
368
369/*!
370 Call this function to decode some data into image changes. The
371 data in \a buffer will be decoded, sending change information to
372 the QImageConsumer of this QImageDecoder until one of the change
373 functions of the consumer returns FALSE. The length of the data is
374 given in \a length.
375
376 Returns the number of bytes consumed: 0 if consumption is
377 complete, and -1 if decoding fails due to invalid data.
378*/
379int QImageDecoder::decode(const uchar* buffer, int length)
380{
381 if (!actual_decoder) {
382 int i=0;
383
384 while (i < length && d->count < max_header)
385 d->header[d->count++] = buffer[i++];
386
387 QImageDecoderPrivate::ensureFactories();
388
389 for (QImageFormatType* f = QImageDecoderPrivate::factories->first();
390 f && !actual_decoder;
391 f = QImageDecoderPrivate::factories->next())
392 {
393 actual_decoder = f->decoderFor(d->header, d->count);
394 }
395 if ( !actual_decoder && !plugins_loaded) {
396 qt_init_image_plugins();
397 plugins_loaded = TRUE;
398
399 for (QImageFormatType* f = QImageDecoderPrivate::factories->first();
400 f && !actual_decoder;
401 f = QImageDecoderPrivate::factories->next())
402 {
403 actual_decoder = f->decoderFor(d->header, d->count);
404 }
405 }
406
407 if (!actual_decoder) {
408 if ( d->count < max_header ) {
409 // not enough info yet
410 return i;
411 } else {
412 // failure - nothing matches max_header bytes
413 return -1;
414 }
415 }
416 }
417 return actual_decoder->decode(img, consumer, buffer, length);
418}
419
420/*!
421 Returns a QImageFormatType by name. This might be used when the
422 user needs to force data to be interpreted as being in a certain
423 format. \a name is one of the formats listed by
424 QImageDecoder::inputFormats(). Note that you will still need to
425 supply decodable data to result->decoderFor() before you can begin
426 decoding the data.
427*/
428QImageFormatType* QImageDecoder::format( const char* name )
429{
430 QImageDecoderPrivate::ensureFactories();
431 qt_init_image_plugins();
432
433 for (QImageFormatType* f = QImageDecoderPrivate::factories->first();
434 f;
435 f = QImageDecoderPrivate::factories->next())
436 {
437 if ( qstricmp(name,f->formatName())==0 )
438 return f;
439 }
440 return 0;
441}
442
443/*!
444 Call this function to find the name of the format of the given
445 header. The returned string is statically allocated. The function
446 will look at the first \a length characters in the \a buffer.
447
448 Returns 0 if the format is not recognized.
449*/
450const char* QImageDecoder::formatName(const uchar* buffer, int length)
451{
452 QImageDecoderPrivate::ensureFactories();
453
454 const char* name = 0;
455 for (QImageFormatType* f = QImageDecoderPrivate::factories->first();
456 f && !name;
457 f = QImageDecoderPrivate::factories->next())
458 {
459 QImageFormat *decoder = f->decoderFor(buffer, length);
460 if (decoder) {
461 name = f->formatName();
462 delete decoder;
463 }
464 }
465 if ( !name && !plugins_loaded) {
466 qt_init_image_plugins();
467 plugins_loaded = TRUE;
468 for (QImageFormatType* f = QImageDecoderPrivate::factories->first();
469 f && !name;
470 f = QImageDecoderPrivate::factories->next())
471 {
472 QImageFormat *decoder = f->decoderFor(buffer, length);
473 if (decoder) {
474 name = f->formatName();
475 delete decoder;
476 }
477 }
478 }
479
480 return name;
481}
482
483/*!
484 Returns a sorted list of formats for which asynchronous loading is
485 supported.
486*/
487QStrList QImageDecoder::inputFormats()
488{
489 QImageDecoderPrivate::ensureFactories();
490 qt_init_image_plugins();
491
492 QStrList result;
493
494 for (QImageFormatType* f = QImageDecoderPrivate::factories->first();
495 f;
496 f = QImageDecoderPrivate::factories->next())
497 {
498 if ( !result.contains( f->formatName() ) ) {
499 result.inSort( f->formatName() );
500 }
501 }
502
503 return result;
504}
505
506/*!
507 Registers the new QImageFormatType \a f. This is not needed in
508 application code because factories call this themselves.
509*/
510void QImageDecoder::registerDecoderFactory(QImageFormatType* f)
511{
512 QImageDecoderPrivate::ensureFactories();
513
514 QImageDecoderPrivate::factories->insert(0,f);
515}
516
517/*!
518 Unregisters the QImageFormatType \a f. This is not needed in
519 application code because factories call this themselves.
520*/
521void QImageDecoder::unregisterDecoderFactory(QImageFormatType* f)
522{
523 if ( !QImageDecoderPrivate::factories )
524 return;
525
526 QImageDecoderPrivate::factories->remove(f);
527}
528
529/*!
530 \class QImageFormat qasyncimageio.h
531 \brief The QImageFormat class is an incremental image decoder for a specific image format.
532
533 \ingroup images
534 \ingroup graphics
535 \ingroup multimedia
536
537 By making a derived class of QImageFormatType, which in turn
538 creates objects that are a subclass of QImageFormat, you can add
539 support for more incremental image formats, allowing such formats
540 to be sources for a QMovie or for the first frame of the image
541 stream to be loaded as a QImage or QPixmap.
542
543 Your new subclass must reimplement the decode() function in order
544 to process your new format.
545
546 New QImageFormat objects are generated by new QImageFormatType
547 factories.
548*/
549
550/*!
551 Destroys the object.
552
553 \internal
554 More importantly, destroys derived classes.
555*/
556QImageFormat::~QImageFormat()
557{
558}
559
560/*!
561 \fn int QImageFormat::decode(QImage& img, QImageConsumer* consumer, const uchar* buffer, int length)
562
563 New subclasses must reimplement this method.
564
565 It should decode some or all of the bytes from \a buffer into \a
566 img, calling the methods of \a consumer as the decoding proceeds
567 to inform that consumer of changes to the image. The length of the
568 data is given in \a length. The consumer may be 0, in which case
569 the function should just process the data into \a img without
570 telling any consumer about the changes. Note that the decoder must
571 store enough state to be able to continue in subsequent calls to
572 this method - this is the essence of the incremental image
573 loading.
574
575 The function should return without processing all the data if it
576 reaches the end of a frame in the input.
577
578 The function must return the number of bytes it has processed.
579*/
580
581/*!
582 \class QImageFormatType qasyncimageio.h
583 \brief The QImageFormatType class is a factory that makes QImageFormat objects.
584
585 \ingroup images
586 \ingroup graphics
587 \ingroup multimedia
588
589 Whereas the QImageIO class allows for \e complete loading of
590 images, QImageFormatType allows for \e incremental loading of
591 images.
592
593 New image file formats are installed by creating objects of
594 derived classes of QImageFormatType. They must implement
595 decoderFor() and formatName().
596
597 QImageFormatType is a very simple class. Its only task is to
598 recognize image data in some format and make a new object,
599 subclassed from QImageFormat, which can decode that format.
600
601 The factories for formats built into Qt are automatically defined
602 before any other factory is initialized. If two factories would
603 recognize an image format, the factory created last will override
604 the earlier one; you can thus override current and future built-in
605 formats.
606*/
607
608/*!
609 \fn virtual QImageFormat* QImageFormatType::decoderFor(const uchar* buffer, int length)
610
611 Returns a decoder for decoding an image that starts with the bytes
612 in \a buffer. The length of the data is given in \a length. This
613 function should only return a decoder if it is certain that the
614 decoder applies to data with the given header. Returns 0 if there
615 is insufficient data in the header to make a positive
616 identification or if the data is not recognized.
617*/
618
619/*!
620 \fn virtual const char* QImageFormatType::formatName() const
621
622 Returns the name of the format supported by decoders from this
623 factory. The string is statically allocated.
624*/
625
626/*!
627 Constructs a factory. It automatically registers itself with
628 QImageDecoder.
629*/
630QImageFormatType::QImageFormatType()
631{
632 QImageDecoder::registerDecoderFactory(this);
633}
634
635/*!
636 Destroys a factory. It automatically unregisters itself from
637 QImageDecoder.
638*/
639QImageFormatType::~QImageFormatType()
640{
641 QImageDecoder::unregisterDecoderFactory(this);
642}
643
644
645/*!
646 Returns TRUE if Qt was compiled with built-in GIF reading support;
647 otherwise returns FALSE.
648*/
649bool qt_builtin_gif_reader()
650{
651#if defined(QT_BUILTIN_GIF_READER)
652 return QT_BUILTIN_GIF_READER == 1;
653#else
654 return 0;
655#endif
656}
657
658// See qgif.h for important information regarding this option
659#if defined(QT_BUILTIN_GIF_READER) && QT_BUILTIN_GIF_READER == 1
660
661/* -- NOTDOC
662 \class QGIFFormat qasyncimageio.h
663 \brief Incremental image decoder for GIF image format.
664
665 \ingroup images
666 \ingroup graphics
667
668 This subclass of QImageFormat decodes GIF format images,
669 including animated GIFs. Internally in
670*/
671
672/*!
673 Constructs a QGIFFormat.
674*/
675QGIFFormat::QGIFFormat()
676{
677 globalcmap = 0;
678 localcmap = 0;
679 lncols = 0;
680 gncols = 0;
681 disposal = NoDisposal;
682 out_of_bounds = FALSE;
683 disposed = TRUE;
684 frame = -1;
685 state = Header;
686 count = 0;
687 lcmap = FALSE;
688}
689
690/*!
691 Destroys a QGIFFormat.
692*/
693QGIFFormat::~QGIFFormat()
694{
695 if (globalcmap) delete[] globalcmap;
696 if ( localcmap ) delete[] localcmap;
697}
698
699
700/* -- NOTDOC
701 \class QGIFFormatType qasyncimageio.h
702 \brief Incremental image decoder for GIF image format.
703
704 \ingroup images
705 \ingroup graphics
706
707 This subclass of QImageFormatType recognizes GIF
708 format images, creating a QGIFFormat when required. An instance
709 of this class is created automatically before any other factories,
710 so you should have no need for such objects.
711*/
712
713QImageFormat* QGIFFormatType::decoderFor(
714 const uchar* buffer, int length)
715{
716 if (length < 6) return 0;
717 if (buffer[0]=='G'
718 && buffer[1]=='I'
719 && buffer[2]=='F'
720 && buffer[3]=='8'
721 && (buffer[4]=='9' || buffer[4]=='7')
722 && buffer[5]=='a')
723 return new QGIFFormat;
724 return 0;
725}
726
727const char* QGIFFormatType::formatName() const
728{
729 return "GIF";
730}
731
732
733void QGIFFormat::disposePrevious( QImage& img, QImageConsumer* consumer )
734{
735 if ( out_of_bounds ) // flush anything that survived
736 consumer->changed(QRect(0,0,swidth,sheight));
737
738 // Handle disposal of previous image before processing next one
739
740 if ( disposed ) return;
741
742 int l = QMIN(swidth-1,left);
743 int r = QMIN(swidth-1,right);
744 int t = QMIN(sheight-1,top);
745 int b = QMIN(sheight-1,bottom);
746
747 switch (disposal) {
748 case NoDisposal:
749 break;
750 case DoNotChange:
751 break;
752 case RestoreBackground:
753 if (trans_index>=0) {
754 // Easy: we use the transparent color
755 fillRect(img, l, t, r-l+1, b-t+1, Q_TRANSPARENT);
756 } else if (bgcol>=0) {
757 // Easy: we use the bgcol given
758 fillRect(img, l, t, r-l+1, b-t+1, color(bgcol));
759 } else {
760 // Impossible: We don't know of a bgcol - use pixel 0
761 QRgb** line = (QRgb **)img.jumpTable();
762 fillRect(img, l, t, r-l+1, b-t+1, line[0][0]);
763 }
764 if (consumer)
765 consumer->changed(QRect(l, t, r-l+1, b-t+1));
766 break;
767 case RestoreImage: {
768 if ( frame > 0 ) {
769 QRgb** line = (QRgb **)img.jumpTable();
770 for (int ln=t; ln<=b; ln++) {
771 memcpy(line[ln]+l,
772 backingstore.scanLine(ln-t),
773 (r-l+1)*sizeof(QRgb) );
774 }
775 consumer->changed(QRect(l, t, r-l+1, b-t+1));
776 }
777 }
778 }
779 disposal = NoDisposal; // Until an extension says otherwise.
780
781 disposed = TRUE;
782}
783
784/*!
785 This function decodes some data into image changes.
786
787 Returns the number of bytes consumed.
788*/
789int QGIFFormat::decode(QImage& img, QImageConsumer* consumer,
790 const uchar* buffer, int length)
791{
792 // We are required to state that
793 // "The Graphics Interchange Format(c) is the Copyright property of
794 // CompuServe Incorporated. GIF(sm) is a Service Mark property of
795 // CompuServe Incorporated."
796
797#define LM(l, m) (((m)<<8)|l)
798 digress = FALSE;
799 int initial = length;
800 QRgb** line = (QRgb **)img.jumpTable();
801 while (!digress && length) {
802 length--;
803 unsigned char ch=*buffer++;
804 switch (state) {
805 case Header:
806 hold[count++]=ch;
807 if (count==6) {
808 // Header
809 gif89=(hold[3]!='8' || hold[4]!='7');
810 state=LogicalScreenDescriptor;
811 count=0;
812 }
813 break;
814 case LogicalScreenDescriptor:
815 hold[count++]=ch;
816 if (count==7) {
817 // Logical Screen Descriptor
818 swidth=LM(hold[0], hold[1]);
819 sheight=LM(hold[2], hold[3]);
820 gcmap=!!(hold[4]&0x80);
821 //UNUSED: bpchan=(((hold[4]&0x70)>>3)+1);
822 //UNUSED: gcmsortflag=!!(hold[4]&0x08);
823 gncols=2<<(hold[4]&0x7);
824 bgcol=(gcmap) ? hold[5] : -1;
825 //aspect=hold[6] ? double(hold[6]+15)/64.0 : 1.0;
826
827 trans_index = -1;
828 count=0;
829 ncols=gncols;
830 if (gcmap) {
831 ccount=0;
832 state=GlobalColorMap;
833 globalcmap = new QRgb[gncols+1]; // +1 for trans_index
834 globalcmap[gncols] = Q_TRANSPARENT;
835 } else {
836 state=Introducer;
837 }
838 }
839 break;
840 case GlobalColorMap: case LocalColorMap:
841 hold[count++]=ch;
842 if (count==3) {
843 QRgb rgb = qRgb(hold[0], hold[1], hold[2]);
844 if ( state == LocalColorMap ) {
845 if ( ccount < lncols )
846 localcmap[ccount] = rgb;
847 } else {
848 globalcmap[ccount] = rgb;
849 }
850 if (++ccount >= ncols) {
851 if ( state == LocalColorMap )
852 state=TableImageLZWSize;
853 else
854 state=Introducer;
855 }
856 count=0;
857 }
858 break;
859 case Introducer:
860 hold[count++]=ch;
861 switch (ch) {
862 case ',':
863 state=ImageDescriptor;
864 break;
865 case '!':
866 state=ExtensionLabel;
867 break;
868 case ';':
869 if (consumer) {
870 if ( out_of_bounds ) // flush anything that survived
871 consumer->changed(QRect(0,0,swidth,sheight));
872 consumer->end();
873 }
874 state=Done;
875 break;
876 default:
877 digress=TRUE;
878 // Unexpected Introducer - ignore block
879 state=Error;
880 }
881 break;
882 case ImageDescriptor:
883 hold[count++]=ch;
884 if (count==10) {
885 int newleft=LM(hold[1], hold[2]);
886 int newtop=LM(hold[3], hold[4]);
887 int width=LM(hold[5], hold[6]);
888 int height=LM(hold[7], hold[8]);
889
890 // disbelieve ridiculous logical screen sizes,
891 // unless the image frames are also large.
892 if ( swidth/10 > QMAX(width,200) )
893 swidth = -1;
894 if ( sheight/10 > QMAX(height,200) )
895 sheight = -1;
896
897 if ( swidth <= 0 )
898 swidth = newleft + width;
899 if ( sheight <= 0 )
900 sheight = newtop + height;
901
902 if (img.isNull()) {
903 img.create(swidth, sheight, 32);
904 memset( img.bits(), 0, img.numBytes() );
905 if (consumer) consumer->setSize(swidth, sheight);
906 }
907 img.setAlphaBuffer(trans_index >= 0);
908 line = (QRgb **)img.jumpTable();
909
910 disposePrevious( img, consumer );
911 disposed = FALSE;
912
913 left = newleft;
914 top = newtop;
915
916 // Sanity check frame size - must fit on "screen".
917 if (left >= swidth) left=QMAX(0, swidth-1);
918 if (top >= sheight) top=QMAX(0, sheight-1);
919 if (left+width >= swidth) {
920 if ( width <= swidth )
921 left=swidth-width;
922 else
923 width=swidth-left;
924 }
925 if (top+height >= sheight) {
926 if ( height <= sheight )
927 top=sheight-height;
928 else
929 height=sheight-top;
930 }
931
932 right=QMAX( 0, left+width-1);
933 bottom=QMAX(0, top+height-1);
934 lcmap=!!(hold[9]&0x80);
935 interlace=!!(hold[9]&0x40);
936 //bool lcmsortflag=!!(hold[9]&0x20);
937 lncols=lcmap ? (2<<(hold[9]&0x7)) : 0;
938 if (lncols) {
939 if ( localcmap )
940 delete [] localcmap;
941 localcmap = new QRgb[lncols+1];
942 localcmap[lncols] = Q_TRANSPARENT;
943 ncols = lncols;
944 } else {
945 ncols = gncols;
946 }
947 frame++;
948 if ( frame == 0 ) {
949 if ( left || top || width!=swidth || height!=sheight ) {
950 // Not full-size image - erase with bg or transparent
951 if ( trans_index >= 0 ) {
952 fillRect(img, 0, 0, swidth, sheight, color(trans_index));
953 if (consumer) consumer->changed(QRect(0,0,swidth,sheight));
954 } else if ( bgcol>=0 ) {
955 fillRect(img, 0, 0, swidth, sheight, color(bgcol));
956 if (consumer) consumer->changed(QRect(0,0,swidth,sheight));
957 }
958 }
959 }
960
961 if ( disposal == RestoreImage ) {
962 int l = QMIN(swidth-1,left);
963 int r = QMIN(swidth-1,right);
964 int t = QMIN(sheight-1,top);
965 int b = QMIN(sheight-1,bottom);
966 int w = r-l+1;
967 int h = b-t+1;
968
969 if (backingstore.width() < w
970 || backingstore.height() < h) {
971 // We just use the backing store as a byte array
972 backingstore.create( QMAX(backingstore.width(), w),
973 QMAX(backingstore.height(), h),
974 32);
975 memset( img.bits(), 0, img.numBytes() );
976 }
977 for (int ln=0; ln<h; ln++) {
978 memcpy(backingstore.scanLine(ln),
979 line[t+ln]+l, w*sizeof(QRgb));
980 }
981 }
982
983 count=0;
984 if (lcmap) {
985 ccount=0;
986 state=LocalColorMap;
987 } else {
988 state=TableImageLZWSize;
989 }
990 x = left;
991 y = top;
992 accum = 0;
993 bitcount = 0;
994 sp = stack;
995 needfirst = FALSE;
996 out_of_bounds = FALSE;
997 }
998 break;
999 case TableImageLZWSize: {
1000 lzwsize=ch;
1001 if ( lzwsize > max_lzw_bits ) {
1002 state=Error;
1003 } else {
1004 code_size=lzwsize+1;
1005 clear_code=1<<lzwsize;
1006 end_code=clear_code+1;
1007 max_code_size=2*clear_code;
1008 max_code=clear_code+2;
1009 int i;
1010 for (i=0; i<clear_code && i<(1<<max_lzw_bits); i++) {
1011 table[0][i]=0;
1012 table[1][i]=i;
1013 }
1014 for (i=clear_code; i<(1<<max_lzw_bits); i++) {
1015 table[0][i]=table[1][i]=0;
1016 }
1017 state=ImageDataBlockSize;
1018 }
1019 count=0;
1020 break;
1021 } case ImageDataBlockSize:
1022 expectcount=ch;
1023 if (expectcount) {
1024 state=ImageDataBlock;
1025 } else {
1026 if (consumer) {
1027 consumer->frameDone();
1028 digress = TRUE;
1029 }
1030
1031 state=Introducer;
1032 }
1033 break;
1034 case ImageDataBlock:
1035 count++;
1036 accum|=(ch<<bitcount);
1037 bitcount+=8;
1038 while (bitcount>=code_size && state==ImageDataBlock) {
1039 int code=accum&((1<<code_size)-1);
1040 bitcount-=code_size;
1041 accum>>=code_size;
1042
1043 if (code==clear_code) {
1044 if (!needfirst) {
1045 int i;
1046 code_size=lzwsize+1;
1047 max_code_size=2*clear_code;
1048 max_code=clear_code+2;
1049 for (i=0; i<clear_code; i++) {
1050 table[0][i]=0;
1051 table[1][i]=i;
1052 }
1053 for (i=clear_code; i<(1<<max_lzw_bits); i++) {
1054 table[0][i]=table[1][i]=0;
1055 }
1056 }
1057 needfirst=TRUE;
1058 } else if (code==end_code) {
1059 bitcount = -32768;
1060 // Left the block end arrive
1061 } else {
1062 if (needfirst) {
1063 firstcode=oldcode=code;
1064 if (!out_of_bounds && line && firstcode!=trans_index)
1065 line[y][x] = color(firstcode);
1066 x++;
1067 if (x>=swidth) out_of_bounds = TRUE;
1068 needfirst=FALSE;
1069 if (x>right) {
1070 x=left;
1071 if (out_of_bounds)
1072 out_of_bounds = left>=swidth || y>=sheight;
1073 nextY(img,consumer);
1074 }
1075 } else {
1076 incode=code;
1077 if (code>=max_code) {
1078 *sp++=firstcode;
1079 code=oldcode;
1080 }
1081 while (code>=clear_code) {
1082 *sp++=table[1][code];
1083 if (code==table[0][code]) {
1084 state=Error;
1085 break;
1086 }
1087 if (sp-stack>=(1<<(max_lzw_bits))*2) {
1088 state=Error;
1089 break;
1090 }
1091 code=table[0][code];
1092 }
1093 *sp++=firstcode=table[1][code];
1094 code=max_code;
1095 if (code<(1<<max_lzw_bits)) {
1096 table[0][code]=oldcode;
1097 table[1][code]=firstcode;
1098 max_code++;
1099 if ((max_code>=max_code_size)
1100 && (max_code_size<(1<<max_lzw_bits)))
1101 {
1102 max_code_size*=2;
1103 code_size++;
1104 }
1105 }
1106 oldcode=incode;
1107 while (sp>stack) {
1108 --sp;
1109 if (!out_of_bounds && *sp!=trans_index)
1110 line[y][x] = color(*sp);
1111 x++;
1112 if (x>=swidth) out_of_bounds = TRUE;
1113 if (x>right) {
1114 x=left;
1115 if (out_of_bounds)
1116 out_of_bounds = left>=swidth || y>=sheight;
1117 nextY(img,consumer);
1118 }
1119 }
1120 }
1121 }
1122 }
1123 if (count==expectcount) {
1124 count=0;
1125 state=ImageDataBlockSize;
1126 }
1127 break;
1128 case ExtensionLabel:
1129 switch (ch) {
1130 case 0xf9:
1131 state=GraphicControlExtension;
1132 break;
1133 case 0xff:
1134 state=ApplicationExtension;
1135 break;
1136#if 0
1137 case 0xfe:
1138 state=CommentExtension;
1139 break;
1140 case 0x01:
1141 break;
1142#endif
1143 default:
1144 state=SkipBlockSize;
1145 }
1146 count=0;
1147 break;
1148 case ApplicationExtension:
1149 if (count<11) hold[count]=ch;
1150 count++;
1151 if (count==hold[0]+1) {
1152 if (qstrncmp((char*)(hold+1), "NETSCAPE", 8)==0) {
1153 // Looping extension
1154 state=NetscapeExtensionBlockSize;
1155 } else {
1156 state=SkipBlockSize;
1157 }
1158 count=0;
1159 }
1160 break;
1161 case NetscapeExtensionBlockSize:
1162 expectcount=ch;
1163 count=0;
1164 if (expectcount) state=NetscapeExtensionBlock;
1165 else state=Introducer;
1166 break;
1167 case NetscapeExtensionBlock:
1168 if (count<3) hold[count]=ch;
1169 count++;
1170 if (count==expectcount) {
1171 int loop = hold[0]+hold[1]*256;
1172 if (consumer) consumer->setLooping(loop);
1173 state=SkipBlockSize; // Ignore further blocks
1174 }
1175 break;
1176 case GraphicControlExtension:
1177 if (count<5) hold[count]=ch;
1178 count++;
1179 if (count==hold[0]+1) {
1180 disposePrevious( img, consumer );
1181 disposal=Disposal((hold[1]>>2)&0x7);
1182 //UNUSED: waitforuser=!!((hold[1]>>1)&0x1);
1183 int delay=count>3 ? LM(hold[2], hold[3]) : 1;
1184 // IE and mozilla use a minimum delay of 10. With the minumum delay of 10
1185 // we are compatible to them and avoid huge loads on the app and xserver.
1186 if ( delay < 10 )
1187 delay = 10;
1188
1189 bool havetrans=hold[1]&0x1;
1190 trans_index = havetrans ? hold[4] : -1;
1191
1192 if (consumer) consumer->setFramePeriod(delay*10);
1193 count=0;
1194 state=SkipBlockSize;
1195 }
1196 break;
1197 case SkipBlockSize:
1198 expectcount=ch;
1199 count=0;
1200 if (expectcount) state=SkipBlock;
1201 else state=Introducer;
1202 break;
1203 case SkipBlock:
1204 count++;
1205 if (count==expectcount) state=SkipBlockSize;
1206 break;
1207 case Done:
1208 digress=TRUE;
1209 /* Netscape ignores the junk, so we do too.
1210 length++; // Unget
1211 state=Error; // More calls to this is an error
1212 */
1213 break;
1214 case Error:
1215 return -1; // Called again after done.
1216 }
1217 }
1218 return initial-length;
1219}
1220
1221void QGIFFormat::fillRect(QImage& img, int col, int row, int w, int h, QRgb color)
1222{
1223 if (w>0) {
1224 QRgb** line = (QRgb **)img.jumpTable() + row;
1225 for (int j=0; j<h; j++) {
1226 for ( int i=0; i<w; i++ ) {
1227 *(line[j]+col+i) = color;
1228 }
1229 }
1230 }
1231}
1232
1233void QGIFFormat::nextY(QImage& img, QImageConsumer* consumer)
1234{
1235 int my;
1236 switch (interlace) {
1237 case 0:
1238 // Non-interlaced
1239 if (consumer && !out_of_bounds)
1240 consumer->changed(QRect(left, y, right-left+1, 1));
1241 y++;
1242 break;
1243 case 1:
1244 {
1245 int i;
1246 my = QMIN(7, bottom-y);
1247 if ( trans_index < 0 ) // Don't dup with transparency
1248 for (i=1; i<=my; i++)
1249 memcpy(img.scanLine(y+i)+left, img.scanLine(y)+left,
1250 (right-left+1)*sizeof(QRgb));
1251 if (consumer && !out_of_bounds)
1252 consumer->changed(QRect(left, y, right-left+1, my+1));
1253 y+=8;
1254 if (y>bottom) {
1255 interlace++; y=top+4;
1256 if (y > bottom) { // for really broken GIFs with bottom < 5
1257 interlace=2;
1258 y = top + 2;
1259 if (y > bottom) { // for really broken GIF with bottom < 3
1260 interlace = 0;
1261 y = top + 1;
1262 }
1263 }
1264 }
1265 } break;
1266 case 2:
1267 {
1268 int i;
1269 my = QMIN(3, bottom-y);
1270 if ( trans_index < 0 ) // Don't dup with transparency
1271 for (i=1; i<=my; i++)
1272 memcpy(img.scanLine(y+i)+left, img.scanLine(y)+left,
1273 (right-left+1)*sizeof(QRgb));
1274 if (consumer && !out_of_bounds)
1275 consumer->changed(QRect(left, y, right-left+1, my+1));
1276 y+=8;
1277 if (y>bottom) {
1278 interlace++; y=top+2;
1279 if (y > bottom) { // for really broken GIF with bottom < 3
1280 interlace = 3;
1281 y = top + 1;
1282 }
1283 }
1284 } break;
1285 case 3:
1286 {
1287 int i;
1288 my = QMIN(1, bottom-y);
1289 if ( trans_index < 0 ) // Don't dup with transparency
1290 for (i=1; i<=my; i++)
1291 memcpy(img.scanLine(y+i)+left, img.scanLine(y)+left,
1292 (right-left+1)*sizeof(QRgb));
1293 if (consumer && !out_of_bounds)
1294 consumer->changed(QRect(left, y, right-left+1, my+1));
1295 y+=4;
1296 if (y>bottom) { interlace++; y=top+1; }
1297 } break;
1298 case 4:
1299 if (consumer && !out_of_bounds)
1300 consumer->changed(QRect(left, y, right-left+1, 1));
1301 y+=2;
1302 }
1303
1304 // Consume bogus extra lines
1305 if (y >= sheight) out_of_bounds=TRUE; //y=bottom;
1306}
1307
1308QRgb QGIFFormat::color( uchar index ) const
1309{
1310 if ( index == trans_index || index > ncols )
1311 return Q_TRANSPARENT;
1312 QRgb *map = lcmap ? localcmap : globalcmap;
1313 return map ? map[index] : 0;
1314}
1315
1316
1317
1318#endif // QT_BUILTIN_GIF_READER
1319
1320#endif // QT_NO_ASYNC_IMAGE_IO
Note: See TracBrowser for help on using the repository browser.