summaryrefslogtreecommitdiffstats
path: root/src/plugins/imageformats
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/imageformats')
-rw-r--r--src/plugins/imageformats/CMakeLists.txt3
-rw-r--r--src/plugins/imageformats/gif/CMakeLists.txt12
-rw-r--r--src/plugins/imageformats/gif/qgifhandler.cpp6
-rw-r--r--src/plugins/imageformats/ico/CMakeLists.txt7
-rw-r--r--src/plugins/imageformats/ico/qicohandler.cpp9
-rw-r--r--src/plugins/imageformats/ico/qicohandler.h2
-rw-r--r--src/plugins/imageformats/jpeg/CMakeLists.txt3
-rw-r--r--src/plugins/imageformats/jpeg/qjpeghandler.cpp117
8 files changed, 121 insertions, 38 deletions
diff --git a/src/plugins/imageformats/CMakeLists.txt b/src/plugins/imageformats/CMakeLists.txt
index 00fefbdc0d..c5ab716d00 100644
--- a/src/plugins/imageformats/CMakeLists.txt
+++ b/src/plugins/imageformats/CMakeLists.txt
@@ -1,4 +1,5 @@
-# Generated from imageformats.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
if(QT_FEATURE_ico)
add_subdirectory(ico)
diff --git a/src/plugins/imageformats/gif/CMakeLists.txt b/src/plugins/imageformats/gif/CMakeLists.txt
index 1241fa2f0f..b56859a264 100644
--- a/src/plugins/imageformats/gif/CMakeLists.txt
+++ b/src/plugins/imageformats/gif/CMakeLists.txt
@@ -1,4 +1,5 @@
-# Generated from gif.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QGifPlugin Plugin:
@@ -10,10 +11,7 @@ qt_internal_add_plugin(QGifPlugin
SOURCES
main.cpp
qgifhandler.cpp qgifhandler_p.h
- LIBRARIES # special case
- Qt::Gui # special case
- Qt::GuiPrivate # special case
+ LIBRARIES
+ Qt::Gui
+ Qt::GuiPrivate
)
-
-#### Keys ignored in scope 1:.:.:gif.pro:<TRUE>:
-# OTHER_FILES = "gif.json"
diff --git a/src/plugins/imageformats/gif/qgifhandler.cpp b/src/plugins/imageformats/gif/qgifhandler.cpp
index add6b64855..8ad4ff7510 100644
--- a/src/plugins/imageformats/gif/qgifhandler.cpp
+++ b/src/plugins/imageformats/gif/qgifhandler.cpp
@@ -1146,9 +1146,9 @@ QVariant QGifHandler::option(ImageOption option) const
}
// 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();
+ return (imageSizes.size() > 0) ? QVariant(imageSizes.at(0)) : QVariant();
// after the last frame has been read, the next size is undefined
- if (frameNumber >= imageSizes.count() - 1)
+ if (frameNumber >= imageSizes.size() - 1)
return QVariant();
// and the last case: the size of the next frame
return imageSizes.at(frameNumber + 1);
@@ -1175,7 +1175,7 @@ int QGifHandler::imageCount() const
QGIFFormat::scan(device(), &imageSizes, &loopCnt);
scanIsCached = true;
}
- return imageSizes.count();
+ return imageSizes.size();
}
int QGifHandler::loopCount() const
diff --git a/src/plugins/imageformats/ico/CMakeLists.txt b/src/plugins/imageformats/ico/CMakeLists.txt
index 8cdedb2cfe..c9cd0f0d40 100644
--- a/src/plugins/imageformats/ico/CMakeLists.txt
+++ b/src/plugins/imageformats/ico/CMakeLists.txt
@@ -1,4 +1,5 @@
-# Generated from ico.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QICOPlugin Plugin:
@@ -14,7 +15,5 @@ qt_internal_add_plugin(QICOPlugin
Qt::Core
Qt::CorePrivate
Qt::Gui
+ NO_UNITY_BUILD
)
-
-#### Keys ignored in scope 1:.:.:ico.pro:<TRUE>:
-# OTHER_FILES = "ico.json"
diff --git a/src/plugins/imageformats/ico/qicohandler.cpp b/src/plugins/imageformats/ico/qicohandler.cpp
index 496e927919..18b39766f5 100644
--- a/src/plugins/imageformats/ico/qicohandler.cpp
+++ b/src/plugins/imageformats/ico/qicohandler.cpp
@@ -499,7 +499,7 @@ QImage ICOReader::iconAt(int index)
if (!image.isNull()) {
readBMP(image);
if (!image.isNull()) {
- if (icoAttrib.depth == 32) {
+ if (icoAttrib.nbits == 32) {
img = std::move(image).convertToFormat(QImage::Format_ARGB32_Premultiplied);
} else {
QImage mask(image.width(), image.height(), QImage::Format_Mono);
@@ -565,14 +565,14 @@ bool ICOReader::write(QIODevice *device, const QList<QImage> &images)
{
bool retValue = false;
- if (images.count()) {
+ if (images.size()) {
qint64 origOffset = device->pos();
ICONDIR id;
id.idReserved = 0;
id.idType = 1;
- id.idCount = images.count();
+ id.idCount = images.size();
ICONDIRENTRY * entries = new ICONDIRENTRY[id.idCount];
BMP_INFOHDR * bmpHeaders = new BMP_INFOHDR[id.idCount];
@@ -735,6 +735,8 @@ bool QtIcoHandler::supportsOption(ImageOption option) const
*/
bool QtIcoHandler::canRead() const
{
+ if (knownCanRead)
+ return true;
bool bCanRead = false;
QIODevice *device = QImageIOHandler::device();
if (device) {
@@ -744,6 +746,7 @@ bool QtIcoHandler::canRead() const
} else {
qCWarning(lcIco, "QtIcoHandler::canRead() called with no device");
}
+ knownCanRead = bCanRead;
return bCanRead;
}
diff --git a/src/plugins/imageformats/ico/qicohandler.h b/src/plugins/imageformats/ico/qicohandler.h
index 0fe251ab60..61c3eea465 100644
--- a/src/plugins/imageformats/ico/qicohandler.h
+++ b/src/plugins/imageformats/ico/qicohandler.h
@@ -30,7 +30,7 @@ public:
private:
int m_currentIconIndex;
ICOReader *m_pICOReader;
-
+ mutable bool knownCanRead = false;
};
QT_END_NAMESPACE
diff --git a/src/plugins/imageformats/jpeg/CMakeLists.txt b/src/plugins/imageformats/jpeg/CMakeLists.txt
index bb5a78fa40..6b077a7647 100644
--- a/src/plugins/imageformats/jpeg/CMakeLists.txt
+++ b/src/plugins/imageformats/jpeg/CMakeLists.txt
@@ -1,4 +1,5 @@
-# Generated from jpeg.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
qt_find_package(WrapJpeg PROVIDED_TARGETS WrapJpeg::WrapJpeg)
diff --git a/src/plugins/imageformats/jpeg/qjpeghandler.cpp b/src/plugins/imageformats/jpeg/qjpeghandler.cpp
index eebc5940ce..59b73587c5 100644
--- a/src/plugins/imageformats/jpeg/qjpeghandler.cpp
+++ b/src/plugins/imageformats/jpeg/qjpeghandler.cpp
@@ -49,6 +49,7 @@ extern "C" {
static void my_error_exit (j_common_ptr cinfo)
{
+ (*cinfo->err->output_message)(cinfo);
my_error_mgr* myerr = (my_error_mgr*) cinfo->err;
longjmp(myerr->setjmp_buffer, 1);
}
@@ -171,9 +172,14 @@ inline static bool read_jpeg_format(QImage::Format &format, j_decompress_ptr cin
format = QImage::Format_Grayscale8;
break;
case 3:
- case 4:
format = QImage::Format_RGB32;
break;
+ case 4:
+ if (cinfo->out_color_space == JCS_CMYK)
+ format = QImage::Format_CMYK8888;
+ else
+ format = QImage::Format_RGB32;
+ break;
default:
result = false;
break;
@@ -191,9 +197,14 @@ static bool ensureValidImage(QImage *dest, struct jpeg_decompress_struct *info,
format = QImage::Format_Grayscale8;
break;
case 3:
- case 4:
format = QImage::Format_RGB32;
break;
+ case 4:
+ if (info->out_color_space == JCS_CMYK)
+ format = QImage::Format_CMYK8888;
+ else
+ format = QImage::Format_RGB32;
+ break;
default:
return false; // unsupported format
}
@@ -205,7 +216,7 @@ static bool read_jpeg_image(QImage *outImage,
QSize scaledSize, QRect scaledClipRect,
QRect clipRect, int quality,
Rgb888ToRgb32Converter converter,
- j_decompress_ptr info, struct my_error_mgr* err )
+ j_decompress_ptr info, struct my_error_mgr* err, bool invertCMYK)
{
if (!setjmp(err->setjmp_buffer)) {
// -1 means default quality.
@@ -347,14 +358,15 @@ static bool read_jpeg_image(QImage *outImage,
QRgb *out = (QRgb*)outImage->scanLine(y);
converter(out, in, clip.width());
} else if (info->out_color_space == JCS_CMYK) {
- // Convert CMYK->RGB.
uchar *in = rows[0] + clip.x() * 4;
- QRgb *out = (QRgb*)outImage->scanLine(y);
- for (int i = 0; i < clip.width(); ++i) {
- int k = in[3];
- *out++ = qRgb(k * in[0] / 255, k * in[1] / 255,
- k * in[2] / 255);
- in += 4;
+ quint32 *out = (quint32*)outImage->scanLine(y);
+ if (invertCMYK) {
+ for (int i = 0; i < clip.width(); ++i) {
+ *out++ = 0xffffffffu - (in[0] | in[1] << 8 | in[2] << 16 | in[3] << 24);
+ in += 4;
+ }
+ } else {
+ memcpy(out, in, clip.width() * 4);
}
} else if (info->output_components == 1) {
// Grayscale.
@@ -458,7 +470,7 @@ static inline void set_text(const QImage &image, j_compress_ptr cinfo, const QSt
if (!comment.isEmpty())
comment += ": ";
comment += it.value().toUtf8();
- if (comment.length() > maxMarkerSize)
+ if (comment.size() > maxMarkerSize)
comment.truncate(maxMarkerSize);
jpeg_write_marker(cinfo, JPEG_COM, (const JOCTET *)comment.constData(), comment.size());
}
@@ -492,7 +504,8 @@ static bool do_write_jpeg_image(struct jpeg_compress_struct &cinfo,
int sourceQuality,
const QString &description,
bool optimize,
- bool progressive)
+ bool progressive,
+ bool invertCMYK)
{
bool success = false;
const QList<QRgb> cmap = image.colorTable();
@@ -532,10 +545,15 @@ static bool do_write_jpeg_image(struct jpeg_compress_struct &cinfo,
cinfo.in_color_space = gray ? JCS_GRAYSCALE : JCS_RGB;
break;
case QImage::Format_Grayscale8:
+ case QImage::Format_Grayscale16:
gray = true;
cinfo.input_components = 1;
cinfo.in_color_space = JCS_GRAYSCALE;
break;
+ case QImage::Format_CMYK8888:
+ cinfo.input_components = 4;
+ cinfo.in_color_space = JCS_CMYK;
+ break;
default:
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
@@ -568,7 +586,7 @@ static bool do_write_jpeg_image(struct jpeg_compress_struct &cinfo,
jpeg_start_compress(&cinfo, TRUE);
set_text(image, &cinfo, description);
- if (cinfo.in_color_space == JCS_RGB)
+ if (cinfo.in_color_space == JCS_RGB || cinfo.in_color_space == JCS_CMYK)
write_icc_profile(image, &cinfo);
row_pointer[0] = new uchar[cinfo.image_width*cinfo.input_components];
@@ -630,6 +648,12 @@ static bool do_write_jpeg_image(struct jpeg_compress_struct &cinfo,
case QImage::Format_Grayscale8:
memcpy(row, image.constScanLine(cinfo.next_scanline), w);
break;
+ case QImage::Format_Grayscale16:
+ {
+ QImage rowImg = image.copy(0, cinfo.next_scanline, w, 1).convertToFormat(QImage::Format_Grayscale8);
+ memcpy(row, rowImg.constScanLine(0), w);
+ }
+ break;
case QImage::Format_RGB888:
memcpy(row, image.constScanLine(cinfo.next_scanline), w * 3);
break;
@@ -646,6 +670,17 @@ static bool do_write_jpeg_image(struct jpeg_compress_struct &cinfo,
}
}
break;
+ case QImage::Format_CMYK8888: {
+ auto *cmykIn = reinterpret_cast<const quint32 *>(image.constScanLine(cinfo.next_scanline));
+ auto *cmykOut = reinterpret_cast<quint32 *>(row);
+ if (invertCMYK) {
+ for (int i = 0; i < w; ++i)
+ cmykOut[i] = 0xffffffffu - cmykIn[i];
+ } else {
+ memcpy(cmykOut, cmykIn, w * 4);
+ }
+ break;
+ }
default:
{
// (Testing shows that this way is actually faster than converting to RGB888 + memcpy)
@@ -681,7 +716,8 @@ static bool write_jpeg_image(const QImage &image,
int sourceQuality,
const QString &description,
bool optimize,
- bool progressive)
+ bool progressive,
+ bool invertCMYK)
{
// protect these objects from the setjmp/longjmp pair inside
// do_write_jpeg_image (by making them non-local).
@@ -692,7 +728,7 @@ static bool write_jpeg_image(const QImage &image,
const bool success = do_write_jpeg_image(cinfo, row_pointer,
image, device,
sourceQuality, description,
- optimize, progressive);
+ optimize, progressive, invertCMYK);
delete [] row_pointer[0];
return success;
@@ -737,6 +773,21 @@ public:
QStringList readTexts;
QByteArray iccProfile;
+ // Photoshop historically invertes the quantities in CMYK JPEG files:
+ // 0 means 100% ink, 255 means no ink. Every reader does the same,
+ // for compatibility reasons.
+ // Use such an interpretation by default, but also offer the alternative
+ // of not inverting the channels.
+ // This is just a "fancy" API; it could be reduced to a boolean setting
+ // for CMYK files.
+ enum class SubType {
+ Automatic,
+ Inverted_CMYK,
+ CMYK,
+ NSubTypes
+ };
+ SubType subType = SubType::Automatic;
+
struct jpeg_decompress_struct info;
struct my_jpeg_source_mgr * iod_src;
struct my_error_mgr err;
@@ -751,6 +802,14 @@ public:
QJpegHandler *q;
};
+static const char SupportedJPEGSubtypes[][14] = {
+ "Automatic",
+ "Inverted_CMYK",
+ "CMYK"
+};
+
+static_assert(std::size(SupportedJPEGSubtypes) == size_t(QJpegHandlerPrivate::SubType::NSubTypes));
+
static bool readExifHeader(QDataStream &stream)
{
char prefix[6];
@@ -967,7 +1026,8 @@ bool QJpegHandlerPrivate::read(QImage *image)
if (state == ReadHeader)
{
- bool success = read_jpeg_image(image, scaledSize, scaledClipRect, clipRect, quality, rgb888ToRgb32ConverterPtr, &info, &err);
+ const bool invertCMYK = subType != QJpegHandlerPrivate::SubType::CMYK;
+ bool success = read_jpeg_image(image, scaledSize, scaledClipRect, clipRect, quality, rgb888ToRgb32ConverterPtr, &info, &err, invertCMYK);
if (success) {
for (int i = 0; i < readTexts.size()-1; i+=2)
image->setText(readTexts.at(i), readTexts.at(i+1));
@@ -1053,13 +1113,14 @@ extern void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orie
bool QJpegHandler::write(const QImage &image)
{
+ const bool invertCMYK = d->subType != QJpegHandlerPrivate::SubType::CMYK;
if (d->transformation != QImageIOHandler::TransformationNone) {
// We don't support writing EXIF headers so apply the transform to the data.
QImage img = image;
qt_imageTransform(img, d->transformation);
- return write_jpeg_image(img, device(), d->quality, d->description, d->optimize, d->progressive);
+ return write_jpeg_image(img, device(), d->quality, d->description, d->optimize, d->progressive, invertCMYK);
}
- return write_jpeg_image(image, device(), d->quality, d->description, d->optimize, d->progressive);
+ return write_jpeg_image(image, device(), d->quality, d->description, d->optimize, d->progressive, invertCMYK);
}
bool QJpegHandler::supportsOption(ImageOption option) const
@@ -1070,6 +1131,8 @@ bool QJpegHandler::supportsOption(ImageOption option) const
|| option == ClipRect
|| option == Description
|| option == Size
+ || option == SubType
+ || option == SupportedSubTypes
|| option == ImageFormat
|| option == OptimizedWrite
|| option == ProgressiveScanWrite
@@ -1093,6 +1156,13 @@ QVariant QJpegHandler::option(ImageOption option) const
case Size:
d->readJpegHeader(device());
return d->size;
+ case SubType:
+ return QByteArray(SupportedJPEGSubtypes[int(d->subType)]);
+ case SupportedSubTypes: {
+ QByteArrayList list(std::begin(SupportedJPEGSubtypes),
+ std::end(SupportedJPEGSubtypes));
+ return QVariant::fromValue(list);
+ }
case ImageFormat:
d->readJpegHeader(device());
return d->format;
@@ -1128,6 +1198,16 @@ void QJpegHandler::setOption(ImageOption option, const QVariant &value)
case Description:
d->description = value.toString();
break;
+ case SubType: {
+ const QByteArray subType = value.toByteArray();
+ for (size_t i = 0; i < std::size(SupportedJPEGSubtypes); ++i) {
+ if (subType == SupportedJPEGSubtypes[i]) {
+ d->subType = QJpegHandlerPrivate::SubType(i);
+ break;
+ }
+ }
+ break;
+ }
case OptimizedWrite:
d->optimize = value.toBool();
break;
@@ -1138,6 +1218,7 @@ void QJpegHandler::setOption(ImageOption option, const QVariant &value)
int transformation = value.toInt();
if (transformation > 0 && transformation < 8)
d->transformation = QImageIOHandler::Transformations(transformation);
+ break;
}
default:
break;