Commit df845cfdc305eefe37f621d37ad894c13752ed47

  • avatar
  • zecke
  • Mon Dec 14 09:38:58 GMT 2009
gif: Change size request handling to not decode the full image

http://bugreports.qt.nokia.com/browse/QTBUG-6696

If asked for the size do not decode the full image. Return the
last size or decode until seeing the image size. The decoding
will be resumed from this position when asked for the image.

Refactor driving the decoder into its own method to reduce
code clones and increase readability.

This makes the image_loading reudction 4x faster going from
80msec to around 20msec.
src/plugins/imageformats/gif/qgifhandler.cpp
(51 / 34)
  
5656
5757// avoid going through QImage::scanLine() which calls detach
5858#define FAST_SCAN_LINE(bits, bpl, y) (bits + (y) * bpl)
59#define GIF_CHUNK_SIZE 4096
5960
60
6161/*
6262 Incremental image decoder for GIF image format.
6363
6767
6868class QGIFFormat {
6969public:
70 enum QueryMode {
71 QuerySize,
72 QueryAll,
73 };
74
7075 QGIFFormat();
7176 ~QGIFFormat();
7277
7378 int decode(QImage *image, const uchar* buffer, int length,
74 int *nextFrameDelay, int *loopCount, QSize *nextSize);
79 int *nextFrameDelay, int *loopCount, QSize *nextSize, int mode = QueryAll);
7580
7681 bool newFrame;
7782 bool partialNewFrame;
234234 Returns the number of bytes consumed.
235235*/
236236int QGIFFormat::decode(QImage *image, const uchar *buffer, int length,
237 int *nextFrameDelay, int *loopCount, QSize *nextSize)
237 int *nextFrameDelay, int *loopCount, QSize *nextSize, int mode)
238238{
239239 // We are required to state that
240240 // "The Graphics Interchange Format(c) is the Copyright property of
346346 sheight = newtop + newheight;
347347
348348 QImage::Format format = trans_index >= 0 ? QImage::Format_ARGB32 : QImage::Format_RGB32;
349 if (image->isNull()) {
349 if (image->isNull() || (mode == QuerySize && nextSize->isEmpty())) {
350 // ### size of the upcoming frame, should rather
351 // be known before decoding it.
352 *nextSize = QSize(swidth, sheight);
353
354 // Only the size of the image should be decoded. Make sure that on
355 // the next entry to the ::decode method we come here again. Do
356 // this by reducing the count and claiming that the ImageDescriptor
357 // has not been processed.
358 if (mode == QuerySize) {
359 --count;
360 return initial-length - 1;
361 }
362
350363 (*image) = QImage(swidth, sheight, format);
351364 bpl = image->bytesPerLine();
352365 bits = image->bits();
353366 memset(bits, 0, image->byteCount());
354
355 // ### size of the upcoming frame, should rather
356 // be known before decoding it.
357 *nextSize = QSize(swidth, sheight);
358367 }
359368
360369 disposePrevious(image);
791791
792792bool QGifHandler::imageIsComing() const
793793{
794 const int GifChunkSize = 4096;
795
796794 while (!gifFormat->partialNewFrame) {
797 if (buffer.isEmpty()) {
798 buffer += device()->read(GifChunkSize);
799 if (buffer.isEmpty())
800 break;
801 }
802
803 int decoded = gifFormat->decode(&lastImage, (const uchar *)buffer.constData(), buffer.size(),
804 &nextDelay, &loopCnt, &nextSize);
805 if (decoded == -1)
795 if (!decode(QGIFFormat::QueryAll))
806796 break;
807 buffer.remove(0, decoded);
808797 }
809798 return gifFormat->partialNewFrame;
810799}
824824
825825bool QGifHandler::read(QImage *image)
826826{
827 const int GifChunkSize = 4096;
828
829827 while (!gifFormat->newFrame) {
830 if (buffer.isEmpty()) {
831 buffer += device()->read(GifChunkSize);
832 if (buffer.isEmpty())
833 break;
834 }
835
836 int decoded = gifFormat->decode(&lastImage, (const uchar *)buffer.constData(), buffer.size(),
837 &nextDelay, &loopCnt, &nextSize);
838 if (decoded == -1)
828 if (!decode(QGIFFormat::QueryAll))
839829 break;
840 buffer.remove(0, decoded);
841830 }
842831 if (gifFormat->newFrame || (gifFormat->partialNewFrame && device()->atEnd())) {
843832 *image = lastImage;
854854QVariant QGifHandler::option(ImageOption option) const
855855{
856856 if (option == Size) {
857 if (imageIsComing())
858 return nextSize;
857 // Reset the size when we are not within a frame.
858 if (!gifFormat->partialNewFrame)
859 nextSize = QSize();
860 while (nextSize.isEmpty()) {
861 if (!decode(QGIFFormat::QuerySize)) {
862 break;
863 }
864 }
865
866 return nextSize;
859867 } else if (option == Animation) {
860868 return true;
861869 }
899899QByteArray QGifHandler::name() const
900900{
901901 return "gif";
902}
903
904bool QGifHandler::decode(int mode) const
905{
906 if (buffer.isEmpty()) {
907 buffer += device()->read(GIF_CHUNK_SIZE);
908 if (buffer.isEmpty())
909 return false;
910 }
911
912 int decoded = gifFormat->decode(&lastImage, (const uchar *)buffer.constData(), buffer.size(),
913 &nextDelay, &loopCnt, &nextSize, mode);
914 if (decoded == -1)
915 return false;
916
917 buffer.remove(0, decoded);
918 return true;
902919}
903920
904921QT_END_NAMESPACE
src/plugins/imageformats/gif/qgifhandler.h
(1 / 0)
  
7878 int currentImageNumber() const;
7979
8080private:
81 bool decode(int mode) const;
8182 bool imageIsComing() const;
8283 QGIFFormat *gifFormat;
8384 QString fileName;

Comments

Add a new comment:

Login or create an account to post a comment

Add your comment