summaryrefslogtreecommitdiffstats
path: root/src/plugins/imageformats/tiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/imageformats/tiff')
-rw-r--r--src/plugins/imageformats/tiff/CMakeLists.txt100
-rw-r--r--src/plugins/imageformats/tiff/main.cpp6
-rw-r--r--src/plugins/imageformats/tiff/qtiffhandler.cpp124
-rw-r--r--src/plugins/imageformats/tiff/qtiffhandler_p.h4
4 files changed, 181 insertions, 53 deletions
diff --git a/src/plugins/imageformats/tiff/CMakeLists.txt b/src/plugins/imageformats/tiff/CMakeLists.txt
new file mode 100644
index 0000000..d38a8ec
--- /dev/null
+++ b/src/plugins/imageformats/tiff/CMakeLists.txt
@@ -0,0 +1,100 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Generated from tiff.pro.
+
+#####################################################################
+## QTiffPlugin Plugin:
+#####################################################################
+
+# special case begin
+# Handle the conditional finding of either system zlib or qt zlib.
+if(NOT QT_FEATURE_system_zlib)
+ find_package(Qt6 COMPONENTS ZlibPrivate)
+elseif(NOT TARGET WrapZLIB::WrapZLIB)
+ qt_find_package(WrapZLIB PROVIDED_TARGETS WrapZLIB::WrapZLIB)
+endif()
+# special case end
+
+qt_internal_add_plugin(QTiffPlugin
+ OUTPUT_NAME qtiff
+ PLUGIN_TYPE imageformats
+ SOURCES
+ main.cpp
+ qtiffhandler.cpp qtiffhandler_p.h
+ LIBRARIES
+ Qt::Core
+ Qt::Gui
+)
+
+#### Keys ignored in scope 1:.:.:tiff.pro:<TRUE>:
+# OTHER_FILES = "tiff.json"
+# QT_FOR_CONFIG = "imageformats-private"
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(QTiffPlugin CONDITION QT_FEATURE_system_tiff
+ LIBRARIES
+ TIFF::TIFF
+)
+
+qt_internal_extend_target(QTiffPlugin CONDITION NOT QT_FEATURE_system_tiff
+ 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_hash_set.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
+ INCLUDE_DIRECTORIES
+ ../../../3rdparty/libtiff/libtiff
+)
+
+qt_internal_extend_target(QTiffPlugin CONDITION WIN32 AND NOT QT_FEATURE_system_tiff
+ SOURCES
+ ../../../3rdparty/libtiff/libtiff/tif_win32.c
+)
+
+qt_internal_extend_target(QTiffPlugin CONDITION UNIX AND NOT QT_FEATURE_system_tiff
+ SOURCES
+ ../../../3rdparty/libtiff/libtiff/tif_unix.c
+)
+
+qt_internal_extend_target(QTiffPlugin CONDITION QT_FEATURE_system_zlib AND NOT QT_FEATURE_system_tiff
+ LIBRARIES
+ WrapZLIB::WrapZLIB
+)
+
+qt_internal_extend_target(QTiffPlugin CONDITION NOT QT_FEATURE_system_tiff AND NOT QT_FEATURE_system_zlib
+ LIBRARIES
+ Qt::ZlibPrivate
+)
diff --git a/src/plugins/imageformats/tiff/main.cpp b/src/plugins/imageformats/tiff/main.cpp
index 2c34097..8882f35 100644
--- a/src/plugins/imageformats/tiff/main.cpp
+++ b/src/plugins/imageformats/tiff/main.cpp
@@ -60,12 +60,12 @@ QImageIOPlugin::Capabilities QTiffPlugin::capabilities(QIODevice *device, const
{
if (format == "tiff" || format == "tif")
return Capabilities(CanRead | CanWrite);
+ Capabilities cap;
if (!format.isEmpty())
- return 0;
+ return cap;
if (!device->isOpen())
- return 0;
+ return cap;
- Capabilities cap;
if (device->isReadable() && QTiffHandler::canRead(device))
cap |= CanRead;
if (device->isWritable())
diff --git a/src/plugins/imageformats/tiff/qtiffhandler.cpp b/src/plugins/imageformats/tiff/qtiffhandler.cpp
index 65873e1..f0dfe7f 100644
--- a/src/plugins/imageformats/tiff/qtiffhandler.cpp
+++ b/src/plugins/imageformats/tiff/qtiffhandler.cpp
@@ -43,6 +43,9 @@
#include <qdebug.h>
#include <qimage.h>
#include <qglobal.h>
+#include <qbuffer.h>
+#include <qfiledevice.h>
+
extern "C" {
#include "tiffio.h"
}
@@ -90,13 +93,33 @@ toff_t qtiffSizeProc(thandle_t fd)
return static_cast<QIODevice *>(fd)->size();
}
-int qtiffMapProc(thandle_t /*fd*/, tdata_t* /*pbase*/, toff_t* /*psize*/)
+int qtiffMapProc(thandle_t fd, void **base, toff_t *size)
{
+ QIODevice *device = static_cast<QIODevice *>(fd);
+
+ QFileDevice *file = qobject_cast<QFileDevice *>(device);
+ if (file) {
+ *base = file->map(0, file->size());
+ if (*base != nullptr) {
+ *size = file->size();
+ return 1;
+ }
+ } else {
+ QBuffer *buf = qobject_cast<QBuffer *>(device);
+ if (buf) {
+ *base = const_cast<char *>(buf->data().constData());
+ *size = buf->size();
+ return 1;
+ }
+ }
return 0;
}
-void qtiffUnmapProc(thandle_t /*fd*/, tdata_t /*base*/, toff_t /*size*/)
+void qtiffUnmapProc(thandle_t fd, void *base, toff_t /*size*/)
{
+ QFileDevice *file = qobject_cast<QFileDevice *>(static_cast<QIODevice *>(fd));
+ if (file && base)
+ file->unmap(static_cast<uchar *>(base));
}
@@ -116,7 +139,7 @@ public:
QImageIOHandler::Transformations transformation;
QImage::Format format;
QSize size;
- uint16 photometric;
+ uint16_t photometric;
bool grayscale;
bool headersRead;
int currentDirectory;
@@ -205,9 +228,14 @@ bool QTiffHandlerPrivate::canRead(QIODevice *device)
// 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);
+ char h[4];
+ if (device->peek(h, 4) != 4)
+ return false;
+ if ((h[0] == 0x49 && h[1] == 0x49) && (h[2] == 0x2a || h[2] == 0x2b) && h[3] == 0)
+ return true; // Little endian, classic or bigtiff
+ if ((h[0] == 0x4d && h[1] == 0x4d) && h[2] == 0 && (h[3] == 0x2a || h[3] == 0x2b))
+ return true; // Big endian, classic or bigtiff
+ return false;
}
bool QTiffHandlerPrivate::openForRead(QIODevice *device)
@@ -245,8 +273,8 @@ bool QTiffHandlerPrivate::readHeaders(QIODevice *device)
TIFFSetDirectory(tiff, currentDirectory);
- uint32 width;
- uint32 height;
+ uint32_t width;
+ uint32_t height;
if (!TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &width)
|| !TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &height)
|| !TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric)) {
@@ -255,15 +283,15 @@ bool QTiffHandlerPrivate::readHeaders(QIODevice *device)
}
size = QSize(width, height);
- uint16 orientationTag;
+ uint16_t orientationTag;
if (TIFFGetField(tiff, TIFFTAG_ORIENTATION, &orientationTag))
transformation = exif2Qt(orientationTag);
// BitsPerSample defaults to 1 according to the TIFF spec.
- uint16 bitPerSample;
+ uint16_t bitPerSample;
if (!TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bitPerSample))
bitPerSample = 1;
- uint16 samplesPerPixel; // they may be e.g. grayscale with 2 samples per pixel
+ uint16_t samplesPerPixel; // they may be e.g. grayscale with 2 samples per pixel
if (!TIFFGetField(tiff, TIFFTAG_SAMPLESPERPIXEL, &samplesPerPixel))
samplesPerPixel = 1;
@@ -278,13 +306,13 @@ bool QTiffHandlerPrivate::readHeaders(QIODevice *device)
else if ((grayscale || photometric == PHOTOMETRIC_PALETTE) && bitPerSample == 8 && samplesPerPixel == 1)
format = QImage::Format_Indexed8;
else if (samplesPerPixel < 4)
- if (bitPerSample > 8 && photometric == PHOTOMETRIC_RGB)
+ if (bitPerSample == 16 && photometric == PHOTOMETRIC_RGB)
format = QImage::Format_RGBX64;
else
format = QImage::Format_RGB32;
else {
- uint16 count;
- uint16 *extrasamples;
+ uint16_t count;
+ uint16_t *extrasamples;
// If there is any definition of the alpha-channel, libtiff will return premultiplied
// data to us. If there is none, libtiff will not touch it and we assume it to be
// non-premultiplied, matching behavior of tested image editors, and how older Qt
@@ -294,7 +322,7 @@ bool QTiffHandlerPrivate::readHeaders(QIODevice *device)
if (!gotField || !count || extrasamples[0] == EXTRASAMPLE_UNSPECIFIED)
premultiplied = false;
- if (bitPerSample > 8 && photometric == PHOTOMETRIC_RGB) {
+ if (bitPerSample == 16 && photometric == PHOTOMETRIC_RGB) {
// We read 64-bit raw, so unassoc remains unpremultiplied.
if (gotField && count && extrasamples[0] == EXTRASAMPLE_UNASSALPHA)
premultiplied = false;
@@ -356,6 +384,8 @@ bool QTiffHandler::read(QImage *image)
}
TIFF *const tiff = d->tiff;
+ if (TIFFIsTiled(tiff) && TIFFTileSize64(tiff) > uint64_t(image->sizeInBytes())) // Corrupt image
+ return false;
const quint32 width = d->size.width();
const quint32 height = d->size.height();
@@ -372,7 +402,7 @@ bool QTiffHandler::read(QImage *image)
}
image->setColorTable(colortable);
} else if (format == QImage::Format_Indexed8) {
- const uint16 tableSize = 256;
+ const uint16_t tableSize = 256;
QVector<QRgb> qtColorTable(tableSize);
if (d->grayscale) {
for (int i = 0; i<tableSize; ++i) {
@@ -381,9 +411,9 @@ bool QTiffHandler::read(QImage *image)
}
} else {
// create the color table
- uint16 *redTable = 0;
- uint16 *greenTable = 0;
- uint16 *blueTable = 0;
+ uint16_t *redTable = 0;
+ uint16_t *greenTable = 0;
+ uint16_t *blueTable = 0;
if (!TIFFGetField(tiff, TIFFTAG_COLORMAP, &redTable, &greenTable, &blueTable)) {
d->close();
return false;
@@ -418,14 +448,19 @@ bool QTiffHandler::read(QImage *image)
quint32 tileWidth, tileLength;
TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &tileWidth);
TIFFGetField(tiff, TIFFTAG_TILELENGTH, &tileLength);
- uchar *buf = (uchar *)_TIFFmalloc(TIFFTileSize(tiff));
- if (!tileWidth || !tileLength || !buf) {
- _TIFFfree(buf);
+ if (!tileWidth || !tileLength || tileWidth % 16 || tileLength % 16) {
d->close();
return false;
}
quint32 byteWidth = (format == QImage::Format_Mono) ? (width + 7)/8 : (width * bytesPerPixel);
quint32 byteTileWidth = (format == QImage::Format_Mono) ? tileWidth/8 : (tileWidth * bytesPerPixel);
+ tmsize_t byteTileSize = TIFFTileSize(tiff);
+ uchar *buf = (uchar *)_TIFFmalloc(byteTileSize);
+ if (!buf || byteTileSize / tileLength < byteTileWidth) {
+ _TIFFfree(buf);
+ d->close();
+ return false;
+ }
for (quint32 y = 0; y < height; y += tileLength) {
for (quint32 x = 0; x < width; x += tileWidth) {
if (TIFFReadTile(tiff, buf, x, y, 0, 0) < 0) {
@@ -443,7 +478,11 @@ bool QTiffHandler::read(QImage *image)
}
_TIFFfree(buf);
} else {
- for (uint32 y=0; y<height; ++y) {
+ if (image->bytesPerLine() < TIFFScanlineSize(tiff)) {
+ d->close();
+ return false;
+ }
+ for (uint32_t y=0; y<height; ++y) {
if (TIFFReadScanline(tiff, image->scanLine(y), y, 0) < 0) {
d->close();
return false;
@@ -454,8 +493,8 @@ bool QTiffHandler::read(QImage *image)
rgb48fixup(image);
} else {
const int stopOnError = 1;
- if (TIFFReadRGBAImageOriented(tiff, width, height, reinterpret_cast<uint32 *>(image->bits()), qt2Exif(d->transformation), stopOnError)) {
- for (uint32 y=0; y<height; ++y)
+ if (TIFFReadRGBAImageOriented(tiff, width, height, reinterpret_cast<uint32_t *>(image->bits()), qt2Exif(d->transformation), stopOnError)) {
+ for (uint32_t y=0; y<height; ++y)
convert32BitOrder(image->scanLine(y), width);
} else {
d->close();
@@ -466,7 +505,7 @@ bool QTiffHandler::read(QImage *image)
float resX = 0;
float resY = 0;
- uint16 resUnit;
+ uint16_t resUnit;
if (!TIFFGetField(tiff, TIFFTAG_RESOLUTIONUNIT, &resUnit))
resUnit = RESUNIT_INCH;
@@ -489,7 +528,7 @@ bool QTiffHandler::read(QImage *image)
}
}
- uint32 count;
+ uint32_t count;
void *profile;
if (TIFFGetField(tiff, TIFFTAG_ICCPROFILE, &count, &profile)) {
QByteArray iccProfile(reinterpret_cast<const char *>(profile), count);
@@ -613,7 +652,7 @@ bool QTiffHandler::write(const QImage &image)
// configure image depth
const QImage::Format format = image.format();
if (format == QImage::Format_Mono || format == QImage::Format_MonoLSB) {
- uint16 photometric = PHOTOMETRIC_MINISBLACK;
+ uint16_t photometric = PHOTOMETRIC_MINISBLACK;
if (image.colorTable().at(0) == 0xffffffff)
photometric = PHOTOMETRIC_MINISWHITE;
if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, photometric)
@@ -635,7 +674,7 @@ bool QTiffHandler::write(const QImage &image)
int chunkStart = y;
int chunkEnd = y + chunk.height();
while (y < chunkEnd) {
- if (TIFFWriteScanline(tiff, reinterpret_cast<uint32 *>(chunk.scanLine(y - chunkStart)), y) != 1) {
+ if (TIFFWriteScanline(tiff, reinterpret_cast<uint32_t *>(chunk.scanLine(y - chunkStart)), y) != 1) {
TIFFClose(tiff);
return false;
}
@@ -650,7 +689,7 @@ bool QTiffHandler::write(const QImage &image)
QVector<QRgb> colorTable = effectiveColorTable(image);
bool isGrayscale = checkGrayscale(colorTable);
if (isGrayscale) {
- uint16 photometric = PHOTOMETRIC_MINISBLACK;
+ uint16_t photometric = PHOTOMETRIC_MINISBLACK;
if (colorTable.at(0) == 0xffffffff)
photometric = PHOTOMETRIC_MINISWHITE;
if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, photometric)
@@ -672,9 +711,9 @@ bool QTiffHandler::write(const QImage &image)
// allocate the color tables
const int tableSize = colorTable.size();
Q_ASSERT(tableSize <= 256);
- QVarLengthArray<uint16> redTable(tableSize);
- QVarLengthArray<uint16> greenTable(tableSize);
- QVarLengthArray<uint16> blueTable(tableSize);
+ QVarLengthArray<uint16_t> redTable(tableSize);
+ QVarLengthArray<uint16_t> greenTable(tableSize);
+ QVarLengthArray<uint16_t> blueTable(tableSize);
// set the color table
for (int i = 0; i<tableSize; ++i) {
@@ -727,7 +766,7 @@ bool QTiffHandler::write(const QImage &image)
} else if (format == QImage::Format_RGBA64
|| format == QImage::Format_RGBA64_Premultiplied) {
const bool premultiplied = image.format() != QImage::Format_RGBA64;
- const uint16 extrasamples = premultiplied ? EXTRASAMPLE_ASSOCALPHA : EXTRASAMPLE_UNASSALPHA;
+ const uint16_t extrasamples = premultiplied ? EXTRASAMPLE_ASSOCALPHA : EXTRASAMPLE_UNASSALPHA;
if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB)
|| !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_LZW)
|| !TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, 4)
@@ -775,7 +814,7 @@ bool QTiffHandler::write(const QImage &image)
} else {
const bool premultiplied = image.format() != QImage::Format_ARGB32
&& image.format() != QImage::Format_RGBA8888;
- const uint16 extrasamples = premultiplied ? EXTRASAMPLE_ASSOCALPHA : EXTRASAMPLE_UNASSALPHA;
+ const uint16_t extrasamples = premultiplied ? EXTRASAMPLE_ASSOCALPHA : EXTRASAMPLE_UNASSALPHA;
if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB)
|| !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_LZW)
|| !TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, 4)
@@ -811,13 +850,6 @@ bool QTiffHandler::write(const QImage &image)
return true;
}
-#if QT_DEPRECATED_SINCE(5, 13)
-QByteArray QTiffHandler::name() const
-{
- return "tiff";
-}
-#endif
-
QVariant QTiffHandler::option(ImageOption option) const
{
if (option == Size && canRead()) {
@@ -896,9 +928,9 @@ int QTiffHandler::currentImageNumber() const
void QTiffHandler::convert32BitOrder(void *buffer, int width)
{
- uint32 *target = reinterpret_cast<uint32 *>(buffer);
- for (int32 x=0; x<width; ++x) {
- uint32 p = target[x];
+ uint32_t *target = reinterpret_cast<uint32_t *>(buffer);
+ for (int32_t x=0; x<width; ++x) {
+ uint32_t p = target[x];
// convert between ARGB and ABGR
target[x] = (p & 0xff000000)
| ((p & 0x00ff0000) >> 16)
@@ -915,7 +947,7 @@ void QTiffHandler::rgb48fixup(QImage *image)
uchar *scanline = image->bits();
const qsizetype bpl = image->bytesPerLine();
for (int y = 0; y < h; ++y) {
- quint16 *dst = reinterpret_cast<uint16 *>(scanline);
+ quint16 *dst = reinterpret_cast<uint16_t *>(scanline);
for (int x = w - 1; x >= 0; --x) {
dst[x * 4 + 3] = 0xffff;
dst[x * 4 + 2] = dst[x * 3 + 2];
diff --git a/src/plugins/imageformats/tiff/qtiffhandler_p.h b/src/plugins/imageformats/tiff/qtiffhandler_p.h
index c2eb412..97a63e1 100644
--- a/src/plugins/imageformats/tiff/qtiffhandler_p.h
+++ b/src/plugins/imageformats/tiff/qtiffhandler_p.h
@@ -55,10 +55,6 @@ public:
bool read(QImage *image) override;
bool write(const QImage &image) override;
-#if QT_DEPRECATED_SINCE(5, 13)
- QByteArray name() const override;
-#endif
-
static bool canRead(QIODevice *device);
QVariant option(ImageOption option) const override;