summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/image/image.pri10
-rw-r--r--src/gui/image/qgifhandler.cpp1218
-rw-r--r--src/gui/image/qgifhandler.pri3
-rw-r--r--src/gui/image/qgifhandler_p.h105
-rw-r--r--src/gui/image/qimagereader.cpp41
-rw-r--r--src/gui/image/qimagewriter.cpp20
-rw-r--r--src/gui/image/qjpeghandler.cpp1144
-rw-r--r--src/gui/image/qjpeghandler.pri11
-rw-r--r--src/gui/image/qjpeghandler_p.h85
-rw-r--r--src/gui/image/qpnghandler.pri4
10 files changed, 5 insertions, 2636 deletions
diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri
index 8db944e5e3..657b57c0cd 100644
--- a/src/gui/image/image.pri
+++ b/src/gui/image/image.pri
@@ -71,11 +71,11 @@ SOURCES += \
image/qxbmhandler.cpp \
image/qxpmhandler.cpp
-!contains(QT_CONFIG, no-png):include($$PWD/qpnghandler.pri)
-else:DEFINES *= QT_NO_IMAGEFORMAT_PNG
-
-contains(QT_CONFIG, jpeg):include($$PWD/qjpeghandler.pri)
-contains(QT_CONFIG, gif):include($$PWD/qgifhandler.pri)
+contains(QT_CONFIG, png) {
+ HEADERS += image/qpnghandler_p.h
+ SOURCES += image/qpnghandler.cpp
+ include($$PWD/../../3rdparty/png_dependency.pri)
+}
# SIMD
SSE2_SOURCES += image/qimage_sse2.cpp
diff --git a/src/gui/image/qgifhandler.cpp b/src/gui/image/qgifhandler.cpp
deleted file mode 100644
index 476b456563..0000000000
--- a/src/gui/image/qgifhandler.cpp
+++ /dev/null
@@ -1,1218 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-** WARNING:
-** A separate license from Unisys may be required to use the gif
-** reader. See http://www.unisys.com/about__unisys/lzw/
-** for information from Unisys
-**
-****************************************************************************/
-
-#include "qgifhandler_p.h"
-
-#include <qimage.h>
-#include <qiodevice.h>
-#include <qvariant.h>
-
-QT_BEGIN_NAMESPACE
-
-#define Q_TRANSPARENT 0x00ffffff
-
-// avoid going through QImage::scanLine() which calls detach
-#define FAST_SCAN_LINE(bits, bpl, y) (bits + (y) * bpl)
-
-
-/*
- Incremental image decoder for GIF image format.
-
- This subclass of QImageFormat decodes GIF format images,
- including animated GIFs. Internally in
-*/
-
-class QGIFFormat {
-public:
- QGIFFormat();
- ~QGIFFormat();
-
- int decode(QImage *image, const uchar* buffer, int length,
- int *nextFrameDelay, int *loopCount);
- static void scan(QIODevice *device, QVector<QSize> *imageSizes, int *loopCount);
-
- bool newFrame;
- bool partialNewFrame;
-
-private:
- void fillRect(QImage *image, int x, int y, int w, int h, QRgb col);
- inline QRgb color(uchar index) const;
-
- // GIF specific stuff
- QRgb* globalcmap;
- QRgb* localcmap;
- QImage backingstore;
- unsigned char hold[16];
- bool gif89;
- int count;
- int ccount;
- int expectcount;
- enum State {
- Header,
- LogicalScreenDescriptor,
- GlobalColorMap,
- LocalColorMap,
- Introducer,
- ImageDescriptor,
- TableImageLZWSize,
- ImageDataBlockSize,
- ImageDataBlock,
- ExtensionLabel,
- GraphicControlExtension,
- ApplicationExtension,
- NetscapeExtensionBlockSize,
- NetscapeExtensionBlock,
- SkipBlockSize,
- SkipBlock,
- Done,
- Error
- } state;
- int gncols;
- int lncols;
- int ncols;
- int lzwsize;
- bool lcmap;
- int swidth, sheight;
- int width, height;
- int left, top, right, bottom;
- enum Disposal { NoDisposal, DoNotChange, RestoreBackground, RestoreImage };
- Disposal disposal;
- bool disposed;
- int trans_index;
- bool gcmap;
- int bgcol;
- int interlace;
- int accum;
- int bitcount;
-
- enum { max_lzw_bits=12 }; // (poor-compiler's static const int)
-
- int code_size, clear_code, end_code, max_code_size, max_code;
- int firstcode, oldcode, incode;
- short* table[2];
- short* stack;
- short *sp;
- bool needfirst;
- int x, y;
- int frame;
- bool out_of_bounds;
- bool digress;
- void nextY(unsigned char *bits, int bpl);
- void disposePrevious(QImage *image);
-};
-
-/*!
- Constructs a QGIFFormat.
-*/
-QGIFFormat::QGIFFormat()
-{
- globalcmap = 0;
- localcmap = 0;
- lncols = 0;
- gncols = 0;
- disposal = NoDisposal;
- out_of_bounds = false;
- disposed = true;
- frame = -1;
- state = Header;
- count = 0;
- lcmap = false;
- newFrame = false;
- partialNewFrame = false;
- table[0] = 0;
- table[1] = 0;
- stack = 0;
-}
-
-/*!
- Destroys a QGIFFormat.
-*/
-QGIFFormat::~QGIFFormat()
-{
- if (globalcmap) delete[] globalcmap;
- if (localcmap) delete[] localcmap;
- delete [] stack;
-}
-
-void QGIFFormat::disposePrevious(QImage *image)
-{
- if (out_of_bounds) {
- // flush anything that survived
- // ### Changed: QRect(0, 0, swidth, sheight)
- }
-
- // Handle disposal of previous image before processing next one
-
- if (disposed) return;
-
- int l = qMin(swidth-1,left);
- int r = qMin(swidth-1,right);
- int t = qMin(sheight-1,top);
- int b = qMin(sheight-1,bottom);
-
- switch (disposal) {
- case NoDisposal:
- break;
- case DoNotChange:
- break;
- case RestoreBackground:
- if (trans_index>=0) {
- // Easy: we use the transparent color
- fillRect(image, l, t, r-l+1, b-t+1, Q_TRANSPARENT);
- } else if (bgcol>=0) {
- // Easy: we use the bgcol given
- fillRect(image, l, t, r-l+1, b-t+1, color(bgcol));
- } else {
- // Impossible: We don't know of a bgcol - use pixel 0
- const QRgb *bits = reinterpret_cast<const QRgb *>(image->constBits());
- fillRect(image, l, t, r-l+1, b-t+1, bits[0]);
- }
- // ### Changed: QRect(l, t, r-l+1, b-t+1)
- break;
- case RestoreImage: {
- if (frame >= 0) {
- for (int ln=t; ln<=b; ln++) {
- memcpy(image->scanLine(ln)+l,
- backingstore.constScanLine(ln-t),
- (r-l+1)*sizeof(QRgb));
- }
- // ### Changed: QRect(l, t, r-l+1, b-t+1)
- }
- }
- }
- disposal = NoDisposal; // Until an extension says otherwise.
-
- disposed = true;
-}
-
-/*!
- This function decodes some data into image changes.
-
- Returns the number of bytes consumed.
-*/
-int QGIFFormat::decode(QImage *image, const uchar *buffer, int length,
- int *nextFrameDelay, int *loopCount)
-{
- // We are required to state that
- // "The Graphics Interchange Format(c) is the Copyright property of
- // CompuServe Incorporated. GIF(sm) is a Service Mark property of
- // CompuServe Incorporated."
-
- if (!stack) {
- stack = new short[(1 << max_lzw_bits) * 4];
- table[0] = &stack[(1 << max_lzw_bits) * 2];
- table[1] = &stack[(1 << max_lzw_bits) * 3];
- }
-
- image->detach();
- int bpl = image->bytesPerLine();
- unsigned char *bits = image->bits();
-
-#define LM(l, m) (((m)<<8)|l)
- digress = false;
- const int initial = length;
- while (!digress && length) {
- length--;
- unsigned char ch=*buffer++;
- switch (state) {
- case Header:
- hold[count++]=ch;
- if (count==6) {
- // Header
- gif89=(hold[3]!='8' || hold[4]!='7');
- state=LogicalScreenDescriptor;
- count=0;
- }
- break;
- case LogicalScreenDescriptor:
- hold[count++]=ch;
- if (count==7) {
- // Logical Screen Descriptor
- swidth=LM(hold[0], hold[1]);
- sheight=LM(hold[2], hold[3]);
- gcmap=!!(hold[4]&0x80);
- //UNUSED: bpchan=(((hold[4]&0x70)>>3)+1);
- //UNUSED: gcmsortflag=!!(hold[4]&0x08);
- gncols=2<<(hold[4]&0x7);
- bgcol=(gcmap) ? hold[5] : -1;
- //aspect=hold[6] ? double(hold[6]+15)/64.0 : 1.0;
-
- trans_index = -1;
- count=0;
- ncols=gncols;
- if (gcmap) {
- ccount=0;
- state=GlobalColorMap;
- globalcmap = new QRgb[gncols+1]; // +1 for trans_index
- globalcmap[gncols] = Q_TRANSPARENT;
- } else {
- state=Introducer;
- }
- }
- break;
- case GlobalColorMap: case LocalColorMap:
- hold[count++]=ch;
- if (count==3) {
- QRgb rgb = qRgb(hold[0], hold[1], hold[2]);
- if (state == LocalColorMap) {
- if (ccount < lncols)
- localcmap[ccount] = rgb;
- } else {
- globalcmap[ccount] = rgb;
- }
- if (++ccount >= ncols) {
- if (state == LocalColorMap)
- state=TableImageLZWSize;
- else
- state=Introducer;
- }
- count=0;
- }
- break;
- case Introducer:
- hold[count++]=ch;
- switch (ch) {
- case ',':
- state=ImageDescriptor;
- break;
- case '!':
- state=ExtensionLabel;
- break;
- case ';':
- // ### Changed: QRect(0, 0, swidth, sheight)
- state=Done;
- break;
- default:
- digress=true;
- // Unexpected Introducer - ignore block
- state=Error;
- }
- break;
- case ImageDescriptor:
- hold[count++]=ch;
- if (count==10) {
- int newleft=LM(hold[1], hold[2]);
- int newtop=LM(hold[3], hold[4]);
- int newwidth=LM(hold[5], hold[6]);
- int newheight=LM(hold[7], hold[8]);
-
- // disbelieve ridiculous logical screen sizes,
- // unless the image frames are also large.
- if (swidth/10 > qMax(newwidth,200))
- swidth = -1;
- if (sheight/10 > qMax(newheight,200))
- sheight = -1;
-
- if (swidth <= 0)
- swidth = newleft + newwidth;
- if (sheight <= 0)
- sheight = newtop + newheight;
-
- QImage::Format format = trans_index >= 0 ? QImage::Format_ARGB32 : QImage::Format_RGB32;
- if (image->isNull()) {
- (*image) = QImage(swidth, sheight, format);
- bpl = image->bytesPerLine();
- bits = image->bits();
- memset(bits, 0, image->byteCount());
- }
-
- // Check if the previous attempt to create the image failed. If it
- // did then the image is broken and we should give up.
- if (image->isNull()) {
- state = Error;
- return -1;
- }
-
- disposePrevious(image);
- disposed = false;
-
- left = newleft;
- top = newtop;
- width = newwidth;
- height = newheight;
-
- right=qMax(0, qMin(left+width, swidth)-1);
- bottom=qMax(0, qMin(top+height, sheight)-1);
- lcmap=!!(hold[9]&0x80);
- interlace=!!(hold[9]&0x40);
- //bool lcmsortflag=!!(hold[9]&0x20);
- lncols=lcmap ? (2<<(hold[9]&0x7)) : 0;
- if (lncols) {
- if (localcmap)
- delete [] localcmap;
- localcmap = new QRgb[lncols+1];
- localcmap[lncols] = Q_TRANSPARENT;
- ncols = lncols;
- } else {
- ncols = gncols;
- }
- frame++;
- if (frame == 0) {
- if (left || top || width<swidth || height<sheight) {
- // Not full-size image - erase with bg or transparent
- if (trans_index >= 0) {
- fillRect(image, 0, 0, swidth, sheight, color(trans_index));
- // ### Changed: QRect(0, 0, swidth, sheight)
- } else if (bgcol>=0) {
- fillRect(image, 0, 0, swidth, sheight, color(bgcol));
- // ### Changed: QRect(0, 0, swidth, sheight)
- }
- }
- }
-
- if (disposal == RestoreImage) {
- int l = qMin(swidth-1,left);
- int r = qMin(swidth-1,right);
- int t = qMin(sheight-1,top);
- int b = qMin(sheight-1,bottom);
- int w = r-l+1;
- int h = b-t+1;
-
- if (backingstore.width() < w
- || backingstore.height() < h) {
- // We just use the backing store as a byte array
- backingstore = QImage(qMax(backingstore.width(), w),
- qMax(backingstore.height(), h),
- QImage::Format_RGB32);
- memset(bits, 0, image->byteCount());
- }
- const int dest_bpl = backingstore.bytesPerLine();
- unsigned char *dest_data = backingstore.bits();
- for (int ln=0; ln<h; ln++) {
- memcpy(FAST_SCAN_LINE(dest_data, dest_bpl, ln),
- FAST_SCAN_LINE(bits, bpl, t+ln) + l, w*sizeof(QRgb));
- }
- }
-
- count=0;
- if (lcmap) {
- ccount=0;
- state=LocalColorMap;
- } else {
- state=TableImageLZWSize;
- }
- x = left;
- y = top;
- accum = 0;
- bitcount = 0;
- sp = stack;
- firstcode = oldcode = 0;
- needfirst = true;
- out_of_bounds = left>=swidth || y>=sheight;
- }
- break;
- case TableImageLZWSize: {
- lzwsize=ch;
- if (lzwsize > max_lzw_bits) {
- state=Error;
- } else {
- code_size=lzwsize+1;
- clear_code=1<<lzwsize;
- end_code=clear_code+1;
- max_code_size=2*clear_code;
- max_code=clear_code+2;
- int i;
- for (i=0; i<clear_code; i++) {
- table[0][i]=0;
- table[1][i]=i;
- }
- state=ImageDataBlockSize;
- }
- count=0;
- break;
- } case ImageDataBlockSize:
- expectcount=ch;
- if (expectcount) {
- state=ImageDataBlock;
- } else {
- state=Introducer;
- digress = true;
- newFrame = true;
- }
- break;
- case ImageDataBlock:
- count++;
- accum|=(ch<<bitcount);
- bitcount+=8;
- while (bitcount>=code_size && state==ImageDataBlock) {
- int code=accum&((1<<code_size)-1);
- bitcount-=code_size;
- accum>>=code_size;
-
- if (code==clear_code) {
- if (!needfirst) {
- code_size=lzwsize+1;
- max_code_size=2*clear_code;
- max_code=clear_code+2;
- }
- needfirst=true;
- } else if (code==end_code) {
- bitcount = -32768;
- // Left the block end arrive
- } else {
- if (needfirst) {
- firstcode=oldcode=code;
- if (!out_of_bounds && image->height() > y && ((frame == 0) || (firstcode != trans_index)))
- ((QRgb*)FAST_SCAN_LINE(bits, bpl, y))[x] = color(firstcode);
- x++;
- if (x>=swidth) out_of_bounds = true;
- needfirst=false;
- if (x>=left+width) {
- x=left;
- out_of_bounds = left>=swidth || y>=sheight;
- nextY(bits, bpl);
- }
- } else {
- incode=code;
- if (code>=max_code) {
- *sp++=firstcode;
- code=oldcode;
- }
- while (code>=clear_code+2) {
- if (code >= max_code) {
- state = Error;
- return -1;
- }
- *sp++=table[1][code];
- if (code==table[0][code]) {
- state=Error;
- return -1;
- }
- if (sp-stack>=(1<<(max_lzw_bits))*2) {
- state=Error;
- return -1;
- }
- code=table[0][code];
- }
- if (code < 0) {
- state = Error;
- return -1;
- }
-
- *sp++=firstcode=table[1][code];
- code=max_code;
- if (code<(1<<max_lzw_bits)) {
- table[0][code]=oldcode;
- table[1][code]=firstcode;
- max_code++;
- if ((max_code>=max_code_size)
- && (max_code_size<(1<<max_lzw_bits)))
- {
- max_code_size*=2;
- code_size++;
- }
- }
- oldcode=incode;
- const int h = image->height();
- QRgb *line = 0;
- if (!out_of_bounds && h > y)
- line = (QRgb*)FAST_SCAN_LINE(bits, bpl, y);
- while (sp>stack) {
- const uchar index = *(--sp);
- if (!out_of_bounds && h > y && ((frame == 0) || (index != trans_index))) {
- line[x] = color(index);
- }
- x++;
- if (x>=swidth) out_of_bounds = true;
- if (x>=left+width) {
- x=left;
- out_of_bounds = left>=swidth || y>=sheight;
- nextY(bits, bpl);
- if (!out_of_bounds && h > y)
- line = (QRgb*)FAST_SCAN_LINE(bits, bpl, y);
- }
- }
- }
- }
- }
- partialNewFrame = true;
- if (count==expectcount) {
- count=0;
- state=ImageDataBlockSize;
- }
- break;
- case ExtensionLabel:
- switch (ch) {
- case 0xf9:
- state=GraphicControlExtension;
- break;
- case 0xff:
- state=ApplicationExtension;
- break;
-#if 0
- case 0xfe:
- state=CommentExtension;
- break;
- case 0x01:
- break;
-#endif
- default:
- state=SkipBlockSize;
- }
- count=0;
- break;
- case ApplicationExtension:
- if (count<11) hold[count]=ch;
- count++;
- if (count==hold[0]+1) {
- if (qstrncmp((char*)(hold+1), "NETSCAPE", 8)==0) {
- // Looping extension
- state=NetscapeExtensionBlockSize;
- } else {
- state=SkipBlockSize;
- }
- count=0;
- }
- break;
- case NetscapeExtensionBlockSize:
- expectcount=ch;
- count=0;
- if (expectcount) state=NetscapeExtensionBlock;
- else state=Introducer;
- break;
- case NetscapeExtensionBlock:
- if (count<3) hold[count]=ch;
- count++;
- if (count==expectcount) {
- *loopCount = hold[1]+hold[2]*256;
- state=SkipBlockSize; // Ignore further blocks
- }
- break;
- case GraphicControlExtension:
- if (count<5) hold[count]=ch;
- count++;
- if (count==hold[0]+1) {
- disposePrevious(image);
- disposal=Disposal((hold[1]>>2)&0x7);
- //UNUSED: waitforuser=!!((hold[1]>>1)&0x1);
- int delay=count>3 ? LM(hold[2], hold[3]) : 1;
- // IE and mozilla use a minimum delay of 10. With the minimum delay of 10
- // we are compatible to them and avoid huge loads on the app and xserver.
- *nextFrameDelay = (delay < 2 ? 10 : delay) * 10;
-
- bool havetrans=hold[1]&0x1;
- trans_index = havetrans ? hold[4] : -1;
-
- count=0;
- state=SkipBlockSize;
- }
- break;
- case SkipBlockSize:
- expectcount=ch;
- count=0;
- if (expectcount) state=SkipBlock;
- else state=Introducer;
- break;
- case SkipBlock:
- count++;
- if (count==expectcount) state=SkipBlockSize;
- break;
- case Done:
- digress=true;
- /* Netscape ignores the junk, so we do too.
- length++; // Unget
- state=Error; // More calls to this is an error
- */
- break;
- case Error:
- return -1; // Called again after done.
- }
- }
- return initial-length;
-}
-
-/*!
- Scans through the data stream defined by \a device and returns the image
- sizes found in the stream in the \a imageSizes vector.
-*/
-void QGIFFormat::scan(QIODevice *device, QVector<QSize> *imageSizes, int *loopCount)
-{
- if (!device)
- return;
-
- qint64 oldPos = device->pos();
- if (device->isSequential() || !device->seek(0))
- return;
-
- int colorCount = 0;
- int localColorCount = 0;
- int globalColorCount = 0;
- int colorReadCount = 0;
- bool localColormap = false;
- bool globalColormap = false;
- int count = 0;
- int blockSize = 0;
- int imageWidth = 0;
- int imageHeight = 0;
- bool done = false;
- uchar hold[16];
- State state = Header;
-
- const int readBufferSize = 40960; // 40k read buffer
- QByteArray readBuffer(device->read(readBufferSize));
-
- if (readBuffer.isEmpty()) {
- device->seek(oldPos);
- return;
- }
-
- // This is a specialized version of the state machine from decode(),
- // which doesn't do any image decoding or mallocing, and has an
- // optimized way of skipping SkipBlocks, ImageDataBlocks and
- // Global/LocalColorMaps.
-
- while (!readBuffer.isEmpty()) {
- int length = readBuffer.size();
- const uchar *buffer = (const uchar *) readBuffer.constData();
- while (!done && length) {
- length--;
- uchar ch = *buffer++;
- switch (state) {
- case Header:
- hold[count++] = ch;
- if (count == 6) {
- state = LogicalScreenDescriptor;
- count = 0;
- }
- break;
- case LogicalScreenDescriptor:
- hold[count++] = ch;
- if (count == 7) {
- imageWidth = LM(hold[0], hold[1]);
- imageHeight = LM(hold[2], hold[3]);
- globalColormap = !!(hold[4] & 0x80);
- globalColorCount = 2 << (hold[4] & 0x7);
- count = 0;
- colorCount = globalColorCount;
- if (globalColormap) {
- int colorTableSize = 3 * globalColorCount;
- if (length >= colorTableSize) {
- // skip the global color table in one go
- length -= colorTableSize;
- buffer += colorTableSize;
- state = Introducer;
- } else {
- colorReadCount = 0;
- state = GlobalColorMap;
- }
- } else {
- state=Introducer;
- }
- }
- break;
- case GlobalColorMap:
- case LocalColorMap:
- hold[count++] = ch;
- if (count == 3) {
- if (++colorReadCount >= colorCount) {
- if (state == LocalColorMap)
- state = TableImageLZWSize;
- else
- state = Introducer;
- }
- count = 0;
- }
- break;
- case Introducer:
- hold[count++] = ch;
- switch (ch) {
- case 0x2c:
- state = ImageDescriptor;
- break;
- case 0x21:
- state = ExtensionLabel;
- break;
- case 0x3b:
- state = Done;
- break;
- default:
- done = true;
- state = Error;
- }
- break;
- case ImageDescriptor:
- hold[count++] = ch;
- if (count == 10) {
- int newLeft = LM(hold[1], hold[2]);
- int newTop = LM(hold[3], hold[4]);
- int newWidth = LM(hold[5], hold[6]);
- int newHeight = LM(hold[7], hold[8]);
-
- if (imageWidth/10 > qMax(newWidth,200))
- imageWidth = -1;
- if (imageHeight/10 > qMax(newHeight,200))
- imageHeight = -1;
-
- if (imageWidth <= 0)
- imageWidth = newLeft + newWidth;
- if (imageHeight <= 0)
- imageHeight = newTop + newHeight;
-
- *imageSizes << QSize(imageWidth, imageHeight);
-
- localColormap = !!(hold[9] & 0x80);
- localColorCount = localColormap ? (2 << (hold[9] & 0x7)) : 0;
- if (localColorCount)
- colorCount = localColorCount;
- else
- colorCount = globalColorCount;
-
- count = 0;
- if (localColormap) {
- int colorTableSize = 3 * localColorCount;
- if (length >= colorTableSize) {
- // skip the local color table in one go
- length -= colorTableSize;
- buffer += colorTableSize;
- state = TableImageLZWSize;
- } else {
- colorReadCount = 0;
- state = LocalColorMap;
- }
- } else {
- state = TableImageLZWSize;
- }
- }
- break;
- case TableImageLZWSize:
- if (ch > max_lzw_bits)
- state = Error;
- else
- state = ImageDataBlockSize;
- count = 0;
- break;
- case ImageDataBlockSize:
- blockSize = ch;
- if (blockSize) {
- if (length >= blockSize) {
- // we can skip the block in one go
- length -= blockSize;
- buffer += blockSize;
- count = 0;
- } else {
- state = ImageDataBlock;
- }
- } else {
- state = Introducer;
- }
- break;
- case ImageDataBlock:
- ++count;
- if (count == blockSize) {
- count = 0;
- state = ImageDataBlockSize;
- }
- break;
- case ExtensionLabel:
- switch (ch) {
- case 0xf9:
- state = GraphicControlExtension;
- break;
- case 0xff:
- state = ApplicationExtension;
- break;
- default:
- state = SkipBlockSize;
- }
- count = 0;
- break;
- case ApplicationExtension:
- if (count < 11)
- hold[count] = ch;
- ++count;
- if (count == hold[0] + 1) {
- if (qstrncmp((char*)(hold+1), "NETSCAPE", 8) == 0)
- state=NetscapeExtensionBlockSize;
- else
- state=SkipBlockSize;
- count = 0;
- }
- break;
- case GraphicControlExtension:
- if (count < 5)
- hold[count] = ch;
- ++count;
- if (count == hold[0] + 1) {
- count = 0;
- state = SkipBlockSize;
- }
- break;
- case NetscapeExtensionBlockSize:
- blockSize = ch;
- count = 0;
- if (blockSize)
- state = NetscapeExtensionBlock;
- else
- state = Introducer;
- break;
- case NetscapeExtensionBlock:
- if (count < 3)
- hold[count] = ch;
- count++;
- if (count == blockSize) {
- *loopCount = LM(hold[1], hold[2]);
- state = SkipBlockSize;
- }
- break;
- case SkipBlockSize:
- blockSize = ch;
- count = 0;
- if (blockSize) {
- if (length >= blockSize) {
- // we can skip the block in one go
- length -= blockSize;
- buffer += blockSize;
- } else {
- state = SkipBlock;
- }
- } else {
- state = Introducer;
- }
- break;
- case SkipBlock:
- ++count;
- if (count == blockSize)
- state = SkipBlockSize;
- break;
- case Done:
- done = true;
- break;
- case Error:
- device->seek(oldPos);
- return;
- }
- }
- readBuffer = device->read(readBufferSize);
- }
- device->seek(oldPos);
- return;
-}
-
-void QGIFFormat::fillRect(QImage *image, int col, int row, int w, int h, QRgb color)
-{
- if (w>0) {
- for (int j=0; j<h; j++) {
- QRgb *line = (QRgb*)image->scanLine(j+row);
- for (int i=0; i<w; i++)
- *(line+col+i) = color;
- }
- }
-}
-
-void QGIFFormat::nextY(unsigned char *bits, int bpl)
-{
- if (out_of_bounds)
- return;
- int my;
- switch (interlace) {
- case 0: // Non-interlaced
- // if (!out_of_bounds) {
- // ### Changed: QRect(left, y, right - left + 1, 1);
- // }
- y++;
- break;
- case 1: {
- int i;
- my = qMin(7, bottom-y);
- // Don't dup with transparency
- if (trans_index < 0) {
- for (i=1; i<=my; i++) {
- memcpy(FAST_SCAN_LINE(bits, bpl, y+i)+left*sizeof(QRgb), FAST_SCAN_LINE(bits, bpl, y)+left*sizeof(QRgb),
- (right-left+1)*sizeof(QRgb));
- }
- }
-
- // if (!out_of_bounds) {
- // ### Changed: QRect(left, y, right - left + 1, my + 1);
- // }
-// if (!out_of_bounds)
-// qDebug("consumer->changed(QRect(%d, %d, %d, %d))", left, y, right-left+1, my+1);
- y+=8;
- if (y>bottom) {
- interlace++; y=top+4;
- if (y > bottom) { // for really broken GIFs with bottom < 5
- interlace=2;
- y = top + 2;
- if (y > bottom) { // for really broken GIF with bottom < 3
- interlace = 0;
- y = top + 1;
- }
- }
- }
- } break;
- case 2: {
- int i;
- my = qMin(3, bottom-y);
- // Don't dup with transparency
- if (trans_index < 0) {
- for (i=1; i<=my; i++) {
- memcpy(FAST_SCAN_LINE(bits, bpl, y+i)+left*sizeof(QRgb), FAST_SCAN_LINE(bits, bpl, y)+left*sizeof(QRgb),
- (right-left+1)*sizeof(QRgb));
- }
- }
-
- // if (!out_of_bounds) {
- // ### Changed: QRect(left, y, right - left + 1, my + 1);
- // }
- y+=8;
- if (y>bottom) {
- interlace++; y=top+2;
- // handle broken GIF with bottom < 3
- if (y > bottom) {
- interlace = 3;
- y = top + 1;
- }
- }
- } break;
- case 3: {
- int i;
- my = qMin(1, bottom-y);
- // Don't dup with transparency
- if (trans_index < 0) {
- for (i=1; i<=my; i++) {
- memcpy(FAST_SCAN_LINE(bits, bpl, y+i)+left*sizeof(QRgb), FAST_SCAN_LINE(bits, bpl, y)+left*sizeof(QRgb),
- (right-left+1)*sizeof(QRgb));
- }
- }
- // if (!out_of_bounds) {
- // ### Changed: QRect(left, y, right - left + 1, my + 1);
- // }
- y+=4;
- if (y>bottom) { interlace++; y=top+1; }
- } break;
- case 4:
- // if (!out_of_bounds) {
- // ### Changed: QRect(left, y, right - left + 1, 1);
- // }
- y+=2;
- }
-
- // Consume bogus extra lines
- if (y >= sheight) out_of_bounds=true; //y=bottom;
-}
-
-inline QRgb QGIFFormat::color(uchar index) const
-{
- if (index > ncols)
- return Q_TRANSPARENT;
-
- QRgb *map = lcmap ? localcmap : globalcmap;
- QRgb col = map ? map[index] : 0;
- return index == trans_index ? col & Q_TRANSPARENT : col;
-}
-
-//-------------------------------------------------------------------------
-//-------------------------------------------------------------------------
-//-------------------------------------------------------------------------
-
-QGifHandler::QGifHandler()
-{
- gifFormat = new QGIFFormat;
- nextDelay = 100;
- loopCnt = -1;
- frameNumber = -1;
- scanIsCached = false;
-}
-
-QGifHandler::~QGifHandler()
-{
- delete gifFormat;
-}
-
-// Does partial decode if necessary, just to see if an image is coming
-
-bool QGifHandler::imageIsComing() const
-{
- const int GifChunkSize = 4096;
-
- while (!gifFormat->partialNewFrame) {
- if (buffer.isEmpty()) {
- buffer += device()->read(GifChunkSize);
- if (buffer.isEmpty())
- break;
- }
-
- int decoded = gifFormat->decode(&lastImage, (const uchar *)buffer.constData(), buffer.size(),
- &nextDelay, &loopCnt);
- if (decoded == -1)
- break;
- buffer.remove(0, decoded);
- }
- return gifFormat->partialNewFrame;
-}
-
-bool QGifHandler::canRead() const
-{
- if (canRead(device()) || imageIsComing()) {
- setFormat("gif");
- return true;
- }
-
- return false;
-}
-
-bool QGifHandler::canRead(QIODevice *device)
-{
- if (!device) {
- qWarning("QGifHandler::canRead() called with no device");
- return false;
- }
-
- char head[6];
- if (device->peek(head, sizeof(head)) == sizeof(head))
- return qstrncmp(head, "GIF87a", 6) == 0
- || qstrncmp(head, "GIF89a", 6) == 0;
- return false;
-}
-
-bool QGifHandler::read(QImage *image)
-{
- const int GifChunkSize = 4096;
-
- while (!gifFormat->newFrame) {
- if (buffer.isEmpty()) {
- buffer += device()->read(GifChunkSize);
- if (buffer.isEmpty())
- break;
- }
-
- int decoded = gifFormat->decode(&lastImage, (const uchar *)buffer.constData(), buffer.size(),
- &nextDelay, &loopCnt);
- if (decoded == -1)
- break;
- buffer.remove(0, decoded);
- }
- if (gifFormat->newFrame || (gifFormat->partialNewFrame && device()->atEnd())) {
- *image = lastImage;
- ++frameNumber;
- gifFormat->newFrame = false;
- gifFormat->partialNewFrame = false;
- return true;
- }
-
- return false;
-}
-
-bool QGifHandler::write(const QImage &image)
-{
- Q_UNUSED(image);
- return false;
-}
-
-bool QGifHandler::supportsOption(ImageOption option) const
-{
- if (!device() || device()->isSequential())
- return option == Animation;
- else
- return option == Size
- || option == Animation;
-}
-
-QVariant QGifHandler::option(ImageOption option) const
-{
- if (option == Size) {
- if (!scanIsCached) {
- QGIFFormat::scan(device(), &imageSizes, &loopCnt);
- scanIsCached = true;
- }
- // before the first frame is read, or we have an empty data stream
- if (frameNumber == -1)
- return (imageSizes.count() > 0) ? QVariant(imageSizes.at(0)) : QVariant();
- // after the last frame has been read, the next size is undefined
- if (frameNumber >= imageSizes.count() - 1)
- return QVariant();
- // and the last case: the size of the next frame
- return imageSizes.at(frameNumber + 1);
- } else if (option == Animation) {
- return true;
- }
- return QVariant();
-}
-
-void QGifHandler::setOption(ImageOption option, const QVariant &value)
-{
- Q_UNUSED(option);
- Q_UNUSED(value);
-}
-
-int QGifHandler::nextImageDelay() const
-{
- return nextDelay;
-}
-
-int QGifHandler::imageCount() const
-{
- if (!scanIsCached) {
- QGIFFormat::scan(device(), &imageSizes, &loopCnt);
- scanIsCached = true;
- }
- return imageSizes.count();
-}
-
-int QGifHandler::loopCount() const
-{
- if (!scanIsCached) {
- QGIFFormat::scan(device(), &imageSizes, &loopCnt);
- scanIsCached = true;
- }
-
- if (loopCnt == 0)
- return -1;
- else if (loopCnt == -1)
- return 0;
- else
- return loopCnt;
-}
-
-int QGifHandler::currentImageNumber() const
-{
- return frameNumber;
-}
-
-QByteArray QGifHandler::name() const
-{
- return "gif";
-}
-
-QT_END_NAMESPACE
diff --git a/src/gui/image/qgifhandler.pri b/src/gui/image/qgifhandler.pri
deleted file mode 100644
index ec33101451..0000000000
--- a/src/gui/image/qgifhandler.pri
+++ /dev/null
@@ -1,3 +0,0 @@
-# common to plugin and built-in forms
-HEADERS += $$PWD/qgifhandler_p.h
-SOURCES += $$PWD/qgifhandler.cpp
diff --git a/src/gui/image/qgifhandler_p.h b/src/gui/image/qgifhandler_p.h
deleted file mode 100644
index bc3debe83c..0000000000
--- a/src/gui/image/qgifhandler_p.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-** WARNING:
-** A separate license from Unisys may be required to use the gif
-** reader. See http://www.unisys.com/about__unisys/lzw/
-** for information from Unisys
-**
-****************************************************************************/
-
-#ifndef QGIFHANDLER_P_H
-#define QGIFHANDLER_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtGui/qimageiohandler.h>
-#include <QtGui/qimage.h>
-#include <QtCore/qbytearray.h>
-
-QT_BEGIN_NAMESPACE
-
-class QGIFFormat;
-class QGifHandler : public QImageIOHandler
-{
-public:
- QGifHandler();
- ~QGifHandler();
-
- bool canRead() const Q_DECL_OVERRIDE;
- bool read(QImage *image) Q_DECL_OVERRIDE;
- bool write(const QImage &image) Q_DECL_OVERRIDE;
-
- QByteArray name() const Q_DECL_OVERRIDE;
-
- static bool canRead(QIODevice *device);
-
- QVariant option(ImageOption option) const Q_DECL_OVERRIDE;
- void setOption(ImageOption option, const QVariant &value) Q_DECL_OVERRIDE;
- bool supportsOption(ImageOption option) const Q_DECL_OVERRIDE;
-
- int imageCount() const Q_DECL_OVERRIDE;
- int loopCount() const Q_DECL_OVERRIDE;
- int nextImageDelay() const Q_DECL_OVERRIDE;
- int currentImageNumber() const Q_DECL_OVERRIDE;
-
-private:
- bool imageIsComing() const;
- QGIFFormat *gifFormat;
- QString fileName;
- mutable QByteArray buffer;
- mutable QImage lastImage;
-
- mutable int nextDelay;
- mutable int loopCnt;
- int frameNumber;
- mutable QVector<QSize> imageSizes;
- mutable bool scanIsCached;
-};
-
-QT_END_NAMESPACE
-
-#endif // QGIFHANDLER_P_H
diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp
index 4dada4ca82..8bf0ce3523 100644
--- a/src/gui/image/qimagereader.cpp
+++ b/src/gui/image/qimagereader.cpp
@@ -155,12 +155,6 @@
#ifndef QT_NO_IMAGEFORMAT_PNG
#include <private/qpnghandler_p.h>
#endif
-#ifndef QT_NO_IMAGEFORMAT_JPEG
-#include <private/qjpeghandler_p.h>
-#endif
-#ifdef QT_BUILTIN_GIF_READER
-#include <private/qgifhandler_p.h>
-#endif
#include <algorithm>
@@ -175,13 +169,6 @@ enum _qt_BuiltInFormatType {
#ifndef QT_NO_IMAGEFORMAT_PNG
_qt_PngFormat,
#endif
-#ifndef QT_NO_IMAGEFORMAT_JPEG
- _qt_JpgFormat,
- _qt_JpegFormat,
-#endif
-#ifdef QT_BUILTIN_GIF_READER
- _qt_GifFormat,
-#endif
#ifndef QT_NO_IMAGEFORMAT_BMP
_qt_BmpFormat,
#endif
@@ -210,13 +197,6 @@ static const _qt_BuiltInFormatStruct _qt_BuiltInFormats[] = {
#ifndef QT_NO_IMAGEFORMAT_PNG
{"png", "image/png"},
#endif
-#ifndef QT_NO_IMAGEFORMAT_JPEG
- {"jpg", "image/jpeg"},
- {"jpeg", "image/jpeg"},
-#endif
-#ifdef QT_BUILTIN_GIF_READER
- {"gif", "image/gif"},
-#endif
#ifndef QT_NO_IMAGEFORMAT_BMP
{"bmp", "image/bmp"},
#endif
@@ -357,14 +337,6 @@ static QImageIOHandler *createReadHandlerHelper(QIODevice *device,
} else if (testFormat == "png") {
handler = new QPngHandler;
#endif
-#ifndef QT_NO_IMAGEFORMAT_JPEG
- } else if (testFormat == "jpg" || testFormat == "jpeg") {
- handler = new QJpegHandler;
-#endif
-#ifdef QT_BUILTIN_GIF_READER
- } else if (testFormat == "gif") {
- handler = new QGifHandler;
-#endif
#ifndef QT_NO_IMAGEFORMAT_BMP
} else if (testFormat == "bmp") {
handler = new QBmpHandler;
@@ -442,19 +414,6 @@ static QImageIOHandler *createReadHandlerHelper(QIODevice *device,
handler = new QPngHandler;
break;
#endif
-#ifndef QT_NO_IMAGEFORMAT_JPEG
- case _qt_JpgFormat:
- case _qt_JpegFormat:
- if (QJpegHandler::canRead(device))
- handler = new QJpegHandler;
- break;
-#endif
-#ifdef QT_BUILTIN_GIF_READER
- case _qt_GifFormat:
- if (QGifHandler::canRead(device))
- handler = new QGifHandler;
- break;
-#endif
#ifndef QT_NO_IMAGEFORMAT_BMP
case _qt_BmpFormat:
if (QBmpHandler::canRead(device))
diff --git a/src/gui/image/qimagewriter.cpp b/src/gui/image/qimagewriter.cpp
index b60cf59864..ddf9f2dda9 100644
--- a/src/gui/image/qimagewriter.cpp
+++ b/src/gui/image/qimagewriter.cpp
@@ -115,12 +115,6 @@
#ifndef QT_NO_IMAGEFORMAT_PNG
#include <private/qpnghandler_p.h>
#endif
-#ifndef QT_NO_IMAGEFORMAT_JPEG
-#include <private/qjpeghandler_p.h>
-#endif
-#ifdef QT_BUILTIN_GIF_READER
-#include <private/qgifhandler_p.h>
-#endif
#include <algorithm>
@@ -184,14 +178,6 @@ static QImageIOHandler *createWriteHandlerHelper(QIODevice *device,
} else if (testFormat == "png") {
handler = new QPngHandler;
#endif
-#ifndef QT_NO_IMAGEFORMAT_JPEG
- } else if (testFormat == "jpg" || testFormat == "jpeg") {
- handler = new QJpegHandler;
-#endif
-#ifdef QT_BUILTIN_GIF_READER
- } else if (testFormat == "gif") {
- handler = new QGifHandler;
-#endif
#ifndef QT_NO_IMAGEFORMAT_BMP
} else if (testFormat == "bmp") {
handler = new QBmpHandler;
@@ -910,9 +896,6 @@ QList<QByteArray> QImageWriter::supportedImageFormats()
#ifndef QT_NO_IMAGEFORMAT_PNG
formats << "png";
#endif
-#ifndef QT_NO_IMAGEFORMAT_JPEG
- formats << "jpg" << "jpeg";
-#endif
#ifndef QT_NO_IMAGEFORMATPLUGIN
supportedImageHandlerFormats(loader(), QImageIOPlugin::CanWrite, &formats);
@@ -951,9 +934,6 @@ QList<QByteArray> QImageWriter::supportedMimeTypes()
#ifndef QT_NO_IMAGEFORMAT_PNG
mimeTypes << "image/png";
#endif
-#ifndef QT_NO_IMAGEFORMAT_JPEG
- mimeTypes << "image/jpeg";
-#endif
#ifndef QT_NO_IMAGEFORMATPLUGIN
supportedImageHandlerMimeTypes(loader(), QImageIOPlugin::CanWrite, &mimeTypes);
diff --git a/src/gui/image/qjpeghandler.cpp b/src/gui/image/qjpeghandler.cpp
deleted file mode 100644
index 52e8b39f11..0000000000
--- a/src/gui/image/qjpeghandler.cpp
+++ /dev/null
@@ -1,1144 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qjpeghandler_p.h"
-
-#include <qimage.h>
-#include <qvariant.h>
-#include <qvector.h>
-#include <qbuffer.h>
-#include <qmath.h>
-#include <private/qsimd_p.h>
-
-#include <stdio.h> // jpeglib needs this to be pre-included
-#include <setjmp.h>
-
-#ifdef FAR
-#undef FAR
-#endif
-
-// including jpeglib.h seems to be a little messy
-extern "C" {
-// mingw includes rpcndr.h but does not define boolean
-#if defined(Q_OS_WIN) && defined(Q_CC_GNU)
-# if defined(__RPCNDR_H__) && !defined(boolean)
- typedef unsigned char boolean;
-# define HAVE_BOOLEAN
-# endif
-#endif
-
-#define XMD_H // shut JPEGlib up
-#if defined(Q_OS_UNIXWARE)
-# define HAVE_BOOLEAN // libjpeg under Unixware seems to need this
-#endif
-#include <jpeglib.h>
-#ifdef const
-# undef const // remove crazy C hackery in jconfig.h
-#endif
-}
-
-QT_BEGIN_NAMESPACE
-QT_WARNING_DISABLE_GCC("-Wclobbered")
-
-Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32(quint32 *dst, const uchar *src, int len);
-typedef void (QT_FASTCALL *Rgb888ToRgb32Converter)(quint32 *dst, const uchar *src, int len);
-
-struct my_error_mgr : public jpeg_error_mgr {
- jmp_buf setjmp_buffer;
-};
-
-extern "C" {
-
-static void my_error_exit (j_common_ptr cinfo)
-{
- my_error_mgr* myerr = (my_error_mgr*) cinfo->err;
- char buffer[JMSG_LENGTH_MAX];
- (*cinfo->err->format_message)(cinfo, buffer);
- qWarning("%s", buffer);
- longjmp(myerr->setjmp_buffer, 1);
-}
-
-static void my_output_message(j_common_ptr cinfo)
-{
- char buffer[JMSG_LENGTH_MAX];
- (*cinfo->err->format_message)(cinfo, buffer);
- qWarning("%s", buffer);
-}
-
-}
-
-
-static const int max_buf = 4096;
-
-struct my_jpeg_source_mgr : public jpeg_source_mgr {
- // Nothing dynamic - cannot rely on destruction over longjump
- QIODevice *device;
- JOCTET buffer[max_buf];
- const QBuffer *memDevice;
-
-public:
- my_jpeg_source_mgr(QIODevice *device);
-};
-
-extern "C" {
-
-static void qt_init_source(j_decompress_ptr)
-{
-}
-
-static boolean qt_fill_input_buffer(j_decompress_ptr cinfo)
-{
- my_jpeg_source_mgr* src = (my_jpeg_source_mgr*)cinfo->src;
- qint64 num_read = 0;
- if (src->memDevice) {
- src->next_input_byte = (const JOCTET *)(src->memDevice->data().constData() + src->memDevice->pos());
- num_read = src->memDevice->data().size() - src->memDevice->pos();
- src->device->seek(src->memDevice->data().size());
- } else {
- src->next_input_byte = src->buffer;
- num_read = src->device->read((char*)src->buffer, max_buf);
- }
- if (num_read <= 0) {
- // Insert a fake EOI marker - as per jpeglib recommendation
- src->next_input_byte = src->buffer;
- src->buffer[0] = (JOCTET) 0xFF;
- src->buffer[1] = (JOCTET) JPEG_EOI;
- src->bytes_in_buffer = 2;
- } else {
- src->bytes_in_buffer = num_read;
- }
- return TRUE;
-}
-
-static void qt_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
-{
- my_jpeg_source_mgr* src = (my_jpeg_source_mgr*)cinfo->src;
-
- // `dumb' implementation from jpeglib
-
- /* Just a dumb implementation for now. Could use fseek() except
- * it doesn't work on pipes. Not clear that being smart is worth
- * any trouble anyway --- large skips are infrequent.
- */
- if (num_bytes > 0) {
- while (num_bytes > (long) src->bytes_in_buffer) { // Should not happen in case of memDevice
- num_bytes -= (long) src->bytes_in_buffer;
- (void) qt_fill_input_buffer(cinfo);
- /* note we assume that qt_fill_input_buffer will never return false,
- * so suspension need not be handled.
- */
- }
- src->next_input_byte += (size_t) num_bytes;
- src->bytes_in_buffer -= (size_t) num_bytes;
- }
-}
-
-static void qt_term_source(j_decompress_ptr cinfo)
-{
- my_jpeg_source_mgr* src = (my_jpeg_source_mgr*)cinfo->src;
- if (!src->device->isSequential())
- src->device->seek(src->device->pos() - src->bytes_in_buffer);
-}
-
-}
-
-inline my_jpeg_source_mgr::my_jpeg_source_mgr(QIODevice *device)
-{
- jpeg_source_mgr::init_source = qt_init_source;
- jpeg_source_mgr::fill_input_buffer = qt_fill_input_buffer;
- jpeg_source_mgr::skip_input_data = qt_skip_input_data;
- jpeg_source_mgr::resync_to_restart = jpeg_resync_to_restart;
- jpeg_source_mgr::term_source = qt_term_source;
- this->device = device;
- memDevice = qobject_cast<QBuffer *>(device);
- bytes_in_buffer = 0;
- next_input_byte = buffer;
-}
-
-
-inline static bool read_jpeg_size(int &w, int &h, j_decompress_ptr cinfo)
-{
- (void) jpeg_calc_output_dimensions(cinfo);
-
- w = cinfo->output_width;
- h = cinfo->output_height;
- return true;
-}
-
-#define HIGH_QUALITY_THRESHOLD 50
-
-inline static bool read_jpeg_format(QImage::Format &format, j_decompress_ptr cinfo)
-{
-
- bool result = true;
- switch (cinfo->output_components) {
- case 1:
- format = QImage::Format_Grayscale8;
- break;
- case 3:
- case 4:
- format = QImage::Format_RGB32;
- break;
- default:
- result = false;
- break;
- }
- cinfo->output_scanline = cinfo->output_height;
- return result;
-}
-
-static bool ensureValidImage(QImage *dest, struct jpeg_decompress_struct *info,
- const QSize& size)
-{
- QImage::Format format;
- switch (info->output_components) {
- case 1:
- format = QImage::Format_Grayscale8;
- break;
- case 3:
- case 4:
- format = QImage::Format_RGB32;
- break;
- default:
- return false; // unsupported format
- }
-
- if (dest->size() != size || dest->format() != format)
- *dest = QImage(size, format);
-
- return !dest->isNull();
-}
-
-static bool read_jpeg_image(QImage *outImage,
- QSize scaledSize, QRect scaledClipRect,
- QRect clipRect, volatile int inQuality,
- Rgb888ToRgb32Converter converter,
- j_decompress_ptr info, struct my_error_mgr* err )
-{
- if (!setjmp(err->setjmp_buffer)) {
- // -1 means default quality.
- int quality = inQuality;
- if (quality < 0)
- quality = 75;
-
- // If possible, merge the scaledClipRect into either scaledSize
- // or clipRect to avoid doing a separate scaled clipping pass.
- // Best results are achieved by clipping before scaling, not after.
- if (!scaledClipRect.isEmpty()) {
- if (scaledSize.isEmpty() && clipRect.isEmpty()) {
- // No clipping or scaling before final clip.
- clipRect = scaledClipRect;
- scaledClipRect = QRect();
- } else if (scaledSize.isEmpty()) {
- // Clipping, but no scaling: combine the clip regions.
- scaledClipRect.translate(clipRect.topLeft());
- clipRect = scaledClipRect.intersected(clipRect);
- scaledClipRect = QRect();
- } else if (clipRect.isEmpty()) {
- // No clipping, but scaling: if we can map back to an
- // integer pixel boundary, then clip before scaling.
- if ((info->image_width % scaledSize.width()) == 0 &&
- (info->image_height % scaledSize.height()) == 0) {
- int x = scaledClipRect.x() * info->image_width /
- scaledSize.width();
- int y = scaledClipRect.y() * info->image_height /
- scaledSize.height();
- int width = (scaledClipRect.right() + 1) *
- info->image_width / scaledSize.width() - x;
- int height = (scaledClipRect.bottom() + 1) *
- info->image_height / scaledSize.height() - y;
- clipRect = QRect(x, y, width, height);
- scaledSize = scaledClipRect.size();
- scaledClipRect = QRect();
- }
- } else {
- // Clipping and scaling: too difficult to figure out,
- // and not a likely use case, so do it the long way.
- }
- }
-
- // Determine the scale factor to pass to libjpeg for quick downscaling.
- if (!scaledSize.isEmpty() && info->image_width && info->image_height) {
- if (clipRect.isEmpty()) {
- double f = qMin(double(info->image_width) / scaledSize.width(),
- double(info->image_height) / scaledSize.height());
-
- // libjpeg supports M/8 scaling with M=[1,16]. All downscaling factors
- // are a speed improvement, but upscaling during decode is slower.
- info->scale_num = qBound(1, qCeil(8/f), 8);
- info->scale_denom = 8;
- } else {
- info->scale_denom = qMin(clipRect.width() / scaledSize.width(),
- clipRect.height() / scaledSize.height());
-
- // Only scale by powers of two when clipping so we can
- // keep the exact pixel boundaries
- if (info->scale_denom < 2)
- info->scale_denom = 1;
- else if (info->scale_denom < 4)
- info->scale_denom = 2;
- else if (info->scale_denom < 8)
- info->scale_denom = 4;
- else
- info->scale_denom = 8;
- info->scale_num = 1;
-
- // Correct the scale factor so that we clip accurately.
- // It is recommended that the clip rectangle be aligned
- // on an 8-pixel boundary for best performance.
- while (info->scale_denom > 1 &&
- ((clipRect.x() % info->scale_denom) != 0 ||
- (clipRect.y() % info->scale_denom) != 0 ||
- (clipRect.width() % info->scale_denom) != 0 ||
- (clipRect.height() % info->scale_denom) != 0)) {
- info->scale_denom /= 2;
- }
- }
- }
-
- // If high quality not required, use fast decompression
- if( quality < HIGH_QUALITY_THRESHOLD ) {
- info->dct_method = JDCT_IFAST;
- info->do_fancy_upsampling = FALSE;
- }
-
- (void) jpeg_calc_output_dimensions(info);
-
- // Determine the clip region to extract.
- QRect imageRect(0, 0, info->output_width, info->output_height);
- QRect clip;
- if (clipRect.isEmpty()) {
- clip = imageRect;
- } else if (info->scale_denom == info->scale_num) {
- clip = clipRect.intersected(imageRect);
- } else {
- // The scale factor was corrected above to ensure that
- // we don't miss pixels when we scale the clip rectangle.
- clip = QRect(clipRect.x() / int(info->scale_denom),
- clipRect.y() / int(info->scale_denom),
- clipRect.width() / int(info->scale_denom),
- clipRect.height() / int(info->scale_denom));
- clip = clip.intersected(imageRect);
- }
-
- // Allocate memory for the clipped QImage.
- if (!ensureValidImage(outImage, info, clip.size()))
- longjmp(err->setjmp_buffer, 1);
-
- // Avoid memcpy() overhead if grayscale with no clipping.
- bool quickGray = (info->output_components == 1 &&
- clip == imageRect);
- if (!quickGray) {
- // Ask the jpeg library to allocate a temporary row.
- // The library will automatically delete it for us later.
- // The libjpeg docs say we should do this before calling
- // jpeg_start_decompress(). We can't use "new" here
- // because we are inside the setjmp() block and an error
- // in the jpeg input stream would cause a memory leak.
- JSAMPARRAY rows = (info->mem->alloc_sarray)
- ((j_common_ptr)info, JPOOL_IMAGE,
- info->output_width * info->output_components, 1);
-
- (void) jpeg_start_decompress(info);
-
- while (info->output_scanline < info->output_height) {
- int y = int(info->output_scanline) - clip.y();
- if (y >= clip.height())
- break; // We've read the entire clip region, so abort.
-
- (void) jpeg_read_scanlines(info, rows, 1);
-
- if (y < 0)
- continue; // Haven't reached the starting line yet.
-
- if (info->output_components == 3) {
- uchar *in = rows[0] + clip.x() * 3;
- QRgb *out = (QRgb*)outImage->scanLine(y);
- converter(out, in, clip.width());
- } else if (info->out_color_space == JCS_CMYK) {
- // Convert CMYK->RGB.
- uchar *in = rows[0] + clip.x() * 4;
- QRgb *out = (QRgb*)outImage->scanLine(y);
- for (int i = 0; i < clip.width(); ++i) {
- int k = in[3];
- *out++ = qRgb(k * in[0] / 255, k * in[1] / 255,
- k * in[2] / 255);
- in += 4;
- }
- } else if (info->output_components == 1) {
- // Grayscale.
- memcpy(outImage->scanLine(y),
- rows[0] + clip.x(), clip.width());
- }
- }
- } else {
- // Load unclipped grayscale data directly into the QImage.
- (void) jpeg_start_decompress(info);
- while (info->output_scanline < info->output_height) {
- uchar *row = outImage->scanLine(info->output_scanline);
- (void) jpeg_read_scanlines(info, &row, 1);
- }
- }
-
- if (info->output_scanline == info->output_height)
- (void) jpeg_finish_decompress(info);
-
- if (info->density_unit == 1) {
- outImage->setDotsPerMeterX(int(100. * info->X_density / 2.54));
- outImage->setDotsPerMeterY(int(100. * info->Y_density / 2.54));
- } else if (info->density_unit == 2) {
- outImage->setDotsPerMeterX(int(100. * info->X_density));
- outImage->setDotsPerMeterY(int(100. * info->Y_density));
- }
-
- if (scaledSize.isValid() && scaledSize != clip.size()) {
- *outImage = outImage->scaled(scaledSize, Qt::IgnoreAspectRatio, quality >= HIGH_QUALITY_THRESHOLD ? Qt::SmoothTransformation : Qt::FastTransformation);
- }
-
- if (!scaledClipRect.isEmpty())
- *outImage = outImage->copy(scaledClipRect);
- return !outImage->isNull();
- }
- else
- return false;
-}
-
-struct my_jpeg_destination_mgr : public jpeg_destination_mgr {
- // Nothing dynamic - cannot rely on destruction over longjump
- QIODevice *device;
- JOCTET buffer[max_buf];
-
-public:
- my_jpeg_destination_mgr(QIODevice *);
-};
-
-
-extern "C" {
-
-static void qt_init_destination(j_compress_ptr)
-{
-}
-
-static boolean qt_empty_output_buffer(j_compress_ptr cinfo)
-{
- my_jpeg_destination_mgr* dest = (my_jpeg_destination_mgr*)cinfo->dest;
-
- int written = dest->device->write((char*)dest->buffer, max_buf);
- if (written == -1)
- (*cinfo->err->error_exit)((j_common_ptr)cinfo);
-
- dest->next_output_byte = dest->buffer;
- dest->free_in_buffer = max_buf;
-
- return TRUE;
-}
-
-static void qt_term_destination(j_compress_ptr cinfo)
-{
- my_jpeg_destination_mgr* dest = (my_jpeg_destination_mgr*)cinfo->dest;
- qint64 n = max_buf - dest->free_in_buffer;
-
- qint64 written = dest->device->write((char*)dest->buffer, n);
- if (written == -1)
- (*cinfo->err->error_exit)((j_common_ptr)cinfo);
-}
-
-}
-
-inline my_jpeg_destination_mgr::my_jpeg_destination_mgr(QIODevice *device)
-{
- jpeg_destination_mgr::init_destination = qt_init_destination;
- jpeg_destination_mgr::empty_output_buffer = qt_empty_output_buffer;
- jpeg_destination_mgr::term_destination = qt_term_destination;
- this->device = device;
- next_output_byte = buffer;
- free_in_buffer = max_buf;
-}
-
-
-static inline void set_text(const QImage &image, j_compress_ptr cinfo, const QString &description)
-{
- QMap<QString, QString> text;
- foreach (const QString &key, image.textKeys()) {
- if (!key.isEmpty())
- text.insert(key, image.text(key));
- }
- foreach (const QString &pair, description.split(QLatin1String("\n\n"))) {
- int index = pair.indexOf(QLatin1Char(':'));
- if (index >= 0 && pair.indexOf(QLatin1Char(' ')) < index) {
- QString s = pair.simplified();
- if (!s.isEmpty())
- text.insert(QLatin1String("Description"), s);
- } else {
- QString key = pair.left(index);
- if (!key.simplified().isEmpty())
- text.insert(key, pair.mid(index + 2).simplified());
- }
- }
- if (text.isEmpty())
- return;
-
- for (QMap<QString, QString>::ConstIterator it = text.constBegin(); it != text.constEnd(); ++it) {
- QByteArray comment = it.key().toLatin1();
- if (!comment.isEmpty())
- comment += ": ";
- comment += it.value().toLatin1();
- if (comment.length() > 65530)
- comment.truncate(65530);
- jpeg_write_marker(cinfo, JPEG_COM, (const JOCTET *)comment.constData(), comment.size());
- }
-}
-
-static bool write_jpeg_image(const QImage &image, QIODevice *device, volatile int sourceQuality, const QString &description, bool optimize, bool progressive)
-{
- bool success = false;
- const QVector<QRgb> cmap = image.colorTable();
-
- if (image.format() == QImage::Format_Invalid || image.format() == QImage::Format_Alpha8)
- return false;
-
- struct jpeg_compress_struct cinfo;
- JSAMPROW row_pointer[1];
- row_pointer[0] = 0;
-
- struct my_jpeg_destination_mgr *iod_dest = new my_jpeg_destination_mgr(device);
- struct my_error_mgr jerr;
-
- cinfo.err = jpeg_std_error(&jerr);
- jerr.error_exit = my_error_exit;
- jerr.output_message = my_output_message;
-
- if (!setjmp(jerr.setjmp_buffer)) {
- // WARNING:
- // this if loop is inside a setjmp/longjmp branch
- // do not create C++ temporaries here because the destructor may never be called
- // if you allocate memory, make sure that you can free it (row_pointer[0])
- jpeg_create_compress(&cinfo);
-
- cinfo.dest = iod_dest;
-
- cinfo.image_width = image.width();
- cinfo.image_height = image.height();
-
- bool gray = false;
- switch (image.format()) {
- case QImage::Format_Mono:
- case QImage::Format_MonoLSB:
- case QImage::Format_Indexed8:
- gray = true;
- for (int i = image.colorCount(); gray && i; i--) {
- gray = gray & qIsGray(cmap[i-1]);
- }
- cinfo.input_components = gray ? 1 : 3;
- cinfo.in_color_space = gray ? JCS_GRAYSCALE : JCS_RGB;
- break;
- case QImage::Format_Grayscale8:
- gray = true;
- cinfo.input_components = 1;
- cinfo.in_color_space = JCS_GRAYSCALE;
- break;
- default:
- cinfo.input_components = 3;
- cinfo.in_color_space = JCS_RGB;
- }
-
- jpeg_set_defaults(&cinfo);
-
- qreal diffInch = qAbs(image.dotsPerMeterX()*2.54/100. - qRound(image.dotsPerMeterX()*2.54/100.))
- + qAbs(image.dotsPerMeterY()*2.54/100. - qRound(image.dotsPerMeterY()*2.54/100.));
- qreal diffCm = (qAbs(image.dotsPerMeterX()/100. - qRound(image.dotsPerMeterX()/100.))
- + qAbs(image.dotsPerMeterY()/100. - qRound(image.dotsPerMeterY()/100.)))*2.54;
- if (diffInch < diffCm) {
- cinfo.density_unit = 1; // dots/inch
- cinfo.X_density = qRound(image.dotsPerMeterX()*2.54/100.);
- cinfo.Y_density = qRound(image.dotsPerMeterY()*2.54/100.);
- } else {
- cinfo.density_unit = 2; // dots/cm
- cinfo.X_density = (image.dotsPerMeterX()+50) / 100;
- cinfo.Y_density = (image.dotsPerMeterY()+50) / 100;
- }
-
- if (optimize)
- cinfo.optimize_coding = true;
-
- if (progressive)
- jpeg_simple_progression(&cinfo);
-
- int quality = sourceQuality >= 0 ? qMin(int(sourceQuality),100) : 75;
- jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
- jpeg_start_compress(&cinfo, TRUE);
-
- set_text(image, &cinfo, description);
-
- row_pointer[0] = new uchar[cinfo.image_width*cinfo.input_components];
- int w = cinfo.image_width;
- while (cinfo.next_scanline < cinfo.image_height) {
- uchar *row = row_pointer[0];
- switch (image.format()) {
- case QImage::Format_Mono:
- case QImage::Format_MonoLSB:
- if (gray) {
- const uchar* data = image.constScanLine(cinfo.next_scanline);
- if (image.format() == QImage::Format_MonoLSB) {
- for (int i=0; i<w; i++) {
- bool bit = !!(*(data + (i >> 3)) & (1 << (i & 7)));
- row[i] = qRed(cmap[bit]);
- }
- } else {
- for (int i=0; i<w; i++) {
- bool bit = !!(*(data + (i >> 3)) & (1 << (7 -(i & 7))));
- row[i] = qRed(cmap[bit]);
- }
- }
- } else {
- const uchar* data = image.constScanLine(cinfo.next_scanline);
- if (image.format() == QImage::Format_MonoLSB) {
- for (int i=0; i<w; i++) {
- bool bit = !!(*(data + (i >> 3)) & (1 << (i & 7)));
- *row++ = qRed(cmap[bit]);
- *row++ = qGreen(cmap[bit]);
- *row++ = qBlue(cmap[bit]);
- }
- } else {
- for (int i=0; i<w; i++) {
- bool bit = !!(*(data + (i >> 3)) & (1 << (7 -(i & 7))));
- *row++ = qRed(cmap[bit]);
- *row++ = qGreen(cmap[bit]);
- *row++ = qBlue(cmap[bit]);
- }
- }
- }
- break;
- case QImage::Format_Indexed8:
- if (gray) {
- const uchar* pix = image.constScanLine(cinfo.next_scanline);
- for (int i=0; i<w; i++) {
- *row = qRed(cmap[*pix]);
- ++row; ++pix;
- }
- } else {
- const uchar* pix = image.constScanLine(cinfo.next_scanline);
- for (int i=0; i<w; i++) {
- *row++ = qRed(cmap[*pix]);
- *row++ = qGreen(cmap[*pix]);
- *row++ = qBlue(cmap[*pix]);
- ++pix;
- }
- }
- break;
- case QImage::Format_Grayscale8:
- memcpy(row, image.constScanLine(cinfo.next_scanline), w);
- break;
- case QImage::Format_RGB888:
- memcpy(row, image.constScanLine(cinfo.next_scanline), w * 3);
- break;
- case QImage::Format_RGB32:
- case QImage::Format_ARGB32:
- case QImage::Format_ARGB32_Premultiplied:
- {
- const QRgb* rgb = (const QRgb*)image.constScanLine(cinfo.next_scanline);
- for (int i=0; i<w; i++) {
- *row++ = qRed(*rgb);
- *row++ = qGreen(*rgb);
- *row++ = qBlue(*rgb);
- ++rgb;
- }
- }
- break;
- default:
- {
- // (Testing shows that this way is actually faster than converting to RGB888 + memcpy)
- QImage rowImg = image.copy(0, cinfo.next_scanline, w, 1).convertToFormat(QImage::Format_RGB32);
- const QRgb* rgb = (const QRgb*)rowImg.constScanLine(0);
- for (int i=0; i<w; i++) {
- *row++ = qRed(*rgb);
- *row++ = qGreen(*rgb);
- *row++ = qBlue(*rgb);
- ++rgb;
- }
- }
- break;
- }
- jpeg_write_scanlines(&cinfo, row_pointer, 1);
- }
-
- jpeg_finish_compress(&cinfo);
- jpeg_destroy_compress(&cinfo);
- success = true;
- } else {
- jpeg_destroy_compress(&cinfo);
- success = false;
- }
-
- delete iod_dest;
- delete [] row_pointer[0];
- return success;
-}
-
-class QJpegHandlerPrivate
-{
-public:
- enum State {
- Ready,
- ReadHeader,
- ReadingEnd,
- Error
- };
-
- QJpegHandlerPrivate(QJpegHandler *qq)
- : quality(75), transformation(QImageIOHandler::TransformationNone), iod_src(0),
- rgb888ToRgb32ConverterPtr(qt_convert_rgb888_to_rgb32), state(Ready), optimize(false), progressive(false), q(qq)
- {}
-
- ~QJpegHandlerPrivate()
- {
- if(iod_src)
- {
- jpeg_destroy_decompress(&info);
- delete iod_src;
- iod_src = 0;
- }
- }
-
- bool readJpegHeader(QIODevice*);
- bool read(QImage *image);
-
- int quality;
- QImageIOHandler::Transformations transformation;
- QVariant size;
- QImage::Format format;
- QSize scaledSize;
- QRect scaledClipRect;
- QRect clipRect;
- QString description;
- QStringList readTexts;
-
- struct jpeg_decompress_struct info;
- struct my_jpeg_source_mgr * iod_src;
- struct my_error_mgr err;
-
- Rgb888ToRgb32Converter rgb888ToRgb32ConverterPtr;
-
- State state;
-
- bool optimize;
- bool progressive;
-
- QJpegHandler *q;
-};
-
-static bool readExifHeader(QDataStream &stream)
-{
- char prefix[6];
- if (stream.readRawData(prefix, sizeof(prefix)) != sizeof(prefix))
- return false;
- static const char exifMagic[6] = {'E', 'x', 'i', 'f', 0, 0};
- return memcmp(prefix, exifMagic, 6) == 0;
-}
-
-/*
- * Returns -1 on error
- * Returns 0 if no Exif orientation was found
- * Returns 1 orientation is horizontal (normal)
- * Returns 2 mirror horizontal
- * Returns 3 rotate 180
- * Returns 4 mirror vertical
- * Returns 5 mirror horizontal and rotate 270 CCW
- * Returns 6 rotate 90 CW
- * Returns 7 mirror horizontal and rotate 90 CW
- * Returns 8 rotate 270 CW
- */
-static int getExifOrientation(QByteArray &exifData)
-{
- QDataStream stream(&exifData, QIODevice::ReadOnly);
-
- if (!readExifHeader(stream))
- return -1;
-
- quint16 val;
- quint32 offset;
- const qint64 headerStart = stream.device()->pos();
-
- // read byte order marker
- stream >> val;
- if (val == 0x4949) // 'II' == Intel
- stream.setByteOrder(QDataStream::LittleEndian);
- else if (val == 0x4d4d) // 'MM' == Motorola
- stream.setByteOrder(QDataStream::BigEndian);
- else
- return -1; // unknown byte order
-
- // read size
- stream >> val;
- if (val != 0x2a)
- return -1;
-
- stream >> offset;
-
- // read IFD
- while (!stream.atEnd()) {
- quint16 numEntries;
-
- // skip offset bytes to get the next IFD
- const qint64 bytesToSkip = offset - (stream.device()->pos() - headerStart);
-
- if (stream.skipRawData(bytesToSkip) != bytesToSkip)
- return -1;
-
- stream >> numEntries;
-
- for (; numEntries > 0; --numEntries) {
- quint16 tag;
- quint16 type;
- quint32 components;
- quint16 value;
- quint16 dummy;
-
- stream >> tag >> type >> components >> value >> dummy;
- if (tag == 0x0112) { // Tag Exif.Image.Orientation
- if (components != 1)
- return -1;
- if (type != 3) // we are expecting it to be an unsigned short
- return -1;
- if (value < 1 || value > 8) // check for valid range
- return -1;
-
- // It is possible to include the orientation multiple times.
- // Right now the first value is returned.
- return value;
- }
- }
-
- // read offset to next IFD
- stream >> offset;
- if (offset == 0) // this is the last IFD
- break;
- }
-
- // No Exif orientation was found
- return 0;
-}
-
-static QImageIOHandler::Transformations exif2Qt(int exifOrientation)
-{
- switch (exifOrientation) {
- case 1: // normal
- return QImageIOHandler::TransformationNone;
- case 2: // mirror horizontal
- return QImageIOHandler::TransformationMirror;
- case 3: // rotate 180
- return QImageIOHandler::TransformationRotate180;
- case 4: // mirror vertical
- return QImageIOHandler::TransformationFlip;
- case 5: // mirror horizontal and rotate 270 CW
- return QImageIOHandler::TransformationFlipAndRotate90;
- case 6: // rotate 90 CW
- return QImageIOHandler::TransformationRotate90;
- case 7: // mirror horizontal and rotate 90 CW
- return QImageIOHandler::TransformationMirrorAndRotate90;
- case 8: // rotate 270 CW
- return QImageIOHandler::TransformationRotate270;
- }
- qWarning("Invalid EXIF orientation");
- return QImageIOHandler::TransformationNone;
-}
-
-/*!
- \internal
-*/
-bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device)
-{
- if(state == Ready)
- {
- state = Error;
- iod_src = new my_jpeg_source_mgr(device);
-
- info.err = jpeg_std_error(&err);
- err.error_exit = my_error_exit;
- err.output_message = my_output_message;
-
- jpeg_create_decompress(&info);
- info.src = iod_src;
-
- if (!setjmp(err.setjmp_buffer)) {
- jpeg_save_markers(&info, JPEG_COM, 0xFFFF);
- jpeg_save_markers(&info, JPEG_APP0 + 1, 0xFFFF); // Exif uses APP1 marker
-
- (void) jpeg_read_header(&info, TRUE);
-
- int width = 0;
- int height = 0;
- read_jpeg_size(width, height, &info);
- size = QSize(width, height);
-
- format = QImage::Format_Invalid;
- read_jpeg_format(format, &info);
-
- QByteArray exifData;
-
- for (jpeg_saved_marker_ptr marker = info.marker_list; marker != NULL; marker = marker->next) {
- if (marker->marker == JPEG_COM) {
- QString key, value;
- QString s = QString::fromLatin1((const char *)marker->data, marker->data_length);
- int index = s.indexOf(QLatin1String(": "));
- if (index == -1 || s.indexOf(QLatin1Char(' ')) < index) {
- key = QLatin1String("Description");
- value = s;
- } else {
- key = s.left(index);
- value = s.mid(index + 2);
- }
- if (!description.isEmpty())
- description += QLatin1String("\n\n");
- description += key + QLatin1String(": ") + value.simplified();
- readTexts.append(key);
- readTexts.append(value);
- } else if (marker->marker == JPEG_APP0 + 1) {
- exifData.append((const char*)marker->data, marker->data_length);
- }
- }
-
- if (!exifData.isEmpty()) {
- // Exif data present
- int exifOrientation = getExifOrientation(exifData);
- if (exifOrientation > 0)
- transformation = exif2Qt(exifOrientation);
- }
-
- state = ReadHeader;
- return true;
- }
- else
- {
- return false;
- }
- }
- else if(state == Error)
- return false;
- return true;
-}
-
-bool QJpegHandlerPrivate::read(QImage *image)
-{
- if(state == Ready)
- readJpegHeader(q->device());
-
- if(state == ReadHeader)
- {
- bool success = read_jpeg_image(image, scaledSize, scaledClipRect, clipRect, quality, rgb888ToRgb32ConverterPtr, &info, &err);
- if (success) {
- for (int i = 0; i < readTexts.size()-1; i+=2)
- image->setText(readTexts.at(i), readTexts.at(i+1));
-
- state = ReadingEnd;
- return true;
- }
-
- state = Error;
- }
-
- return false;
-
-}
-
-Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_neon(quint32 *dst, const uchar *src, int len);
-Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_ssse3(quint32 *dst, const uchar *src, int len);
-extern "C" void qt_convert_rgb888_to_rgb32_mips_dspr2_asm(quint32 *dst, const uchar *src, int len);
-
-QJpegHandler::QJpegHandler()
- : d(new QJpegHandlerPrivate(this))
-{
-#if defined(__ARM_NEON__)
- // from qimage_neon.cpp
- if (qCpuHasFeature(NEON))
- d->rgb888ToRgb32ConverterPtr = qt_convert_rgb888_to_rgb32_neon;
-#endif
-
-#if defined(QT_COMPILER_SUPPORTS_SSSE3)
- // from qimage_ssse3.cpps
- if (qCpuHasFeature(SSSE3)) {
- d->rgb888ToRgb32ConverterPtr = qt_convert_rgb888_to_rgb32_ssse3;
- }
-#endif // QT_COMPILER_SUPPORTS_SSSE3
-#if defined(QT_COMPILER_SUPPORTS_MIPS_DSPR2)
- if (qCpuHasFeature(DSPR2)) {
- d->rgb888ToRgb32ConverterPtr = qt_convert_rgb888_to_rgb32_mips_dspr2_asm;
- }
-#endif // QT_COMPILER_SUPPORTS_DSPR2
-}
-
-QJpegHandler::~QJpegHandler()
-{
- delete d;
-}
-
-bool QJpegHandler::canRead() const
-{
- if(d->state == QJpegHandlerPrivate::Ready && !canRead(device()))
- return false;
-
- if (d->state != QJpegHandlerPrivate::Error && d->state != QJpegHandlerPrivate::ReadingEnd) {
- setFormat("jpeg");
- return true;
- }
-
- return false;
-}
-
-bool QJpegHandler::canRead(QIODevice *device)
-{
- if (!device) {
- qWarning("QJpegHandler::canRead() called with no device");
- return false;
- }
-
- char buffer[2];
- if (device->peek(buffer, 2) != 2)
- return false;
- return uchar(buffer[0]) == 0xff && uchar(buffer[1]) == 0xd8;
-}
-
-bool QJpegHandler::read(QImage *image)
-{
- if (!canRead())
- return false;
- return d->read(image);
-}
-
-extern void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient);
-
-bool QJpegHandler::write(const QImage &image)
-{
- if (d->transformation != QImageIOHandler::TransformationNone) {
- // We don't support writing EXIF headers so apply the transform to the data.
- QImage img = image;
- qt_imageTransform(img, d->transformation);
- return write_jpeg_image(img, device(), d->quality, d->description, d->optimize, d->progressive);
- }
- return write_jpeg_image(image, device(), d->quality, d->description, d->optimize, d->progressive);
-}
-
-bool QJpegHandler::supportsOption(ImageOption option) const
-{
- return option == Quality
- || option == ScaledSize
- || option == ScaledClipRect
- || option == ClipRect
- || option == Description
- || option == Size
- || option == ImageFormat
- || option == OptimizedWrite
- || option == ProgressiveScanWrite
- || option == ImageTransformation;
-}
-
-QVariant QJpegHandler::option(ImageOption option) const
-{
- switch(option) {
- case Quality:
- return d->quality;
- case ScaledSize:
- return d->scaledSize;
- case ScaledClipRect:
- return d->scaledClipRect;
- case ClipRect:
- return d->clipRect;
- case Description:
- d->readJpegHeader(device());
- return d->description;
- case Size:
- d->readJpegHeader(device());
- return d->size;
- case ImageFormat:
- d->readJpegHeader(device());
- return d->format;
- case OptimizedWrite:
- return d->optimize;
- case ProgressiveScanWrite:
- return d->progressive;
- case ImageTransformation:
- d->readJpegHeader(device());
- return int(d->transformation);
- default:
- break;
- }
-
- return QVariant();
-}
-
-void QJpegHandler::setOption(ImageOption option, const QVariant &value)
-{
- switch(option) {
- case Quality:
- d->quality = value.toInt();
- break;
- case ScaledSize:
- d->scaledSize = value.toSize();
- break;
- case ScaledClipRect:
- d->scaledClipRect = value.toRect();
- break;
- case ClipRect:
- d->clipRect = value.toRect();
- break;
- case Description:
- d->description = value.toString();
- break;
- case OptimizedWrite:
- d->optimize = value.toBool();
- break;
- case ProgressiveScanWrite:
- d->progressive = value.toBool();
- break;
- case ImageTransformation: {
- int transformation = value.toInt();
- if (transformation > 0 && transformation < 8)
- d->transformation = QImageIOHandler::Transformations(transformation);
- }
- default:
- break;
- }
-}
-
-QByteArray QJpegHandler::name() const
-{
- return "jpeg";
-}
-
-QT_END_NAMESPACE
diff --git a/src/gui/image/qjpeghandler.pri b/src/gui/image/qjpeghandler.pri
deleted file mode 100644
index de40c6742e..0000000000
--- a/src/gui/image/qjpeghandler.pri
+++ /dev/null
@@ -1,11 +0,0 @@
-# common to plugin and built-in forms
-HEADERS += $$PWD/qjpeghandler_p.h
-SOURCES += $$PWD/qjpeghandler.cpp
-contains(QT_CONFIG, system-jpeg) {
- msvc: \
- LIBS += libjpeg.lib
- else: \
- LIBS += -ljpeg
-} else {
- include($$PWD/../../3rdparty/libjpeg.pri)
-}
diff --git a/src/gui/image/qjpeghandler_p.h b/src/gui/image/qjpeghandler_p.h
deleted file mode 100644
index 534ce12115..0000000000
--- a/src/gui/image/qjpeghandler_p.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QJPEGHANDLER_P_H
-#define QJPEGHANDLER_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtGui/qimageiohandler.h>
-#include <QtCore/QSize>
-#include <QtCore/QRect>
-
-QT_BEGIN_NAMESPACE
-
-class QJpegHandlerPrivate;
-class QJpegHandler : public QImageIOHandler
-{
-public:
- QJpegHandler();
- ~QJpegHandler();
-
- bool canRead() const Q_DECL_OVERRIDE;
- bool read(QImage *image) Q_DECL_OVERRIDE;
- bool write(const QImage &image) Q_DECL_OVERRIDE;
-
- QByteArray name() const Q_DECL_OVERRIDE;
-
- static bool canRead(QIODevice *device);
-
- QVariant option(ImageOption option) const Q_DECL_OVERRIDE;
- void setOption(ImageOption option, const QVariant &value) Q_DECL_OVERRIDE;
- bool supportsOption(ImageOption option) const Q_DECL_OVERRIDE;
-
-private:
- QJpegHandlerPrivate *d;
-};
-
-QT_END_NAMESPACE
-
-#endif // QJPEGHANDLER_P_H
diff --git a/src/gui/image/qpnghandler.pri b/src/gui/image/qpnghandler.pri
index 505d214130..e69de29bb2 100644
--- a/src/gui/image/qpnghandler.pri
+++ b/src/gui/image/qpnghandler.pri
@@ -1,4 +0,0 @@
-HEADERS += $$PWD/qpnghandler_p.h
-SOURCES += $$PWD/qpnghandler.cpp
-
-include($$PWD/../../3rdparty/png_dependency.pri)