diff options
Diffstat (limited to 'src/plugins/imageformats')
-rw-r--r-- | src/plugins/imageformats/gif/gif.pro | 5 | ||||
-rw-r--r-- | src/plugins/imageformats/gif/qgifhandler.cpp | 1199 | ||||
-rw-r--r-- | src/plugins/imageformats/gif/qgifhandler.h | 96 | ||||
-rw-r--r-- | src/plugins/imageformats/imageformats.pro | 8 | ||||
-rw-r--r-- | src/plugins/imageformats/jpeg/jpeg.pro | 60 | ||||
-rw-r--r-- | src/plugins/imageformats/jpeg/qjpeghandler.cpp | 901 | ||||
-rw-r--r-- | src/plugins/imageformats/jpeg/qjpeghandler.h | 76 | ||||
-rw-r--r-- | src/plugins/imageformats/mng/mng.pro | 43 | ||||
-rw-r--r-- | src/plugins/imageformats/mng/qmnghandler.cpp | 497 | ||||
-rw-r--r-- | src/plugins/imageformats/mng/qmnghandler.h | 83 | ||||
-rw-r--r-- | src/plugins/imageformats/tiff/qtiffhandler.cpp | 661 | ||||
-rw-r--r-- | src/plugins/imageformats/tiff/qtiffhandler.h | 78 | ||||
-rw-r--r-- | src/plugins/imageformats/tiff/tiff.pro | 73 |
13 files changed, 12 insertions, 3768 deletions
diff --git a/src/plugins/imageformats/gif/gif.pro b/src/plugins/imageformats/gif/gif.pro index 8a5c51a..439b431 100644 --- a/src/plugins/imageformats/gif/gif.pro +++ b/src/plugins/imageformats/gif/gif.pro @@ -1,9 +1,8 @@ TARGET = qgif include(../../qpluginbase.pri) -HEADERS += qgifhandler.h -SOURCES += main.cpp \ - qgifhandler.cpp +include(../../../gui/image/qgifhandler.pri) +SOURCES += $$PWD/main.cpp QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/imageformats target.path += $$[QT_INSTALL_PLUGINS]/imageformats diff --git a/src/plugins/imageformats/gif/qgifhandler.cpp b/src/plugins/imageformats/gif/qgifhandler.cpp deleted file mode 100644 index 129a11b..0000000 --- a/src/plugins/imageformats/gif/qgifhandler.cpp +++ /dev/null @@ -1,1199 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $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.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 - QRgb *bits = (QRgb*)image->bits(); - 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.scanLine(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()); - } - - 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 && 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) { - *sp++=table[1][code]; - if (code==table[0][code]) { - state=Error; - break; - } - if (sp-stack>=(1<<(max_lzw_bits))*2) { - state=Error; - break; - } - code=table[0][code]; - } - *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(); - const QRgb *map = lcmap ? localcmap : globalcmap; - 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 && index!=trans_index) { - if (index > ncols) - line[x] = Q_TRANSPARENT; - else - line[x] = map ? map[index] : 0; - } - 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->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) -{ - 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 == trans_index || index > ncols) - return Q_TRANSPARENT; - - QRgb *map = lcmap ? localcmap : globalcmap; - return map ? map[index] : 0; -} - -//------------------------------------------------------------------------- -//------------------------------------------------------------------------- -//------------------------------------------------------------------------- - -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; - } - return loopCnt-1; // In GIF, loop count is iteration count, so subtract one -} - -int QGifHandler::currentImageNumber() const -{ - return frameNumber; -} - -QByteArray QGifHandler::name() const -{ - return "gif"; -} - -QT_END_NAMESPACE diff --git a/src/plugins/imageformats/gif/qgifhandler.h b/src/plugins/imageformats/gif/qgifhandler.h deleted file mode 100644 index 8e07aff..0000000 --- a/src/plugins/imageformats/gif/qgifhandler.h +++ /dev/null @@ -1,96 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $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_H -#define QGIFHANDLER_H - -#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; - bool read(QImage *image); - bool write(const QImage &image); - - QByteArray name() const; - - static bool canRead(QIODevice *device); - - QVariant option(ImageOption option) const; - void setOption(ImageOption option, const QVariant &value); - bool supportsOption(ImageOption option) const; - - int imageCount() const; - int loopCount() const; - int nextImageDelay() const; - int currentImageNumber() const; - -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_H diff --git a/src/plugins/imageformats/imageformats.pro b/src/plugins/imageformats/imageformats.pro index 2e4036b..5fff2de 100644 --- a/src/plugins/imageformats/imageformats.pro +++ b/src/plugins/imageformats/imageformats.pro @@ -1,8 +1,8 @@ TEMPLATE = subdirs -!contains(QT_CONFIG, no-jpeg):SUBDIRS += jpeg -!contains(QT_CONFIG, no-gif):SUBDIRS += gif -!contains(QT_CONFIG, no-mng):SUBDIRS += mng +!contains(QT_CONFIG, no-jpeg):!contains(QT_CONFIG, jpeg):SUBDIRS += jpeg +!contains(QT_CONFIG, no-gif):!contains(QT_CONFIG, gif):SUBDIRS += gif +!contains(QT_CONFIG, no-mng):!contains(QT_CONFIG, mng):SUBDIRS += mng contains(QT_CONFIG, svg):SUBDIRS += svg -!contains(QT_CONFIG, no-tiff):SUBDIRS += tiff +!contains(QT_CONFIG, no-tiff):!contains(QT_CONFIG, tiff):SUBDIRS += tiff !contains(QT_CONFIG, no-ico):SUBDIRS += ico diff --git a/src/plugins/imageformats/jpeg/jpeg.pro b/src/plugins/imageformats/jpeg/jpeg.pro index d4b0fef..c5671c3 100644 --- a/src/plugins/imageformats/jpeg/jpeg.pro +++ b/src/plugins/imageformats/jpeg/jpeg.pro @@ -3,10 +3,6 @@ include(../../qpluginbase.pri) QTDIR_build:REQUIRES = "!contains(QT_CONFIG, no-jpeg)" -HEADERS += qjpeghandler.h -SOURCES += main.cpp \ - qjpeghandler.cpp - wince*: { DEFINES += NO_GETENV contains(CE_ARCH,x86):CONFIG -= stl exceptions @@ -21,61 +17,9 @@ symbian: { QMAKE_CFLAGS_WARN_ON += -Wno-unused-parameter -Wno-main } -contains(QT_CONFIG, system-jpeg) { - unix|win32-g++*:LIBS += -ljpeg - win32:!win32-g++*:LIBS += libjpeg.lib -} else { - INCLUDEPATH += ../../../3rdparty/libjpeg - SOURCES += \ - ../../../3rdparty/libjpeg/jaricom.c \ - ../../../3rdparty/libjpeg/jcapimin.c \ - ../../../3rdparty/libjpeg/jcapistd.c \ - ../../../3rdparty/libjpeg/jcarith.c \ - ../../../3rdparty/libjpeg/jccoefct.c \ - ../../../3rdparty/libjpeg/jccolor.c \ - ../../../3rdparty/libjpeg/jcdctmgr.c \ - ../../../3rdparty/libjpeg/jchuff.c \ - ../../../3rdparty/libjpeg/jcinit.c \ - ../../../3rdparty/libjpeg/jcmainct.c \ - ../../../3rdparty/libjpeg/jcmarker.c \ - ../../../3rdparty/libjpeg/jcmaster.c \ - ../../../3rdparty/libjpeg/jcomapi.c \ - ../../../3rdparty/libjpeg/jcparam.c \ - ../../../3rdparty/libjpeg/jcprepct.c \ - ../../../3rdparty/libjpeg/jcsample.c \ - ../../../3rdparty/libjpeg/jctrans.c \ - ../../../3rdparty/libjpeg/jdapimin.c \ - ../../../3rdparty/libjpeg/jdapistd.c \ - ../../../3rdparty/libjpeg/jdarith.c \ - ../../../3rdparty/libjpeg/jdatadst.c \ - ../../../3rdparty/libjpeg/jdatasrc.c \ - ../../../3rdparty/libjpeg/jdcoefct.c \ - ../../../3rdparty/libjpeg/jdcolor.c \ - ../../../3rdparty/libjpeg/jddctmgr.c \ - ../../../3rdparty/libjpeg/jdhuff.c \ - ../../../3rdparty/libjpeg/jdinput.c \ - ../../../3rdparty/libjpeg/jdmainct.c \ - ../../../3rdparty/libjpeg/jdmarker.c \ - ../../../3rdparty/libjpeg/jdmaster.c \ - ../../../3rdparty/libjpeg/jdmerge.c \ - ../../../3rdparty/libjpeg/jdpostct.c \ - ../../../3rdparty/libjpeg/jdsample.c \ - ../../../3rdparty/libjpeg/jdtrans.c \ - ../../../3rdparty/libjpeg/jerror.c \ - ../../../3rdparty/libjpeg/jfdctflt.c \ - ../../../3rdparty/libjpeg/jfdctfst.c \ - ../../../3rdparty/libjpeg/jfdctint.c \ - ../../../3rdparty/libjpeg/jidctflt.c \ - ../../../3rdparty/libjpeg/jidctfst.c \ - ../../../3rdparty/libjpeg/jidctint.c \ - ../../../3rdparty/libjpeg/jquant1.c \ - ../../../3rdparty/libjpeg/jquant2.c \ - ../../../3rdparty/libjpeg/jutils.c \ - ../../../3rdparty/libjpeg/jmemmgr.c \ - ../../../3rdparty/libjpeg/jmemnobs.c -} +include(../../../gui/image/qjpeghandler.pri) +SOURCES += main.cpp QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/imageformats target.path += $$[QT_INSTALL_PLUGINS]/imageformats INSTALLS += target - diff --git a/src/plugins/imageformats/jpeg/qjpeghandler.cpp b/src/plugins/imageformats/jpeg/qjpeghandler.cpp deleted file mode 100644 index 60e7cce..0000000 --- a/src/plugins/imageformats/jpeg/qjpeghandler.cpp +++ /dev/null @@ -1,901 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qjpeghandler.h" - -#include <qimage.h> -#include <qvariant.h> -#include <qvector.h> -#include <qbuffer.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 - -struct my_error_mgr : public jpeg_error_mgr { - jmp_buf setjmp_buffer; -}; - -#if defined(Q_C_CALLBACKS) -extern "C" { -#endif - -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); -} - -#if defined(Q_C_CALLBACKS) -} -#endif - - -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); -}; - -#if defined(Q_C_CALLBACKS) -extern "C" { -#endif - -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; - if (src->memDevice) { - src->next_input_byte = (const JOCTET *)(src->memDevice->data().constData() + src->memDevice->pos()); - src->bytes_in_buffer = (size_t)(src->memDevice->data().size() - src->memDevice->pos()); - return true; - } - src->next_input_byte = src->buffer; - int num_read = src->device->read((char*)src->buffer, max_buf); - if (num_read <= 0) { - // Insert a fake EOI marker - as per jpeglib recommendation - src->buffer[0] = (JOCTET) 0xFF; - src->buffer[1] = (JOCTET) JPEG_EOI; - src->bytes_in_buffer = 2; - } else { - src->bytes_in_buffer = num_read; - } -#if defined(Q_OS_UNIXWARE) - return B_TRUE; -#else - return true; -#endif -} - -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()) - { - // read() isn't used for memDevice, so seek past everything that was used - if (src->memDevice) - src->device->seek(src->device->pos() + (src->memDevice->data().size() - src->memDevice->pos() - src->bytes_in_buffer)); - else - src->device->seek(src->device->pos() - src->bytes_in_buffer); - } -} - -#if defined(Q_C_CALLBACKS) -} -#endif - -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_Indexed8; - 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_Indexed8; - 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); - - if (format == QImage::Format_Indexed8) { - dest->setColorCount(256); - for (int i = 0; i < 256; i++) - dest->setColor(i, qRgb(i,i,i)); - } - } - - return !dest->isNull(); -} - -static bool read_jpeg_image(QImage *outImage, - QSize scaledSize, QRect scaledClipRect, - QRect clipRect, int inQuality, 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()) { - if (clipRect.isEmpty()) { - info->scale_denom = - qMin(info->image_width / scaledSize.width(), - info->image_height / scaledSize.height()); - } else { - info->scale_denom = - qMin(clipRect.width() / scaledSize.width(), - clipRect.height() / scaledSize.height()); - } - 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; - if (!clipRect.isEmpty()) { - // 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) { - // Expand 24->32 bpp. - uchar *in = rows[0] + clip.x() * 3; - QRgb *out = (QRgb*)outImage->scanLine(y); - for (int i = 0; i < clip.width(); ++i) { - *out++ = qRgb(in[0], in[1], in[2]); - in += 3; - } - } 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 *); -}; - - -#if defined(Q_C_CALLBACKS) -extern "C" { -#endif - -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; - -#if defined(Q_OS_UNIXWARE) - return B_TRUE; -#else - return true; -#endif -} - -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); -} - -#if defined(Q_C_CALLBACKS) -} -#endif - -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 bool can_write_format(QImage::Format fmt) -{ - switch (fmt) { - case QImage::Format_Mono: - case QImage::Format_MonoLSB: - case QImage::Format_Indexed8: - case QImage::Format_RGB888: - case QImage::Format_RGB32: - case QImage::Format_ARGB32: - case QImage::Format_ARGB32_Premultiplied: - return true; - break; - default: - break; - } - return false; -} - -static bool write_jpeg_image(const QImage &sourceImage, QIODevice *device, int sourceQuality) -{ - bool success = false; - const QImage image = can_write_format(sourceImage.format()) ? - sourceImage : sourceImage.convertToFormat(QImage::Format_RGB888); - const QVector<QRgb> cmap = image.colorTable(); - - 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; - - 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--;) { - gray = gray & (qRed(cmap[i]) == qGreen(cmap[i]) && - qRed(cmap[i]) == qBlue(cmap[i])); - } - cinfo.input_components = gray ? 1 : 3; - cinfo.in_color_space = gray ? JCS_GRAYSCALE : JCS_RGB; - 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; - } - - - int quality = sourceQuality >= 0 ? qMin(sourceQuality,100) : 75; -#if defined(Q_OS_UNIXWARE) - jpeg_set_quality(&cinfo, quality, B_TRUE /* limit to baseline-JPEG values */); - jpeg_start_compress(&cinfo, B_TRUE); -#else - jpeg_set_quality(&cinfo, quality, true /* limit to baseline-JPEG values */); - jpeg_start_compress(&cinfo, true); -#endif - - 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.scanLine(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.scanLine(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.scanLine(cinfo.next_scanline); - for (int i=0; i<w; i++) { - *row = qRed(cmap[*pix]); - ++row; ++pix; - } - } else { - const uchar* pix = image.scanLine(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_RGB888: - memcpy(row, image.scanLine(cinfo.next_scanline), w * 3); - break; - case QImage::Format_RGB32: - case QImage::Format_ARGB32: - case QImage::Format_ARGB32_Premultiplied: { - QRgb* rgb = (QRgb*)image.scanLine(cinfo.next_scanline); - for (int i=0; i<w; i++) { - *row++ = qRed(*rgb); - *row++ = qGreen(*rgb); - *row++ = qBlue(*rgb); - ++rgb; - } - break; - } - default: - qWarning("QJpegHandler: unable to write image of format %i", - image.format()); - 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, - Error - }; - - QJpegHandlerPrivate(QJpegHandler *qq) - : quality(75), iod_src(0), state(Ready), 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; - QVariant size; - QImage::Format format; - QSize scaledSize; - QRect scaledClipRect; - QRect clipRect; - struct jpeg_decompress_struct info; - struct my_jpeg_source_mgr * iod_src; - struct my_error_mgr err; - - State state; - - QJpegHandler *q; -}; - -/*! - \internal -*/ -bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device) -{ - if(state == Ready) - { - state = Error; - iod_src = new my_jpeg_source_mgr(device); - - jpeg_create_decompress(&info); - info.src = iod_src; - info.err = jpeg_std_error(&err); - err.error_exit = my_error_exit; - - if (!setjmp(err.setjmp_buffer)) { - #if defined(Q_OS_UNIXWARE) - (void) jpeg_read_header(&info, B_TRUE); - #else - (void) jpeg_read_header(&info, true); - #endif - - 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); - 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, &info, &err); - state = success ? Ready : Error; - return success; - } - - return false; - -} - -QJpegHandler::QJpegHandler() - : d(new QJpegHandlerPrivate(this)) -{ -} - -QJpegHandler::~QJpegHandler() -{ - delete d; -} - -bool QJpegHandler::canRead() const -{ - if(d->state == QJpegHandlerPrivate::Ready && !canRead(device())) - return false; - - if (d->state != QJpegHandlerPrivate::Error) { - 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); -} - -bool QJpegHandler::write(const QImage &image) -{ - return write_jpeg_image(image, device(), d->quality); -} - -bool QJpegHandler::supportsOption(ImageOption option) const -{ - return option == Quality - || option == ScaledSize - || option == ScaledClipRect - || option == ClipRect - || option == Size - || option == ImageFormat; -} - -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 Size: - d->readJpegHeader(device()); - return d->size; - case ImageFormat: - d->readJpegHeader(device()); - return d->format; - default: - 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; - default: - break; - } -} - -QByteArray QJpegHandler::name() const -{ - return "jpeg"; -} - - - - -QT_END_NAMESPACE diff --git a/src/plugins/imageformats/jpeg/qjpeghandler.h b/src/plugins/imageformats/jpeg/qjpeghandler.h deleted file mode 100644 index c879f21..0000000 --- a/src/plugins/imageformats/jpeg/qjpeghandler.h +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QJPEGHANDLER_H -#define QJPEGHANDLER_H - -#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; - bool read(QImage *image); - bool write(const QImage &image); - - QByteArray name() const; - - static bool canRead(QIODevice *device); - - QVariant option(ImageOption option) const; - void setOption(ImageOption option, const QVariant &value); - bool supportsOption(ImageOption option) const; - -private: - QJpegHandlerPrivate *d; -}; - -QT_END_NAMESPACE - -#endif // QJPEGHANDLER_H diff --git a/src/plugins/imageformats/mng/mng.pro b/src/plugins/imageformats/mng/mng.pro index 158f41a..88085f3 100644 --- a/src/plugins/imageformats/mng/mng.pro +++ b/src/plugins/imageformats/mng/mng.pro @@ -3,54 +3,15 @@ include(../../qpluginbase.pri) QTDIR_build:REQUIRES = "!contains(QT_CONFIG, no-mng)" -HEADERS += qmnghandler.h -SOURCES += main.cpp \ - qmnghandler.cpp - symbian: { #Disable warnings in 3rdparty code due to unused variables and arguments QMAKE_CXXFLAGS.CW += -W nounused TARGET.UID3=0x2001E619 } -contains(QT_CONFIG, system-mng) { - unix|win32-g++*:LIBS += -lmng - win32:!win32-g++*:LIBS += libmng.lib -} else { - DEFINES += MNG_BUILD_SO - DEFINES += MNG_NO_INCLUDE_JNG - INCLUDEPATH += ../../../3rdparty/libmng - SOURCES += \ - ../../../3rdparty/libmng/libmng_callback_xs.c \ - ../../../3rdparty/libmng/libmng_chunk_io.c \ - ../../../3rdparty/libmng/libmng_chunk_descr.c \ - ../../../3rdparty/libmng/libmng_chunk_prc.c \ - ../../../3rdparty/libmng/libmng_chunk_xs.c \ - ../../../3rdparty/libmng/libmng_cms.c \ - ../../../3rdparty/libmng/libmng_display.c \ - ../../../3rdparty/libmng/libmng_dither.c \ - ../../../3rdparty/libmng/libmng_error.c \ - ../../../3rdparty/libmng/libmng_filter.c \ - ../../../3rdparty/libmng/libmng_hlapi.c \ - ../../../3rdparty/libmng/libmng_jpeg.c \ - ../../../3rdparty/libmng/libmng_object_prc.c \ - ../../../3rdparty/libmng/libmng_pixels.c \ - ../../../3rdparty/libmng/libmng_prop_xs.c \ - ../../../3rdparty/libmng/libmng_read.c \ - ../../../3rdparty/libmng/libmng_trace.c \ - ../../../3rdparty/libmng/libmng_write.c \ - ../../../3rdparty/libmng/libmng_zlib.c -} - -contains(QT_CONFIG, system-zlib) { - symbian:LIBS_PRIVATE += -llibz - else:if(unix|win32-g++*):LIBS_PRIVATE += -lz - else:LIBS += zdll.lib -} else { - INCLUDEPATH += ../../../3rdparty/zlib -} +include(../../../gui/image/qmnghandler.pri) +SOURCES += main.cpp QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/imageformats target.path += $$[QT_INSTALL_PLUGINS]/imageformats INSTALLS += target - diff --git a/src/plugins/imageformats/mng/qmnghandler.cpp b/src/plugins/imageformats/mng/qmnghandler.cpp deleted file mode 100644 index ec442a1..0000000 --- a/src/plugins/imageformats/mng/qmnghandler.cpp +++ /dev/null @@ -1,497 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qmnghandler.h" - -#include "qimage.h" -#include "qvariant.h" -#include "qcolor.h" - -#define MNG_USE_SO -#include <libmng.h> - -QT_BEGIN_NAMESPACE - -class QMngHandlerPrivate -{ - Q_DECLARE_PUBLIC(QMngHandler) - public: - bool haveReadNone; - bool haveReadAll; - mng_handle hMNG; - QImage image; - int elapsed; - int nextDelay; - int iterCount; - int frameIndex; - int nextIndex; - int frameCount; - mng_uint32 iStyle; - mng_bool readData(mng_ptr pBuf, mng_uint32 iSize, mng_uint32p pRead); - mng_bool writeData(mng_ptr pBuf, mng_uint32 iSize, mng_uint32p pWritten); - mng_bool processHeader(mng_uint32 iWidth, mng_uint32 iHeight); - QMngHandlerPrivate(QMngHandler *q_ptr); - ~QMngHandlerPrivate(); - bool getNextImage(QImage *result); - bool writeImage(const QImage &image); - int currentImageNumber() const; - int imageCount() const; - bool jumpToImage(int imageNumber); - bool jumpToNextImage(); - int nextImageDelay() const; - bool setBackgroundColor(const QColor &color); - QColor backgroundColor() const; - QMngHandler *q_ptr; -}; - -static mng_bool myerror(mng_handle /*hMNG*/, - mng_int32 iErrorcode, - mng_int8 /*iSeverity*/, - mng_chunkid iChunkname, - mng_uint32 /*iChunkseq*/, - mng_int32 iExtra1, - mng_int32 iExtra2, - mng_pchar zErrortext) -{ - qWarning("MNG error %d: %s; chunk %c%c%c%c; subcode %d:%d", - iErrorcode,zErrortext, - (iChunkname>>24)&0xff, - (iChunkname>>16)&0xff, - (iChunkname>>8)&0xff, - (iChunkname>>0)&0xff, - iExtra1,iExtra2); - return TRUE; -} - -static mng_ptr myalloc(mng_size_t iSize) -{ -#if defined(Q_OS_WINCE) - mng_ptr ptr = malloc(iSize); - memset(ptr, 0, iSize); - return ptr; -#else - return (mng_ptr)calloc(1, iSize); -#endif -} - -static void myfree(mng_ptr pPtr, mng_size_t /*iSize*/) -{ - free(pPtr); -} - -static mng_bool myopenstream(mng_handle) -{ - return MNG_TRUE; -} - -static mng_bool myclosestream(mng_handle hMNG) -{ - QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG)); - pMydata->haveReadAll = true; - return MNG_TRUE; -} - -static mng_bool myreaddata(mng_handle hMNG, - mng_ptr pBuf, - mng_uint32 iSize, - mng_uint32p pRead) -{ - QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG)); - return pMydata->readData(pBuf, iSize, pRead); -} - -static mng_bool mywritedata(mng_handle hMNG, - mng_ptr pBuf, - mng_uint32 iSize, - mng_uint32p pWritten) -{ - QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG)); - return pMydata->writeData(pBuf, iSize, pWritten); -} - -static mng_bool myprocessheader(mng_handle hMNG, - mng_uint32 iWidth, - mng_uint32 iHeight) -{ - QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG)); - return pMydata->processHeader(iWidth, iHeight); -} - -static mng_ptr mygetcanvasline(mng_handle hMNG, - mng_uint32 iLinenr) -{ - QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG)); - return (mng_ptr)pMydata->image.scanLine(iLinenr); -} - -static mng_bool myrefresh(mng_handle /*hMNG*/, - mng_uint32 /*iX*/, - mng_uint32 /*iY*/, - mng_uint32 /*iWidth*/, - mng_uint32 /*iHeight*/) -{ - return MNG_TRUE; -} - -static mng_uint32 mygettickcount(mng_handle hMNG) -{ - QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG)); - return pMydata->elapsed++; -} - -static mng_bool mysettimer(mng_handle hMNG, - mng_uint32 iMsecs) -{ - QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG)); - pMydata->elapsed += iMsecs; - pMydata->nextDelay = iMsecs; - return MNG_TRUE; -} - -static mng_bool myprocessterm(mng_handle hMNG, - mng_uint8 iTermaction, - mng_uint8 /*iIteraction*/, - mng_uint32 /*iDelay*/, - mng_uint32 iItermax) -{ - QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG)); - if (iTermaction == 3) - pMydata->iterCount = iItermax; - return MNG_TRUE; -} - -static mng_bool mytrace(mng_handle, - mng_int32 iFuncnr, - mng_int32 iFuncseq, - mng_pchar zFuncname) -{ - qDebug("mng trace: iFuncnr: %d iFuncseq: %d zFuncname: %s", iFuncnr, iFuncseq, zFuncname); - return MNG_TRUE; -} - -QMngHandlerPrivate::QMngHandlerPrivate(QMngHandler *q_ptr) - : haveReadNone(true), haveReadAll(false), elapsed(0), nextDelay(0), iterCount(1), - frameIndex(-1), nextIndex(0), frameCount(0), q_ptr(q_ptr) -{ - iStyle = (QSysInfo::ByteOrder == QSysInfo::LittleEndian) ? MNG_CANVAS_BGRA8 : MNG_CANVAS_ARGB8; - // Initialize libmng - hMNG = mng_initialize((mng_ptr)this, myalloc, myfree, mytrace); - if (hMNG) { - // Set callback functions - mng_setcb_errorproc(hMNG, myerror); - mng_setcb_openstream(hMNG, myopenstream); - mng_setcb_closestream(hMNG, myclosestream); - mng_setcb_readdata(hMNG, myreaddata); - mng_setcb_writedata(hMNG, mywritedata); - mng_setcb_processheader(hMNG, myprocessheader); - mng_setcb_getcanvasline(hMNG, mygetcanvasline); - mng_setcb_refresh(hMNG, myrefresh); - mng_setcb_gettickcount(hMNG, mygettickcount); - mng_setcb_settimer(hMNG, mysettimer); - mng_setcb_processterm(hMNG, myprocessterm); - mng_set_doprogressive(hMNG, MNG_FALSE); - mng_set_suspensionmode(hMNG, MNG_TRUE); - } -} - -QMngHandlerPrivate::~QMngHandlerPrivate() -{ - mng_cleanup(&hMNG); -} - -mng_bool QMngHandlerPrivate::readData(mng_ptr pBuf, mng_uint32 iSize, mng_uint32p pRead) -{ - Q_Q(QMngHandler); - *pRead = q->device()->read((char *)pBuf, iSize); - return (*pRead > 0) ? MNG_TRUE : MNG_FALSE; -} - -mng_bool QMngHandlerPrivate::writeData(mng_ptr pBuf, mng_uint32 iSize, mng_uint32p pWritten) -{ - Q_Q(QMngHandler); - *pWritten = q->device()->write((char *)pBuf, iSize); - return MNG_TRUE; -} - -mng_bool QMngHandlerPrivate::processHeader(mng_uint32 iWidth, mng_uint32 iHeight) -{ - if (mng_set_canvasstyle(hMNG, iStyle) != MNG_NOERROR) - return MNG_FALSE; - image = QImage(iWidth, iHeight, QImage::Format_ARGB32); - image.fill(0); - return MNG_TRUE; -} - -bool QMngHandlerPrivate::getNextImage(QImage *result) -{ - mng_retcode ret; - if (haveReadNone) { - haveReadNone = false; - ret = mng_readdisplay(hMNG); - } else { - ret = mng_display_resume(hMNG); - } - if ((MNG_NOERROR == ret) || (MNG_NEEDTIMERWAIT == ret)) { - *result = image; - frameIndex = nextIndex++; - if (haveReadAll && (frameCount == 0)) - frameCount = nextIndex; - return true; - } - return false; -} - -bool QMngHandlerPrivate::writeImage(const QImage &image) -{ - mng_reset(hMNG); - if (mng_create(hMNG) != MNG_NOERROR) - return false; - - this->image = image.convertToFormat(QImage::Format_ARGB32); - int w = image.width(); - int h = image.height(); - - if ( - // width, height, ticks, layercount, framecount, playtime, simplicity - (mng_putchunk_mhdr(hMNG, w, h, 1000, 0, 0, 0, 7) == MNG_NOERROR) && - // termination_action, action_after_iterations, delay, iteration_max - (mng_putchunk_term(hMNG, 3, 0, 1, 0x7FFFFFFF) == MNG_NOERROR) && - // width, height, bitdepth, colortype, compression, filter, interlace - (mng_putchunk_ihdr(hMNG, w, h, 8, 6, 0, 0, 0) == MNG_NOERROR) && - // width, height, colortype, bitdepth, compression, filter, interlace, canvasstyle, getcanvasline - (mng_putimgdata_ihdr(hMNG, w, h, 6, 8, 0, 0, 0, iStyle, mygetcanvasline) == MNG_NOERROR) && - (mng_putchunk_iend(hMNG) == MNG_NOERROR) && - (mng_putchunk_mend(hMNG) == MNG_NOERROR) && - (mng_write(hMNG) == MNG_NOERROR) - ) - return true; - return false; -} - -int QMngHandlerPrivate::currentImageNumber() const -{ -// return mng_get_currentframe(hMNG) % imageCount(); not implemented, apparently - return frameIndex; -} - -int QMngHandlerPrivate::imageCount() const -{ -// return mng_get_totalframes(hMNG); not implemented, apparently - if (haveReadAll) - return frameCount; - return 0; // Don't know -} - -bool QMngHandlerPrivate::jumpToImage(int imageNumber) -{ - if (imageNumber == nextIndex) - return true; - - if ((imageNumber == 0) && haveReadAll && (nextIndex == frameCount)) { - // Loop! - nextIndex = 0; - return true; - } - if (mng_display_freeze(hMNG) == MNG_NOERROR) { - if (mng_display_goframe(hMNG, imageNumber) == MNG_NOERROR) { - nextIndex = imageNumber; - return true; - } - } - return false; -} - -bool QMngHandlerPrivate::jumpToNextImage() -{ - return jumpToImage((currentImageNumber()+1) % imageCount()); -} - -int QMngHandlerPrivate::nextImageDelay() const -{ - return nextDelay; -} - -bool QMngHandlerPrivate::setBackgroundColor(const QColor &color) -{ - mng_uint16 iRed = (mng_uint16)(color.red() << 8); - mng_uint16 iBlue = (mng_uint16)(color.blue() << 8); - mng_uint16 iGreen = (mng_uint16)(color.green() << 8); - return (mng_set_bgcolor(hMNG, iRed, iBlue, iGreen) == MNG_NOERROR); -} - -QColor QMngHandlerPrivate::backgroundColor() const -{ - mng_uint16 iRed; - mng_uint16 iBlue; - mng_uint16 iGreen; - if (mng_get_bgcolor(hMNG, &iRed, &iBlue, &iGreen) == MNG_NOERROR) - return QColor((iRed >> 8) & 0xFF, (iGreen >> 8) & 0xFF, (iBlue >> 8) & 0xFF); - return QColor(); -} - -QMngHandler::QMngHandler() - : d_ptr(new QMngHandlerPrivate(this)) -{ -} - -QMngHandler::~QMngHandler() -{ -} - -/*! \reimp */ -bool QMngHandler::canRead() const -{ - Q_D(const QMngHandler); - if ((!d->haveReadNone - && (!d->haveReadAll || (d->haveReadAll && (d->nextIndex < d->frameCount)))) - || canRead(device())) - { - setFormat("mng"); - return true; - } - return false; -} - -/*! \internal */ -bool QMngHandler::canRead(QIODevice *device) -{ - if (!device) { - qWarning("QMngHandler::canRead() called with no device"); - return false; - } - - return device->peek(8) == "\x8A\x4D\x4E\x47\x0D\x0A\x1A\x0A"; -} - -/*! \reimp */ -QByteArray QMngHandler::name() const -{ - return "mng"; -} - -/*! \reimp */ -bool QMngHandler::read(QImage *image) -{ - Q_D(QMngHandler); - return canRead() ? d->getNextImage(image) : false; -} - -/*! \reimp */ -bool QMngHandler::write(const QImage &image) -{ - Q_D(QMngHandler); - return d->writeImage(image); -} - -/*! \reimp */ -int QMngHandler::currentImageNumber() const -{ - Q_D(const QMngHandler); - return d->currentImageNumber(); -} - -/*! \reimp */ -int QMngHandler::imageCount() const -{ - Q_D(const QMngHandler); - return d->imageCount(); -} - -/*! \reimp */ -bool QMngHandler::jumpToImage(int imageNumber) -{ - Q_D(QMngHandler); - return d->jumpToImage(imageNumber); -} - -/*! \reimp */ -bool QMngHandler::jumpToNextImage() -{ - Q_D(QMngHandler); - return d->jumpToNextImage(); -} - -/*! \reimp */ -int QMngHandler::loopCount() const -{ - Q_D(const QMngHandler); - if (d->iterCount == 0x7FFFFFFF) - return -1; // infinite loop - return d->iterCount-1; -} - -/*! \reimp */ -int QMngHandler::nextImageDelay() const -{ - Q_D(const QMngHandler); - return d->nextImageDelay(); -} - -/*! \reimp */ -QVariant QMngHandler::option(ImageOption option) const -{ - Q_D(const QMngHandler); - if (option == QImageIOHandler::Animation) - return true; - else if (option == QImageIOHandler::BackgroundColor) - return d->backgroundColor(); - return QVariant(); -} - -/*! \reimp */ -void QMngHandler::setOption(ImageOption option, const QVariant & value) -{ - Q_D(QMngHandler); - if (option == QImageIOHandler::BackgroundColor) - d->setBackgroundColor(qVariantValue<QColor>(value)); -} - -/*! \reimp */ -bool QMngHandler::supportsOption(ImageOption option) const -{ - if (option == QImageIOHandler::Animation) - return true; - else if (option == QImageIOHandler::BackgroundColor) - return true; - return false; -} - -QT_END_NAMESPACE diff --git a/src/plugins/imageformats/mng/qmnghandler.h b/src/plugins/imageformats/mng/qmnghandler.h deleted file mode 100644 index 65243be..0000000 --- a/src/plugins/imageformats/mng/qmnghandler.h +++ /dev/null @@ -1,83 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QMNGHANDLER_H -#define QMNGHANDLER_H - -#include <QtCore/qscopedpointer.h> -#include <QtGui/qimageiohandler.h> - -QT_BEGIN_NAMESPACE - -class QImage; -class QByteArray; -class QIODevice; -class QVariant; -class QMngHandlerPrivate; - -class QMngHandler : public QImageIOHandler -{ - public: - QMngHandler(); - ~QMngHandler(); - virtual bool canRead() const; - virtual QByteArray name() const; - virtual bool read(QImage *image); - virtual bool write(const QImage &image); - virtual int currentImageNumber() const; - virtual int imageCount() const; - virtual bool jumpToImage(int imageNumber); - virtual bool jumpToNextImage(); - virtual int loopCount() const; - virtual int nextImageDelay() const; - static bool canRead(QIODevice *device); - virtual QVariant option(ImageOption option) const; - virtual void setOption(ImageOption option, const QVariant & value); - virtual bool supportsOption(ImageOption option) const; - - private: - Q_DECLARE_PRIVATE(QMngHandler) - QScopedPointer<QMngHandlerPrivate> d_ptr; -}; - -QT_END_NAMESPACE - -#endif // QMNGHANDLER_H diff --git a/src/plugins/imageformats/tiff/qtiffhandler.cpp b/src/plugins/imageformats/tiff/qtiffhandler.cpp deleted file mode 100644 index 619aa4e..0000000 --- a/src/plugins/imageformats/tiff/qtiffhandler.cpp +++ /dev/null @@ -1,661 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qtiffhandler.h" -#include <qvariant.h> -#include <qdebug.h> -#include <qimage.h> -#include <qglobal.h> -extern "C" { -#include "tiffio.h" -} - -QT_BEGIN_NAMESPACE - -tsize_t qtiffReadProc(thandle_t fd, tdata_t buf, tsize_t size) -{ - QIODevice* device = static_cast<QTiffHandler*>(fd)->device(); - return device->isReadable() ? device->read(static_cast<char *>(buf), size) : -1; -} - -tsize_t qtiffWriteProc(thandle_t fd, tdata_t buf, tsize_t size) -{ - return static_cast<QTiffHandler*>(fd)->device()->write(static_cast<char *>(buf), size); -} - -toff_t qtiffSeekProc(thandle_t fd, toff_t off, int whence) -{ - QIODevice *device = static_cast<QTiffHandler*>(fd)->device(); - switch (whence) { - case SEEK_SET: - device->seek(off); - break; - case SEEK_CUR: - device->seek(device->pos() + off); - break; - case SEEK_END: - device->seek(device->size() + off); - break; - } - - return device->pos(); -} - -int qtiffCloseProc(thandle_t /*fd*/) -{ - return 0; -} - -toff_t qtiffSizeProc(thandle_t fd) -{ - return static_cast<QTiffHandler*>(fd)->device()->size(); -} - -int qtiffMapProc(thandle_t /*fd*/, tdata_t* /*pbase*/, toff_t* /*psize*/) -{ - return 0; -} - -void qtiffUnmapProc(thandle_t /*fd*/, tdata_t /*base*/, toff_t /*size*/) -{ -} - -// for 32 bits images -inline void rotate_right_mirror_horizontal(QImage *const image)// rotate right->mirrored horizontal -{ - const int height = image->height(); - const int width = image->width(); - QImage generated(/* width = */ height, /* height = */ width, image->format()); - const uint32 *originalPixel = reinterpret_cast<const uint32*>(image->bits()); - uint32 *const generatedPixels = reinterpret_cast<uint32*>(generated.bits()); - for (int row=0; row < height; ++row) { - for (int col=0; col < width; ++col) { - int idx = col * height + row; - generatedPixels[idx] = *originalPixel; - ++originalPixel; - } - } - *image = generated; -} - -inline void rotate_right_mirror_vertical(QImage *const image) // rotate right->mirrored vertical -{ - const int height = image->height(); - const int width = image->width(); - QImage generated(/* width = */ height, /* height = */ width, image->format()); - const int lastCol = width - 1; - const int lastRow = height - 1; - const uint32 *pixel = reinterpret_cast<const uint32*>(image->bits()); - uint32 *const generatedBits = reinterpret_cast<uint32*>(generated.bits()); - for (int row=0; row < height; ++row) { - for (int col=0; col < width; ++col) { - int idx = (lastCol - col) * height + (lastRow - row); - generatedBits[idx] = *pixel; - ++pixel; - } - } - *image = generated; -} - -QTiffHandler::QTiffHandler() : QImageIOHandler() -{ - compression = NoCompression; -} - -bool QTiffHandler::canRead() const -{ - if (canRead(device())) { - setFormat("tiff"); - return true; - } - return false; -} - -bool QTiffHandler::canRead(QIODevice *device) -{ - if (!device) { - qWarning("QTiffHandler::canRead() called with no device"); - return false; - } - - // current implementation uses TIFFClientOpen which needs to be - // able to seek, so sequential devices are not supported - QByteArray header = device->peek(4); - return header == QByteArray::fromRawData("\x49\x49\x2A\x00", 4) - || header == QByteArray::fromRawData("\x4D\x4D\x00\x2A", 4); -} - -bool QTiffHandler::read(QImage *image) -{ - if (!canRead()) - return false; - - TIFF *const tiff = TIFFClientOpen("foo", - "r", - this, - qtiffReadProc, - qtiffWriteProc, - qtiffSeekProc, - qtiffCloseProc, - qtiffSizeProc, - qtiffMapProc, - qtiffUnmapProc); - - if (!tiff) { - return false; - } - uint32 width; - uint32 height; - uint16 photometric; - if (!TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &width) - || !TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &height) - || !TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric)) { - TIFFClose(tiff); - return false; - } - - // BitsPerSample defaults to 1 according to the TIFF spec. - uint16 bitPerSample; - if (!TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bitPerSample)) - bitPerSample = 1; - - bool grayscale = photometric == PHOTOMETRIC_MINISBLACK || photometric == PHOTOMETRIC_MINISWHITE; - if (grayscale && bitPerSample == 1) { - if (image->size() != QSize(width, height) || image->format() != QImage::Format_Mono) - *image = QImage(width, height, QImage::Format_Mono); - QVector<QRgb> colortable(2); - if (photometric == PHOTOMETRIC_MINISBLACK) { - colortable[0] = 0xff000000; - colortable[1] = 0xffffffff; - } else { - colortable[0] = 0xffffffff; - colortable[1] = 0xff000000; - } - image->setColorTable(colortable); - - if (!image->isNull()) { - for (uint32 y=0; y<height; ++y) { - if (TIFFReadScanline(tiff, image->scanLine(y), y, 0) < 0) { - TIFFClose(tiff); - return false; - } - } - } - } else { - if ((grayscale || photometric == PHOTOMETRIC_PALETTE) && bitPerSample == 8) { - if (image->size() != QSize(width, height) || image->format() != QImage::Format_Indexed8) - *image = QImage(width, height, QImage::Format_Indexed8); - if (!image->isNull()) { - const uint16 tableSize = 256; - QVector<QRgb> qtColorTable(tableSize); - if (grayscale) { - for (int i = 0; i<tableSize; ++i) { - const int c = (photometric == PHOTOMETRIC_MINISBLACK) ? i : (255 - i); - qtColorTable[i] = qRgb(c, c, c); - } - } else { - // create the color table - uint16 *redTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16))); - uint16 *greenTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16))); - uint16 *blueTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16))); - if (!redTable || !greenTable || !blueTable) { - TIFFClose(tiff); - return false; - } - if (!TIFFGetField(tiff, TIFFTAG_COLORMAP, &redTable, &greenTable, &blueTable)) { - TIFFClose(tiff); - return false; - } - - for (int i = 0; i<tableSize ;++i) { - const int red = redTable[i] / 257; - const int green = greenTable[i] / 257; - const int blue = blueTable[i] / 257; - qtColorTable[i] = qRgb(red, green, blue); - } - } - - image->setColorTable(qtColorTable); - for (uint32 y=0; y<height; ++y) { - if (TIFFReadScanline(tiff, image->scanLine(y), y, 0) < 0) { - TIFFClose(tiff); - return false; - } - } - - // free redTable, greenTable and greenTable done by libtiff - } - } else { - if (image->size() != QSize(width, height) || image->format() != QImage::Format_ARGB32) - *image = QImage(width, height, QImage::Format_ARGB32); - if (!image->isNull()) { - const int stopOnError = 1; - if (TIFFReadRGBAImageOriented(tiff, width, height, reinterpret_cast<uint32 *>(image->bits()), ORIENTATION_TOPLEFT, stopOnError)) { - for (uint32 y=0; y<height; ++y) - convert32BitOrder(image->scanLine(y), width); - } else { - TIFFClose(tiff); - return false; - } - } - } - } - - if (image->isNull()) { - TIFFClose(tiff); - return false; - } - - float resX = 0; - float resY = 0; - uint16 resUnit = RESUNIT_NONE; - if (TIFFGetField(tiff, TIFFTAG_RESOLUTIONUNIT, &resUnit) - && TIFFGetField(tiff, TIFFTAG_XRESOLUTION, &resX) - && TIFFGetField(tiff, TIFFTAG_YRESOLUTION, &resY)) { - - switch(resUnit) { - case RESUNIT_CENTIMETER: - image->setDotsPerMeterX(qRound(resX * 100)); - image->setDotsPerMeterY(qRound(resY * 100)); - break; - case RESUNIT_INCH: - image->setDotsPerMeterX(qRound(resX * (100 / 2.54))); - image->setDotsPerMeterY(qRound(resY * (100 / 2.54))); - break; - default: - // do nothing as defaults have already - // been set within the QImage class - break; - } - } - - // rotate the image if the orientation is defined in the file - uint16 orientationTag; - if (TIFFGetField(tiff, TIFFTAG_ORIENTATION, &orientationTag)) { - if (image->format() == QImage::Format_ARGB32) { - // TIFFReadRGBAImageOriented() flip the image but does not rotate them - switch (orientationTag) { - case 5: - rotate_right_mirror_horizontal(image); - break; - case 6: - rotate_right_mirror_vertical(image); - break; - case 7: - rotate_right_mirror_horizontal(image); - break; - case 8: - rotate_right_mirror_vertical(image); - break; - } - } else { - switch (orientationTag) { - case 1: // default orientation - break; - case 2: // mirror horizontal - *image = image->mirrored(true, false); - break; - case 3: // mirror both - *image = image->mirrored(true, true); - break; - case 4: // mirror vertical - *image = image->mirrored(false, true); - break; - case 5: // rotate right mirror horizontal - { - QMatrix transformation; - transformation.rotate(90); - *image = image->transformed(transformation); - *image = image->mirrored(true, false); - break; - } - case 6: // rotate right - { - QMatrix transformation; - transformation.rotate(90); - *image = image->transformed(transformation); - break; - } - case 7: // rotate right, mirror vertical - { - QMatrix transformation; - transformation.rotate(90); - *image = image->transformed(transformation); - *image = image->mirrored(false, true); - break; - } - case 8: // rotate left - { - QMatrix transformation; - transformation.rotate(270); - *image = image->transformed(transformation); - break; - } - } - } - } - - - TIFFClose(tiff); - return true; -} - -static bool checkGrayscale(const QVector<QRgb> &colorTable) -{ - if (colorTable.size() != 256) - return false; - - const bool increasing = (colorTable.at(0) == 0xff000000); - for (int i = 0; i < 256; ++i) { - if ((increasing && colorTable.at(i) != qRgb(i, i, i)) - || (!increasing && colorTable.at(i) != qRgb(255 - i, 255 - i, 255 - i))) - return false; - } - return true; -} - -bool QTiffHandler::write(const QImage &image) -{ - if (!device()->isWritable()) - return false; - - TIFF *const tiff = TIFFClientOpen("foo", - "w", - this, - qtiffReadProc, - qtiffWriteProc, - qtiffSeekProc, - qtiffCloseProc, - qtiffSizeProc, - qtiffMapProc, - qtiffUnmapProc); - if (!tiff) - return false; - - const int width = image.width(); - const int height = image.height(); - - if (!TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH, width) - || !TIFFSetField(tiff, TIFFTAG_IMAGELENGTH, height) - || !TIFFSetField(tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)) { - TIFFClose(tiff); - return false; - } - - // set the resolution - bool resolutionSet = false; - const int dotPerMeterX = image.dotsPerMeterX(); - const int dotPerMeterY = image.dotsPerMeterY(); - if ((dotPerMeterX % 100) == 0 - && (dotPerMeterY % 100) == 0) { - resolutionSet = TIFFSetField(tiff, TIFFTAG_RESOLUTIONUNIT, RESUNIT_CENTIMETER) - && TIFFSetField(tiff, TIFFTAG_XRESOLUTION, dotPerMeterX/100.0) - && TIFFSetField(tiff, TIFFTAG_YRESOLUTION, dotPerMeterY/100.0); - } else { - resolutionSet = TIFFSetField(tiff, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH) - && TIFFSetField(tiff, TIFFTAG_XRESOLUTION, static_cast<float>(image.logicalDpiX())) - && TIFFSetField(tiff, TIFFTAG_YRESOLUTION, static_cast<float>(image.logicalDpiY())); - } - if (!resolutionSet) { - TIFFClose(tiff); - return false; - } - - // configure image depth - const QImage::Format format = image.format(); - if (format == QImage::Format_Mono || format == QImage::Format_MonoLSB) { - uint16 photometric = PHOTOMETRIC_MINISBLACK; - if (image.colorTable().at(0) == 0xffffffff) - photometric = PHOTOMETRIC_MINISWHITE; - if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, photometric) - || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_CCITTRLE) - || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 1)) { - TIFFClose(tiff); - return false; - } - - // try to do the conversion in chunks no greater than 16 MB - int chunks = (width * height / (1024 * 1024 * 16)) + 1; - int chunkHeight = qMax(height / chunks, 1); - - int y = 0; - while (y < height) { - QImage chunk = image.copy(0, y, width, qMin(chunkHeight, height - y)).convertToFormat(QImage::Format_Mono); - - int chunkStart = y; - int chunkEnd = y + chunk.height(); - while (y < chunkEnd) { - if (TIFFWriteScanline(tiff, reinterpret_cast<uint32 *>(chunk.scanLine(y - chunkStart)), y) != 1) { - TIFFClose(tiff); - return false; - } - ++y; - } - } - TIFFClose(tiff); - } else if (format == QImage::Format_Indexed8) { - const QVector<QRgb> colorTable = image.colorTable(); - bool isGrayscale = checkGrayscale(colorTable); - if (isGrayscale) { - uint16 photometric = PHOTOMETRIC_MINISBLACK; - if (image.colorTable().at(0) == 0xffffffff) - photometric = PHOTOMETRIC_MINISWHITE; - if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, photometric) - || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_PACKBITS) - || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) { - TIFFClose(tiff); - return false; - } - } else { - if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE) - || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_PACKBITS) - || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) { - TIFFClose(tiff); - return false; - } - //// write the color table - // allocate the color tables - uint16 *redTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16))); - uint16 *greenTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16))); - uint16 *blueTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16))); - if (!redTable || !greenTable || !blueTable) { - TIFFClose(tiff); - return false; - } - - // set the color table - const int tableSize = colorTable.size(); - Q_ASSERT(tableSize <= 256); - for (int i = 0; i<tableSize; ++i) { - const QRgb color = colorTable.at(i); - redTable[i] = qRed(color) * 257; - greenTable[i] = qGreen(color) * 257; - blueTable[i] = qBlue(color) * 257; - } - - const bool setColorTableSuccess = TIFFSetField(tiff, TIFFTAG_COLORMAP, redTable, greenTable, blueTable); - - qFree(redTable); - qFree(greenTable); - qFree(blueTable); - - if (!setColorTableSuccess) { - TIFFClose(tiff); - return false; - } - } - - //// write the data - // try to do the conversion in chunks no greater than 16 MB - int chunks = (width * height/ (1024 * 1024 * 16)) + 1; - int chunkHeight = qMax(height / chunks, 1); - - int y = 0; - while (y < height) { - QImage chunk = image.copy(0, y, width, qMin(chunkHeight, height - y)); - - int chunkStart = y; - int chunkEnd = y + chunk.height(); - while (y < chunkEnd) { - if (TIFFWriteScanline(tiff, reinterpret_cast<uint32 *>(chunk.scanLine(y - chunkStart)), y) != 1) { - TIFFClose(tiff); - return false; - } - ++y; - } - } - TIFFClose(tiff); - - } else { - if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB) - || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_LZW) - || !TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, 4) - || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) { - TIFFClose(tiff); - return false; - } - // try to do the ARGB32 conversion in chunks no greater than 16 MB - int chunks = (width * height * 4 / (1024 * 1024 * 16)) + 1; - int chunkHeight = qMax(height / chunks, 1); - - int y = 0; - while (y < height) { - QImage chunk = image.copy(0, y, width, qMin(chunkHeight, height - y)).convertToFormat(QImage::Format_ARGB32); - - int chunkStart = y; - int chunkEnd = y + chunk.height(); - while (y < chunkEnd) { - if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) - convert32BitOrder(chunk.scanLine(y - chunkStart), width); - else - convert32BitOrderBigEndian(chunk.scanLine(y - chunkStart), width); - - if (TIFFWriteScanline(tiff, reinterpret_cast<uint32 *>(chunk.scanLine(y - chunkStart)), y) != 1) { - TIFFClose(tiff); - return false; - } - ++y; - } - } - TIFFClose(tiff); - } - - return true; -} - -QByteArray QTiffHandler::name() const -{ - return "tiff"; -} - -QVariant QTiffHandler::option(ImageOption option) const -{ - if (option == Size && canRead()) { - QSize imageSize; - qint64 pos = device()->pos(); - TIFF *tiff = TIFFClientOpen("foo", - "r", - const_cast<QTiffHandler*>(this), - qtiffReadProc, - qtiffWriteProc, - qtiffSeekProc, - qtiffCloseProc, - qtiffSizeProc, - qtiffMapProc, - qtiffUnmapProc); - - if (tiff) { - uint32 width = 0; - uint32 height = 0; - TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &width); - TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &height); - imageSize = QSize(width, height); - } - device()->seek(pos); - if (imageSize.isValid()) - return imageSize; - } else if (option == CompressionRatio) { - return compression; - } else if (option == ImageFormat) { - return QImage::Format_ARGB32; - } - return QVariant(); -} - -void QTiffHandler::setOption(ImageOption option, const QVariant &value) -{ - if (option == CompressionRatio && value.type() == QVariant::Int) - compression = value.toInt(); -} - -bool QTiffHandler::supportsOption(ImageOption option) const -{ - return option == CompressionRatio - || option == Size - || option == ImageFormat; -} - -void QTiffHandler::convert32BitOrder(void *buffer, int width) -{ - uint32 *target = reinterpret_cast<uint32 *>(buffer); - for (int32 x=0; x<width; ++x) { - uint32 p = target[x]; - // convert between ARGB and ABGR - target[x] = (p & 0xff000000) - | ((p & 0x00ff0000) >> 16) - | (p & 0x0000ff00) - | ((p & 0x000000ff) << 16); - } -} - -void QTiffHandler::convert32BitOrderBigEndian(void *buffer, int width) -{ - uint32 *target = reinterpret_cast<uint32 *>(buffer); - for (int32 x=0; x<width; ++x) { - uint32 p = target[x]; - target[x] = (p & 0xff000000) >> 24 - | (p & 0x00ff0000) << 8 - | (p & 0x0000ff00) << 8 - | (p & 0x000000ff) << 8; - } -} - -QT_END_NAMESPACE diff --git a/src/plugins/imageformats/tiff/qtiffhandler.h b/src/plugins/imageformats/tiff/qtiffhandler.h deleted file mode 100644 index 4534ed5..0000000 --- a/src/plugins/imageformats/tiff/qtiffhandler.h +++ /dev/null @@ -1,78 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QTIFFHANDLER_H -#define QTIFFHANDLER_H - -#include <QtGui/qimageiohandler.h> - -QT_BEGIN_NAMESPACE - -class QTiffHandler : public QImageIOHandler -{ -public: - QTiffHandler(); - - bool canRead() const; - bool read(QImage *image); - bool write(const QImage &image); - - QByteArray name() const; - - static bool canRead(QIODevice *device); - - QVariant option(ImageOption option) const; - void setOption(ImageOption option, const QVariant &value); - bool supportsOption(ImageOption option) const; - - enum Compression { - NoCompression = 0, - LzwCompression = 1 - }; -private: - void convert32BitOrder(void *buffer, int width); - void convert32BitOrderBigEndian(void *buffer, int width); - int compression; -}; - -QT_END_NAMESPACE - -#endif // QTIFFHANDLER_H diff --git a/src/plugins/imageformats/tiff/tiff.pro b/src/plugins/imageformats/tiff/tiff.pro index 08e471c..e781526 100644 --- a/src/plugins/imageformats/tiff/tiff.pro +++ b/src/plugins/imageformats/tiff/tiff.pro @@ -3,77 +3,8 @@ include(../../qpluginbase.pri) QTDIR_build:REQUIRES = "!contains(QT_CONFIG, no-tiff)" -HEADERS += qtiffhandler.h -SOURCES += main.cpp \ - qtiffhandler.cpp - -contains(QT_CONFIG, system-tiff) { - unix|win32-g++*:LIBS += -ltiff - win32:!win32-g++*:LIBS += libtiff.lib - - contains(QT_CONFIG, system-jpeg) { - unix|win32-g++*:LIBS += -ljpeg - win32:!win32-g++*:LIBS += libjpeg.lib - } -} else { - INCLUDEPATH += ../../../3rdparty/libtiff/libtiff - SOURCES += \ - ../../../3rdparty/libtiff/libtiff/tif_aux.c \ - ../../../3rdparty/libtiff/libtiff/tif_close.c \ - ../../../3rdparty/libtiff/libtiff/tif_codec.c \ - ../../../3rdparty/libtiff/libtiff/tif_color.c \ - ../../../3rdparty/libtiff/libtiff/tif_compress.c \ - ../../../3rdparty/libtiff/libtiff/tif_dir.c \ - ../../../3rdparty/libtiff/libtiff/tif_dirinfo.c \ - ../../../3rdparty/libtiff/libtiff/tif_dirread.c \ - ../../../3rdparty/libtiff/libtiff/tif_dirwrite.c \ - ../../../3rdparty/libtiff/libtiff/tif_dumpmode.c \ - ../../../3rdparty/libtiff/libtiff/tif_error.c \ - ../../../3rdparty/libtiff/libtiff/tif_extension.c \ - ../../../3rdparty/libtiff/libtiff/tif_fax3.c \ - ../../../3rdparty/libtiff/libtiff/tif_fax3sm.c \ - ../../../3rdparty/libtiff/libtiff/tif_flush.c \ - ../../../3rdparty/libtiff/libtiff/tif_getimage.c \ - ../../../3rdparty/libtiff/libtiff/tif_luv.c \ - ../../../3rdparty/libtiff/libtiff/tif_lzw.c \ - ../../../3rdparty/libtiff/libtiff/tif_next.c \ - ../../../3rdparty/libtiff/libtiff/tif_open.c \ - ../../../3rdparty/libtiff/libtiff/tif_packbits.c \ - ../../../3rdparty/libtiff/libtiff/tif_pixarlog.c \ - ../../../3rdparty/libtiff/libtiff/tif_predict.c \ - ../../../3rdparty/libtiff/libtiff/tif_print.c \ - ../../../3rdparty/libtiff/libtiff/tif_read.c \ - ../../../3rdparty/libtiff/libtiff/tif_strip.c \ - ../../../3rdparty/libtiff/libtiff/tif_swab.c \ - ../../../3rdparty/libtiff/libtiff/tif_thunder.c \ - ../../../3rdparty/libtiff/libtiff/tif_tile.c \ - ../../../3rdparty/libtiff/libtiff/tif_version.c \ - ../../../3rdparty/libtiff/libtiff/tif_warning.c \ - ../../../3rdparty/libtiff/libtiff/tif_write.c \ - ../../../3rdparty/libtiff/libtiff/tif_zip.c - win32:!wince*: { - SOURCES += ../../../3rdparty/libtiff/libtiff/tif_win32.c - } - unix: { - SOURCES += ../../../3rdparty/libtiff/libtiff/tif_unix.c - } - wince*: { - SOURCES += ../../../corelib/kernel/qfunctions_wince.cpp \ - ../../../3rdparty/libtiff/libtiff/tif_wince.c \ - ../../../3rdparty/libtiff/libtiff/tif_win32.c - } - symbian: { - SOURCES += ../../../3rdparty/libtiff/port/lfind.c - } -} - -contains(QT_CONFIG, system-zlib) { - symbian:LIBS_PRIVATE += -llibz - else:if(unix|win32-g++*):LIBS_PRIVATE += -lz - else:LIBS += zdll.lib -} else { - INCLUDEPATH += ../../../3rdparty/zlib -} +include(../../../gui/image/qtiffhandler.pri) +SOURCES += main.cpp QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/imageformats target.path += $$[QT_INSTALL_PLUGINS]/imageformats |