diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-03-23 09:18:55 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-03-23 09:18:55 (GMT) |
commit | e5fcad302d86d316390c6b0f62759a067313e8a9 (patch) | |
tree | c2afbf6f1066b6ce261f14341cf6d310e5595bc1 /src/plugins/imageformats/tiff | |
download | Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.zip Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.gz Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.bz2 |
Long live Qt 4.5!
Diffstat (limited to 'src/plugins/imageformats/tiff')
-rw-r--r-- | src/plugins/imageformats/tiff/main.cpp | 97 | ||||
-rw-r--r-- | src/plugins/imageformats/tiff/qtiffhandler.cpp | 328 | ||||
-rw-r--r-- | src/plugins/imageformats/tiff/qtiffhandler.h | 78 | ||||
-rw-r--r-- | src/plugins/imageformats/tiff/tiff.pro | 70 |
4 files changed, 573 insertions, 0 deletions
diff --git a/src/plugins/imageformats/tiff/main.cpp b/src/plugins/imageformats/tiff/main.cpp new file mode 100644 index 0000000..f6590d4 --- /dev/null +++ b/src/plugins/imageformats/tiff/main.cpp @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qimageiohandler.h> +#include <qdebug.h> + +#ifndef QT_NO_IMAGEFORMATPLUGIN + +#ifdef QT_NO_IMAGEFORMAT_TIFF +#undef QT_NO_IMAGEFORMAT_TIFF +#endif +#include "qtiffhandler.h" + +QT_BEGIN_NAMESPACE + +class QTiffPlugin : public QImageIOPlugin +{ +public: + Capabilities capabilities(QIODevice * device, const QByteArray & format) const; + QImageIOHandler * create(QIODevice * device, const QByteArray & format = QByteArray()) const; + QStringList keys() const; +}; + +QImageIOPlugin::Capabilities QTiffPlugin::capabilities(QIODevice *device, const QByteArray &format) const +{ + if (format == "tiff" || format == "tif") + return Capabilities(CanRead | CanWrite); + if (!format.isEmpty()) + return 0; + if (!device->isOpen()) + return 0; + + Capabilities cap; + if (device->isReadable() && QTiffHandler::canRead(device)) + cap |= CanRead; + if (device->isWritable()) + cap |= CanWrite; + return cap; +} + +QImageIOHandler* QTiffPlugin::create(QIODevice *device, const QByteArray &format) const +{ + QImageIOHandler *tiffHandler = new QTiffHandler(); + tiffHandler->setDevice(device); + tiffHandler->setFormat(format); + return tiffHandler; +} + +QStringList QTiffPlugin::keys() const +{ + return QStringList() << QLatin1String("tiff") << QLatin1String("tif"); +} + +Q_EXPORT_STATIC_PLUGIN(QTiffPlugin) +Q_EXPORT_PLUGIN2(qtiff, QTiffPlugin) + +QT_END_NAMESPACE + +#endif /* QT_NO_IMAGEFORMATPLUGIN */ diff --git a/src/plugins/imageformats/tiff/qtiffhandler.cpp b/src/plugins/imageformats/tiff/qtiffhandler.cpp new file mode 100644 index 0000000..518e6d1 --- /dev/null +++ b/src/plugins/imageformats/tiff/qtiffhandler.cpp @@ -0,0 +1,328 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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*/) +{ +} + +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 *tiff = TIFFClientOpen("foo", + "r", + 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); + if (image->size() != QSize(width, height) || image->format() != QImage::Format_ARGB32) + *image = QImage(width, height, QImage::Format_ARGB32); + if (!image->isNull()) { + if (TIFFReadRGBAImageOriented(tiff, width, height, reinterpret_cast<uint32 *>(image->bits()), ORIENTATION_TOPLEFT, 0)) { + uint16 resUnit = RESUNIT_NONE; + float resX = 0; + float resY = 0; + 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; + } + for (uint32 y=0; y<height; ++y) + convert32BitOrder(image->scanLine(y), width); + } else { + *image = QImage(); + } + } + TIFFClose(tiff); + } + + if (image->isNull()) + return false; + + return true; +} + +bool QTiffHandler::write(const QImage &image) +{ + if (!device()->isWritable()) + return false; + + TIFF *tiff = TIFFClientOpen("foo", + "w", + this, + qtiffReadProc, + qtiffWriteProc, + qtiffSeekProc, + qtiffCloseProc, + qtiffSizeProc, + qtiffMapProc, + qtiffUnmapProc); + + if (tiff) { + int width = image.width(); + int height = image.height(); + int depth = 32; + + if (!TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH, width) + || !TIFFSetField(tiff, TIFFTAG_IMAGELENGTH, height) + || !TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB) + || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_LZW) + || !TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, depth/8) + || !TIFFSetField(tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG) + || !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); + } else { + return false; + } + 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 new file mode 100644 index 0000000..0c0d9ef --- /dev/null +++ b/src/plugins/imageformats/tiff/qtiffhandler.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 new file mode 100644 index 0000000..8930cf3 --- /dev/null +++ b/src/plugins/imageformats/tiff/tiff.pro @@ -0,0 +1,70 @@ +TARGET = qtiff +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:LIBS += -ltiff + win32:LIBS += libtiff.lib +} +!contains(QT_CONFIG, system-tiff) { + 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 { + SOURCES += ../../../3rdparty/libtiff/libtiff/tif_win32.c + } + unix: { + SOURCES += ../../../3rdparty/libtiff/libtiff/tif_unix.c + } + wince*: { + SOURCES += ../../../corelib/kernel/qfunctions_wince.cpp + } +} + +contains(QT_CONFIG, system-zlib) { + LIBS += -lz +} +!contains(QT_CONFIG, system-zlib) { + INCLUDEPATH += ../../../3rdparty/zlib +} + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/imageformats +target.path += $$[QT_INSTALL_PLUGINS]/imageformats +INSTALLS += target |