Compare commits

..

1 Commits

Author SHA1 Message Date
Albert Astals Cid
8658355701 Fix crash on malformed files
oss-fuzz/449485443
2025-10-05 21:25:48 +00:00
34 changed files with 193 additions and 216 deletions

View File

@@ -1,11 +1,11 @@
cmake_minimum_required(VERSION 3.16)
set(KF_VERSION "6.20.0") # handled by release scripts
set(KF_DEP_VERSION "6.20.0") # handled by release scripts
set(KF_DEP_VERSION "6.19.0") # handled by release scripts
project(KImageFormats VERSION ${KF_VERSION})
include(FeatureSummary)
find_package(ECM 6.20.0 NO_MODULE)
find_package(ECM 6.19.0 NO_MODULE)
set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://commits.kde.org/extra-cmake-modules")
feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES)
@@ -21,7 +21,7 @@ include(ECMDeprecationSettings)
include(CheckIncludeFiles)
include(FindPkgConfig)
set(REQUIRED_QT_VERSION 6.8.0)
set(REQUIRED_QT_VERSION 6.7.0)
find_package(Qt6Gui ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE)
find_package(KF6Archive ${KF_DEP_VERSION})
@@ -100,7 +100,7 @@ add_feature_info(LibJXR LibJXR_FOUND "required for the QImage plugin for JPEG XR
ecm_set_disabled_deprecation_versions(
QT 6.10.0
KF 6.19.0
KF 6.18.0
)
add_subdirectory(src)

View File

@@ -38,7 +38,7 @@ git clone --depth 1 -b v1.2.1 https://github.com/AOMediaCodec/libavif.git
git clone --depth 1 https://github.com/strukturag/libde265.git
git clone --depth 1 -b v2.5.3 https://github.com/uclouvain/openjpeg.git
git clone --depth 1 https://github.com/strukturag/libheif.git
git clone --depth=1 --recursive --shallow-submodules https://github.com/libjxl/libjxl.git
git clone --depth=1 --branch v0.11.x --recursive --shallow-submodules https://github.com/libjxl/libjxl.git
git clone --depth 1 https://github.com/LibRaw/LibRaw
git clone --depth 1 https://github.com/mircomir/jxrlib.git
git clone --depth 1 -b v2.6.0 https://github.com/cisco/openh264.git

View File

@@ -1,6 +0,0 @@
[
{
"fileName" : "fruktpilot.png",
"fuzziness" : 1
}
]

View File

@@ -1,6 +0,0 @@
[
{
"fileName" : "fruktpilot16_icc.png",
"fuzziness" : 1
}
]

View File

@@ -1,6 +0,0 @@
[
{
"fileName" : "fruktpilot32_icc.png",
"fuzziness" : 1
}
]

View File

@@ -1,6 +0,0 @@
[
{
"fileName" : "fruktpilot32fplin_icc.png",
"fuzziness" : 1
}
]

View File

@@ -1,6 +0,0 @@
[
{
"fileName" : "fruktpilot_icc.png",
"fuzziness" : 1
}
]

View File

@@ -138,11 +138,13 @@ bool TemplateImage::checkOptionaInfo(const QImage& image, QString& error) const
return false;
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
auto clmName = QString(QMetaEnum::fromType<QColorSpace::ColorModel>().valueToKey(quint64(cs.colorModel())));
if (clmName != clm) {
error = QStringLiteral("ColorSpace ColorModel mismatch (current: %1, expected: %2)!").arg(clmName, clm);
return false;
}
#endif
}
// Test resolution

View File

@@ -319,9 +319,11 @@ QImage formatSourceImage(const QImage::Format &format)
image = QImage(QStringLiteral("%1/rgba16.png").arg(folder));
break;
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
case QImage::Format_CMYK8888:
image = QImage(QStringLiteral("%1/cmyk8.tif").arg(folder));
break;
#endif
default:
break;

View File

@@ -293,7 +293,9 @@ bool QAVIFHandler::decode_one_frame()
colorspace = QColorSpace::fromIccProfile(icc_data);
if (!colorspace.isValid()) {
qCWarning(LOG_AVIFPLUGIN, "AVIF image has Qt-unsupported or invalid ICC profile!");
} else {
}
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
else {
if (colorspace.colorModel() == QColorSpace::ColorModel::Cmyk) {
qCWarning(LOG_AVIFPLUGIN, "CMYK ICC profile is not extected for AVIF, discarding the ICCprofile!");
colorspace = QColorSpace();
@@ -323,6 +325,7 @@ bool QAVIFHandler::decode_one_frame()
}
}
}
#endif
} else {
float prim[8] = {0.64f, 0.33f, 0.3f, 0.6f, 0.15f, 0.06f, 0.3127f, 0.329f};
// outPrimaries: rX, rY, gX, gY, bX, bY, wX, wY
@@ -357,12 +360,14 @@ bool QAVIFHandler::decode_one_frame()
case 13:
q_trc = QColorSpace::TransferFunction::SRgb;
break;
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
case 16: /* AVIF_TRANSFER_CHARACTERISTICS_PQ */
q_trc = QColorSpace::TransferFunction::St2084;
break;
case 18: /* AVIF_TRANSFER_CHARACTERISTICS_HLG */
q_trc = QColorSpace::TransferFunction::Hlg;
break;
#endif
default:
qCWarning(LOG_AVIFPLUGIN, "CICP colorPrimaries: %d, transferCharacteristics: %d\nThe colorspace is unsupported by this plug-in yet.",
m_decoder->image->colorPrimaries,
@@ -372,9 +377,11 @@ bool QAVIFHandler::decode_one_frame()
}
if (q_trc != QColorSpace::TransferFunction::Custom) { // we create new colorspace using Qt
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
if (loadgray) {
colorspace = QColorSpace(whitePoint, q_trc, q_trc_gamma);
} else {
#endif
switch (m_decoder->image->colorPrimaries) {
/* AVIF_COLOR_PRIMARIES_BT709 */
case 0:
@@ -390,7 +397,9 @@ bool QAVIFHandler::decode_one_frame()
colorspace = QColorSpace(whitePoint, redPoint, greenPoint, bluePoint, q_trc, q_trc_gamma);
break;
}
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
}
#endif
}
if (!colorspace.isValid()) {
@@ -738,12 +747,14 @@ bool QAVIFHandler::write(const QImage &image)
/* AVIF_TRANSFER_CHARACTERISTICS_SRGB */
avif->transferCharacteristics = (avifTransferCharacteristics)13;
break;
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
case QColorSpace::TransferFunction::St2084:
avif->transferCharacteristics = (avifTransferCharacteristics)16;
break;
case QColorSpace::TransferFunction::Hlg:
avif->transferCharacteristics = (avifTransferCharacteristics)18;
break;
#endif
default:
/* AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED */
break;
@@ -788,6 +799,7 @@ bool QAVIFHandler::write(const QImage &image)
}
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
QImage tmpcolorimage;
auto cs = image.colorSpace();
if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Cmyk && image.format() == QImage::Format_CMYK8888) {
@@ -802,6 +814,9 @@ bool QAVIFHandler::write(const QImage &image)
} else {
tmpcolorimage = image.convertToFormat(tmpformat);
}
#else
QImage tmpcolorimage = image.convertToFormat(tmpformat);
#endif
avifPixelFormat pixel_format = AVIF_PIXEL_FORMAT_YUV420;
if (m_quality >= KIMG_AVIF_QUALITY_HIGH) {
@@ -861,12 +876,14 @@ bool QAVIFHandler::write(const QImage &image)
/* AVIF_TRANSFER_CHARACTERISTICS_SRGB */
transfer_to_save = (avifTransferCharacteristics)13;
break;
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
case QColorSpace::TransferFunction::St2084:
transfer_to_save = (avifTransferCharacteristics)16;
break;
case QColorSpace::TransferFunction::Hlg:
transfer_to_save = (avifTransferCharacteristics)18;
break;
#endif
default:
/* AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED */
transfer_to_save = (avifTransferCharacteristics)2;
@@ -902,12 +919,14 @@ bool QAVIFHandler::write(const QImage &image)
case 5: // AVIF_TRANSFER_CHARACTERISTICS_BT470BG
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, 2.8f));
break;
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
case 16:
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, QColorSpace::TransferFunction::St2084));
break;
case 18:
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, QColorSpace::TransferFunction::Hlg));
break;
#endif
default: // AVIF_TRANSFER_CHARACTERISTICS_SRGB + any other
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, QColorSpace::TransferFunction::SRgb));
transfer_to_save = (avifTransferCharacteristics)13;

View File

@@ -235,11 +235,6 @@ void IFFChunk::setRecursionCounter(qint32 cnt)
_recursionCnt = cnt;
}
quint32 IFFChunk::dataBytes() const
{
return std::min(bytes(), quint32(data().size()));
}
IFFChunk::ChunkList IFFChunk::innerFromDevice(QIODevice *d, bool *ok, IFFChunk *parent)
{
auto tmp = false;
@@ -385,7 +380,7 @@ BMHDChunk::BMHDChunk() : IFFChunk()
bool BMHDChunk::isValid() const
{
if (dataBytes() < 20) {
if (bytes() < 20) {
return false;
}
return chunkId() == BMHDChunk::defaultChunkId();
@@ -526,7 +521,7 @@ qint32 CMAPChunk::count() const
if (!isValid()) {
return 0;
}
return dataBytes() / 3;
return bytes() / 3;
}
QList<QRgb> CMAPChunk::palette(bool halfbride) const
@@ -550,8 +545,12 @@ bool CMAPChunk::innerReadStructure(QIODevice *d)
QList<QRgb> CMAPChunk::innerPalette() const
{
QList<QRgb> l;
auto &&d = data();
for (qint32 i = 0, n = count(); i < n; ++i) {
const QByteArray &d = data();
const qint32 n = count();
if (n * 3 > d.size()) {
return {};
}
for (qint32 i = 0; i < n; ++i) {
auto i3 = i * 3;
l << qRgb(d.at(i3), d.at(i3 + 1), d.at(i3 + 2));
}
@@ -583,7 +582,7 @@ qint32 CMYKChunk::count() const
if (!isValid()) {
return 0;
}
return dataBytes() / 4;
return bytes() / 4;
}
QList<QRgb> CMYKChunk::innerPalette() const
@@ -617,7 +616,7 @@ CAMGChunk::CAMGChunk() : IFFChunk()
bool CAMGChunk::isValid() const
{
if (dataBytes() != 4) {
if (bytes() != 4) {
return false;
}
return chunkId() == CAMGChunk::defaultChunkId();
@@ -659,7 +658,7 @@ bool DPIChunk::isValid() const
quint16 DPIChunk::dpiX() const
{
if (dataBytes() < 4) {
if (bytes() < 4) {
return 0;
}
return ui16(data().at(1), data().at(0));
@@ -667,7 +666,7 @@ quint16 DPIChunk::dpiX() const
quint16 DPIChunk::dpiY() const
{
if (dataBytes() < 4) {
if (bytes() < 4) {
return 0;
}
return ui16(data().at(3), data().at(2));
@@ -711,7 +710,7 @@ bool XBMIChunk::isValid() const
quint16 XBMIChunk::dpiX() const
{
if (dataBytes() < 6) {
if (bytes() < 6) {
return 0;
}
return ui16(data().at(3), data().at(2));
@@ -719,7 +718,7 @@ quint16 XBMIChunk::dpiX() const
quint16 XBMIChunk::dpiY() const
{
if (dataBytes() < 6) {
if (bytes() < 6) {
return 0;
}
return ui16(data().at(5), data().at(4));
@@ -727,7 +726,7 @@ quint16 XBMIChunk::dpiY() const
XBMIChunk::PictureType XBMIChunk::pictureType() const
{
if (dataBytes() < 6) {
if (bytes() < 6) {
return PictureType(-1);
}
return PictureType(i16(data().at(1), data().at(0)));
@@ -1019,7 +1018,7 @@ QByteArray BODYChunk::deinterleave(const QByteArray &planes, qint32 y, const BMH
auto pal = cmap->palette();
if (ipal) {
auto tmp = ipal->palette(y);
if (!tmp.isEmpty())
if (tmp.size() == pal.size())
pal = tmp;
}
// HAM 6: 2 control bits+4 bits of data, 16-color palette
@@ -1603,7 +1602,7 @@ TBHDChunk::TBHDChunk()
bool TBHDChunk::isValid() const
{
if (dataBytes() != 24 && dataBytes() != 32) {
if (bytes() != 24 && bytes() != 32) {
return false;
}
return chunkId() == TBHDChunk::defaultChunkId();
@@ -1637,7 +1636,7 @@ QSize TBHDChunk::size() const
qint32 TBHDChunk::left() const
{
if (dataBytes() != 32) {
if (bytes() != 32) {
return 0;
}
return i32(data().at(27), data().at(26), data().at(25), data().at(24));
@@ -1645,7 +1644,7 @@ qint32 TBHDChunk::left() const
qint32 TBHDChunk::top() const
{
if (dataBytes() != 32) {
if (bytes() != 32) {
return 0;
}
return i32(data().at(31), data().at(30), data().at(29), data().at(28));
@@ -2419,12 +2418,10 @@ QList<QRgb> BEAMChunk::palette(qint32 y) const
for (auto c = 0; c < col; ++c) {
// 2 bytes per color (0x0R 0xGB)
auto idx = bpp * y + c * 2;
if (idx + 1 < dt.size()) {
auto r = quint8(dt[idx] & 0x0F);
auto g = quint8(dt[idx + 1] & 0xF0);
auto b = quint8(dt[idx + 1] & 0x0F);
pal << qRgb(r | (r << 4), (g >> 4) | g, b | (b << 4));
}
auto r = quint8(dt[idx] & 0x0F);
auto g = quint8(dt[idx + 1] & 0xF0);
auto b = quint8(dt[idx + 1] & 0x0F);
pal << qRgb(r | (r << 4), (g >> 4) | g, b | (b << 4));
}
return pal;
}
@@ -2473,7 +2470,7 @@ SHAMChunk::SHAMChunk()
bool SHAMChunk::isValid() const
{
if (dataBytes() < 2) {
if (bytes() < 2) {
return false;
}
auto &&dt = data();
@@ -2512,12 +2509,10 @@ QList<QRgb> SHAMChunk::palette(qint32 y) const
for (auto c = 0, col = bpp / 2, idx0 = y / div * bpp + 2; c < col; ++c) {
// 2 bytes per color (0x0R 0xGB)
auto idx = idx0 + c * 2;
if (idx + 1 < dt.size()) {
auto r = quint8(dt[idx] & 0x0F);
auto g = quint8(dt[idx + 1] & 0xF0);
auto b = quint8(dt[idx + 1] & 0x0F);
pal << qRgb(r | (r << 4), (g >> 4) | g, b | (b << 4));
}
auto r = quint8(dt[idx] & 0x0F);
auto g = quint8(dt[idx + 1] & 0xF0);
auto b = quint8(dt[idx + 1] & 0x0F);
pal << qRgb(r | (r << 4), (g >> 4) | g, b | (b << 4));
}
return pal;
}
@@ -2574,18 +2569,16 @@ QList<QRgb> RASTChunk::palette(qint32 y) const
QList<QRgb> pal;
for (auto c = 0; c < col; ++c) {
auto idx = bpp * y + 2 + c * 2;
if (idx + 1 < dt.size()) {
// The Atari ST uses 3 bits per color (512 colors) while the Atari STE
// uses 4 bits per color (4096 colors). This strange encoding with the
// least significant bit set as MSB is, I believe, to ensure hardware
// compatibility between the two machines.
#define H1L(a) ((quint8(a) & 0x7) << 1) | ((quint8(a) >> 3) & 1)
auto r = H1L(dt[idx]);
auto g = H1L(dt[idx + 1] >> 4);
auto b = H1L(dt[idx + 1]);
#undef H1L
pal << qRgb(r | (r << 4), (g << 4) | g, b | (b << 4));
}
// The Atari ST uses 3 bits per color (512 colors) while the Atari STE
// uses 4 bits per color (4096 colors). This strange encoding with the
// least significant bit set as MSB is, I believe, to ensure hardware
// compatibility between the two machines.
#define H1L(a) ((quint8(a) & 0x7) << 1) | ((quint8(a) >> 3) & 1)
auto r = H1L(dt[idx]);
auto g = H1L(dt[idx + 1] >> 4);
auto b = H1L(dt[idx + 1]);
#undef H1L
pal << qRgb(r | (r << 4), (g << 4) | g, b | (b << 4));
}
return pal;
}
@@ -2693,7 +2686,7 @@ bool PCHGChunk::hasAlpha() const
bool PCHGChunk::isValid() const
{
if (dataBytes() < 20) {
if (bytes() < 20) {
return false;
}
return chunkId() == PCHGChunk::defaultChunkId();
@@ -2795,6 +2788,10 @@ static QByteArray pchgFastDecomp(const QByteArray& input, int treeSize, int orig
return {};
}
QByteArray out;
out.resize(originalSize);
char* outPtr = out.data();
// Emulate a3 pointer to words:
// a2 points to the *last word* => word index (0..treeWords-1)
auto resetA3 = [&]() {
@@ -2819,9 +2816,10 @@ static QByteArray pchgFastDecomp(const QByteArray& input, int treeSize, int orig
return true;
};
int produced = 0;
// Main decode loop: produce exactly originalSize bytes
QByteArray out;
while (out.size() < qsizetype(originalSize)) {
while (produced < originalSize) {
if (bits == 0) {
if (!refill()) {
// Not enough bits to complete output
@@ -2857,7 +2855,7 @@ static QByteArray pchgFastDecomp(const QByteArray& input, int treeSize, int orig
a3_word = next;
} else {
// Leaf: emit low 8 bits, reset a3
out.append(static_cast<char>(w & 0xFF));
outPtr[produced++] = static_cast<char>(w & 0xFF);
a3_word = resetA3();
}
} else {
@@ -2877,7 +2875,7 @@ static QByteArray pchgFastDecomp(const QByteArray& input, int treeSize, int orig
// Non-negative: check bit #8; if set -> leaf
if ((w & 0x0100) != 0) {
out.append(static_cast<char>(w & 0xFF));
outPtr[produced++] = static_cast<char>(w & 0xFF);
a3_word = resetA3();
} else {
// Not a leaf: continue scanning

View File

@@ -350,12 +350,6 @@ protected:
static ChunkList innerFromDevice(QIODevice *d, bool *ok, IFFChunk *parent = nullptr);
/*!
* \brief dataBytes
* \return Maximum usable cache data size.
*/
quint32 dataBytes() const;
private:
char _chunkId[4];

View File

@@ -2120,8 +2120,10 @@ bool writeL8(const QImage &outImage, QDataStream &s)
}
ScanLineConverter slc(QImage::Format_Grayscale8);
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
if(outImage.colorSpace().isValid())
slc.setTargetColorSpace(QColorSpace(QPointF(0.3127, 0.3291), QColorSpace::TransferFunction::SRgb));
#endif
for (int y = 0, h = outImage.height(); y < h; ++y) {
const quint8 *scanLine = reinterpret_cast<const quint8*>(slc.convertedScanLine(outImage, y));

View File

@@ -608,13 +608,13 @@ bool EXRHandler::write(const QImage &image)
pixels.resizeErase(EXR_LINES_PER_BLOCK, width);
// convert the image and write into the stream
auto convFormat = image.hasAlphaChannel() ? QImage::Format_RGBA32FPx4 : QImage::Format_RGBX32FPx4;
auto convFormat = image.hasAlphaChannel() ? QImage::Format_RGBA16FPx4 : QImage::Format_RGBX16FPx4;
ScanLineConverter slc(convFormat);
slc.setDefaultSourceColorSpace(QColorSpace(QColorSpace::SRgb));
slc.setTargetColorSpace(QColorSpace(QColorSpace::SRgbLinear));
for (int y = 0, n = 0; y < height; y += n) {
for (n = 0; n < std::min(EXR_LINES_PER_BLOCK, height - y); ++n) {
auto scanLine = reinterpret_cast<const float *>(slc.convertedScanLine(image, y + n));
auto scanLine = reinterpret_cast<const qfloat16 *>(slc.convertedScanLine(image, y + n));
if (scanLine == nullptr) {
return false;
}

View File

@@ -189,6 +189,7 @@ bool HEIFHandler::write_helper(const QImage &image)
}
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
QImage tmpimage;
auto cs = image.colorSpace();
if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Cmyk && image.format() == QImage::Format_CMYK8888) {
@@ -204,6 +205,9 @@ bool HEIFHandler::write_helper(const QImage &image)
} else {
tmpimage = image.convertToFormat(tmpformat);
}
#else
QImage tmpimage = image.convertToFormat(tmpformat);
#endif
struct heif_context *context = heif_context_alloc();
struct heif_error err;
@@ -864,7 +868,9 @@ bool HEIFHandler::ensureDecoder()
QColorSpace colorspace = QColorSpace::fromIccProfile(ba);
if (!colorspace.isValid()) {
qCWarning(LOG_HEIFPLUGIN) << "HEIC image has Qt-unsupported or invalid ICC profile!";
} else if (colorspace.colorModel() == QColorSpace::ColorModel::Cmyk) {
}
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
else if (colorspace.colorModel() == QColorSpace::ColorModel::Cmyk) {
qCWarning(LOG_HEIFPLUGIN) << "CMYK ICC profile is not expected for HEIF, discarding the ICCprofile!";
colorspace = QColorSpace();
} else if (colorspace.colorModel() == QColorSpace::ColorModel::Gray) {
@@ -891,6 +897,7 @@ bool HEIFHandler::ensureDecoder()
m_current_image.convertTo(bit_depth > 8 ? QImage::Format_Grayscale16 : QImage::Format_Grayscale8);
}
}
#endif
m_current_image.setColorSpace(colorspace);
}
} else {
@@ -927,12 +934,14 @@ bool HEIFHandler::ensureDecoder()
case 13:
q_trc = QColorSpace::TransferFunction::SRgb;
break;
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
case 16:
q_trc = QColorSpace::TransferFunction::St2084;
break;
case 18:
q_trc = QColorSpace::TransferFunction::Hlg;
break;
#endif
default:
qCWarning(LOG_HEIFPLUGIN) << "CICP color_primaries: %d, transfer_characteristics: %d\nThe colorspace is unsupported by this plug-in yet."
<< nclx->color_primaries

View File

@@ -73,7 +73,7 @@ static void info_callback(const char *msg, void *client_data)
static OPJ_SIZE_T jp2_read(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data)
{
auto dev = (QIODevice*)p_user_data;
if (dev == nullptr || dev->atEnd()) {
if (dev == nullptr) {
return OPJ_SIZE_T(-1);
}
return OPJ_SIZE_T(dev->read((char*)p_buffer, (qint64)p_nb_bytes));
@@ -391,6 +391,7 @@ public:
prec = 0;
}
auto jp2cs = m_jp2_image->color_space;
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
if (jp2cs == OPJ_CLRSPC_UNKNOWN || jp2cs == OPJ_CLRSPC_UNSPECIFIED) {
auto cs = colorSpace();
if (cs.colorModel() == QColorSpace::ColorModel::Cmyk)
@@ -400,6 +401,7 @@ public:
else if (cs.colorModel() == QColorSpace::ColorModel::Gray)
jp2cs = OPJ_CLRSPC_GRAY;
}
#endif
if (jp2cs == OPJ_CLRSPC_UNKNOWN || jp2cs == OPJ_CLRSPC_UNSPECIFIED) {
if (m_jp2_image->numcomps == 1)
jp2cs = OPJ_CLRSPC_GRAY;
@@ -429,8 +431,10 @@ public:
}
} else if (jp2cs == OPJ_CLRSPC_CMYK) {
if (m_jp2_image->numcomps == 4) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
if (prec == 8 || prec == 16)
fmt = QImage::Format_CMYK8888;
#endif
}
}
}
@@ -575,6 +579,7 @@ public:
prec = 16;
convFormat = QImage::Format_RGBA64;
break;
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
case QImage::Format_CMYK8888: // requires OpenJPEG 2.5.3+
if (opjVersion() >= QT_VERSION_CHECK(2, 5, 3)) {
ncomp = 4;
@@ -583,6 +588,7 @@ public:
} else {
Q_FALLTHROUGH();
}
#endif
default:
if (image.depth() > 32) {
qCWarning(LOG_JP2PLUGIN) << "The image is saved losing precision!";

View File

@@ -26,9 +26,13 @@ Q_LOGGING_CATEGORY(LOG_JXLPLUGIN, "kf.imageformats.plugins.jxl", QtDebugMsg)
Q_LOGGING_CATEGORY(LOG_JXLPLUGIN, "kf.imageformats.plugins.jxl", QtWarningMsg)
#endif
// Avoid rotation on buggy Qts (see also https://bugreports.qt.io/browse/QTBUG-126575)
#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 3)
#ifndef JXL_QT_AUTOTRANSFORM
#define JXL_QT_AUTOTRANSFORM
#endif
#endif
#ifndef JXL_HDR_PRESERVATION_DISABLED
// Define JXL_HDR_PRESERVATION_DISABLED to disable HDR preservation
@@ -410,6 +414,7 @@ bool QJpegXLHandler::countALLFrames()
m_framedelays[0] = 0;
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
// CMYK detection
if ((m_basicinfo.uses_original_profile == JXL_TRUE) && (m_basicinfo.num_color_channels == 3) && (m_colorspace.isValid())) {
bool alpha_found = false;
@@ -466,6 +471,7 @@ bool QJpegXLHandler::countALLFrames()
qCWarning(LOG_JXLPLUGIN, "JXL has CMYK colorspace but BLACK channel was not found!");
}
}
#endif
#ifndef JXL_DECODE_BOXES_DISABLED
if (!decodeContainer()) {
@@ -492,6 +498,7 @@ bool QJpegXLHandler::decode_one_frame()
}
if (m_isCMYK) { // CMYK decoding
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
uchar *pixels_cmy = nullptr;
uchar *pixels_black = nullptr;
@@ -732,6 +739,11 @@ bool QJpegXLHandler::decode_one_frame()
free(pixels_cmy);
pixels_cmy = nullptr;
}
#else
// CMYK not supported in older Qt
m_parseState = ParseJpegXLError;
return false;
#endif
} else { // RGB or GRAY
m_current_image = imageAlloc(m_basicinfo.xsize, m_basicinfo.ysize, m_input_image_format);
if (m_current_image.isNull()) {
@@ -909,9 +921,11 @@ bool QJpegXLHandler::write(const QImage &image)
}
bool save_cmyk = false;
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
if (image.format() == QImage::Format_CMYK8888 && image.colorSpace().isValid() && image.colorSpace().colorModel() == QColorSpace::ColorModel::Cmyk) {
save_cmyk = true;
}
#endif
JxlEncoderStatus status;
JxlPixelFormat pixel_format;
@@ -922,6 +936,7 @@ bool QJpegXLHandler::write(const QImage &image)
auto xmp_data = image.text(QStringLiteral(META_KEY_XMP_ADOBE)).toUtf8();
if (save_cmyk) { // CMYK is always lossless
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
output_info.uses_original_profile = JXL_TRUE;
output_info.xsize = image.width();
output_info.ysize = image.height();
@@ -1094,6 +1109,13 @@ bool QJpegXLHandler::write(const QImage &image)
JxlEncoderDestroy(encoder);
return false;
}
#else
if (runner) {
JxlThreadParallelRunnerDestroy(runner);
}
JxlEncoderDestroy(encoder);
return false;
#endif
} else { // RGB or GRAY saving
int save_depth = 8; // 8 / 16 / 32
bool save_fp = false;
@@ -1132,7 +1154,9 @@ bool QJpegXLHandler::write(const QImage &image)
case QImage::Format_RGBX8888:
case QImage::Format_RGBA8888:
case QImage::Format_RGBA8888_Premultiplied:
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
case QImage::Format_CMYK8888:
#endif
save_depth = 8;
break;
case QImage::Format_Grayscale16:
@@ -1227,6 +1251,7 @@ bool QJpegXLHandler::write(const QImage &image)
}
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
QImage tmpimage;
if (image.colorSpace().isValid()) {
if (is_gray && image.colorSpace().colorModel() != QColorSpace::ColorModel::Gray) {
@@ -1279,6 +1304,9 @@ bool QJpegXLHandler::write(const QImage &image)
} else { // no ColorSpace or invalid
tmpimage = image.convertToFormat(tmpformat);
}
#else
QImage tmpimage = image.convertToFormat(tmpformat);
#endif
output_info.xsize = tmpimage.width();
output_info.ysize = tmpimage.height();
@@ -1304,7 +1332,10 @@ bool QJpegXLHandler::write(const QImage &image)
output_info.uses_original_profile = JXL_FALSE;
if (tmpimage.colorSpace().isValid()) {
const QPointF whiteP = image.colorSpace().whitePoint();
QPointF whiteP(0.3127f, 0.329f);
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
whiteP = image.colorSpace().whitePoint();
#endif
switch (tmpimage.colorSpace().primaries()) {
case QColorSpace::Primaries::SRgb:
@@ -1333,6 +1364,9 @@ bool QJpegXLHandler::write(const QImage &image)
break;
case QColorSpace::Primaries::ProPhotoRgb:
color_profile.white_point = JXL_WHITE_POINT_CUSTOM;
#if QT_VERSION < QT_VERSION_CHECK(6, 8, 0)
whiteP = QPointF(0.3457f, 0.3585f);
#endif
color_profile.white_point_xy[0] = whiteP.x();
color_profile.white_point_xy[1] = whiteP.y();
color_profile.primaries = JXL_PRIMARIES_CUSTOM;
@@ -1343,6 +1377,7 @@ bool QJpegXLHandler::write(const QImage &image)
color_profile.primaries_blue_xy[0] = 0.0366;
color_profile.primaries_blue_xy[1] = 0.0001;
break;
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
case QColorSpace::Primaries::Bt2020:
color_profile.white_point = JXL_WHITE_POINT_D65;
color_profile.primaries = JXL_PRIMARIES_2100;
@@ -1353,6 +1388,7 @@ bool QJpegXLHandler::write(const QImage &image)
color_profile.primaries_blue_xy[0] = 0.131;
color_profile.primaries_blue_xy[1] = 0.046;
break;
#endif
default:
if (is_gray && !whiteP.isNull()) {
color_profile.white_point = JXL_WHITE_POINT_CUSTOM;

View File

@@ -579,7 +579,9 @@ public:
// IMPORTANT: these values must be in exactMatchingFormat()
// clang-format off
auto valid = QSet<QImage::Format>()
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
<< QImage::Format_CMYK8888
#endif
#ifndef JXR_DENY_FLOAT_IMAGE
<< QImage::Format_RGBA16FPx4
<< QImage::Format_RGBX16FPx4
@@ -669,8 +671,10 @@ public:
wmiSCP->bVerbose = FALSE;
if (fmt == QImage::Format_Grayscale8 || fmt == QImage::Format_Grayscale16 || fmt == QImage::Format_Mono)
wmiSCP->cfColorFormat = Y_ONLY;
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
else if (fmt == QImage::Format_CMYK8888)
wmiSCP->cfColorFormat = CMYK;
#endif
else
wmiSCP->cfColorFormat = YUV_444;
wmiSCP->bdBitDepth = BD_LONG;
@@ -808,8 +812,10 @@ private:
<< std::pair<QImage::Format, PKPixelFormatGUID>(QImage::Format_RGBA32FPx4_Premultiplied, GUID_PKPixelFormat128bppPRGBAFloat)
<< std::pair<QImage::Format, PKPixelFormatGUID>(QImage::Format_RGBX32FPx4, GUID_PKPixelFormat128bppRGBFloat)
#endif // JXR_DENY_FLOAT_IMAGE
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
<< std::pair<QImage::Format, PKPixelFormatGUID>(QImage::Format_CMYK8888, GUID_PKPixelFormat32bppCMYK)
<< std::pair<QImage::Format, PKPixelFormatGUID>(QImage::Format_CMYK8888, GUID_PKPixelFormat32bppCMYKDIRECT)
#endif
<< std::pair<QImage::Format, PKPixelFormatGUID>(QImage::Format_Mono, GUID_PKPixelFormatBlackWhite)
<< std::pair<QImage::Format, PKPixelFormatGUID>(QImage::Format_Grayscale8, GUID_PKPixelFormat8bppGray)
<< std::pair<QImage::Format, PKPixelFormatGUID>(QImage::Format_Grayscale16, GUID_PKPixelFormat16bppGray)

View File

@@ -781,11 +781,13 @@ static bool writeImage24(const QImage &image, QDataStream &s, PCXHEADER &header)
auto tcs = QColorSpace();
auto tfmt = image.format();
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
auto cs = image.colorSpace();
if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Cmyk && tfmt == QImage::Format_CMYK8888) {
tcs = QColorSpace(QColorSpace::SRgb);
tfmt = QImage::Format_RGB32;
}
#endif
if (tfmt != QImage::Format_ARGB32 && tfmt != QImage::Format_RGB32) {
tfmt = hasAlpha ? QImage::Format_ARGB32 : QImage::Format_RGB32;
}

View File

@@ -275,11 +275,13 @@ bool SoftimagePICHandler::write(const QImage &image)
bool alpha = image.hasAlphaChannel();
auto tcs = QColorSpace();
auto tfmt = image.format();
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
auto cs = image.colorSpace();
if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Cmyk && tfmt == QImage::Format_CMYK8888) {
tcs = QColorSpace(QColorSpace::SRgb);
tfmt = QImage::Format_RGB32;
}
#endif
if (tfmt != QImage::Format_ARGB32 && tfmt != QImage::Format_RGB32) {
tfmt = alpha ? QImage::Format_ARGB32 : QImage::Format_RGB32;
}

View File

@@ -91,7 +91,7 @@ typedef quint8 uchar;
namespace // Private.
{
#if defined(PSD_NATIVE_CMYK_SUPPORT_DISABLED)
#if QT_VERSION < QT_VERSION_CHECK(6, 8, 0) || defined(PSD_NATIVE_CMYK_SUPPORT_DISABLED)
# define CMYK_FORMAT QImage::Format_Invalid
#else
# define CMYK_FORMAT QImage::Format_CMYK8888
@@ -327,18 +327,11 @@ static PSDImageResourceSection readImageResourceSection(QDataStream &s, bool *ok
*ok = true;
// Section size
quint32 tmpSize;
s >> tmpSize;
qint64 sectioSize = tmpSize;
qint32 sectioSize;
s >> sectioSize;
// Reading Image resource block
for (auto size = sectioSize; size > 0;) {
#define DEC_SIZE(value) \
if ((size -= qint64(value)) < 0) { \
*ok = false; \
break; }
// Length Description
// -------------------------------------------------------------------
// 4 Signature: '8BIM'
@@ -353,7 +346,7 @@ static PSDImageResourceSection readImageResourceSection(QDataStream &s, bool *ok
quint32 signature;
s >> signature;
DEC_SIZE(sizeof(signature))
size -= sizeof(signature);
// NOTE: MeSa signature is not documented but found in some old PSD take from Photoshop 7.0 CD.
if (signature != S_8BIM && signature != S_MeSa) { // 8BIM and MeSa
qCDebug(LOG_PSDPLUGIN) << "Invalid Image Resource Block Signature!";
@@ -364,7 +357,7 @@ static PSDImageResourceSection readImageResourceSection(QDataStream &s, bool *ok
// id
quint16 id;
s >> id;
DEC_SIZE(sizeof(id))
size -= sizeof(id);
// getting data
PSDImageResourceBlock irb;
@@ -372,25 +365,20 @@ static PSDImageResourceSection readImageResourceSection(QDataStream &s, bool *ok
// name
qint32 bytes = 0;
irb.name = readPascalString(s, 2, &bytes);
DEC_SIZE(bytes)
size -= bytes;
// data read
quint32 dataSize;
s >> dataSize;
DEC_SIZE(sizeof(dataSize))
if (auto dev = s.device()) {
if (dataSize > size) {
qCDebug(LOG_PSDPLUGIN) << "Invalid Image Resource Block Data Size!";
*ok = false;
break;
}
irb.data = deviceRead(dev, dataSize);
}
size -= sizeof(dataSize);
// NOTE: Qt device::read() and QDataStream::readRawData() could read less data than specified.
// The read code should be improved.
if (auto dev = s.device())
irb.data = dev->read(dataSize);
auto read = irb.data.size();
if (read > 0) {
DEC_SIZE(read)
}
if (read != qint64(dataSize)) {
if (read > 0)
size -= read;
if (quint32(read) != dataSize) {
qCDebug(LOG_PSDPLUGIN) << "Image Resource Block Read Error!";
*ok = false;
break;
@@ -398,15 +386,12 @@ static PSDImageResourceSection readImageResourceSection(QDataStream &s, bool *ok
if (auto pad = dataSize % 2) {
auto skipped = s.skipRawData(pad);
if (skipped > 0) {
DEC_SIZE(skipped);
}
if (skipped > 0)
size -= skipped;
}
// insert IRB
irs.insert(id, irb);
#undef DEC_SIZE
}
return irs;
@@ -504,13 +489,7 @@ PSDColorModeDataSection readColorModeDataSection(QDataStream &s, bool *ok = null
qint32 size;
s >> size;
if (size < 0) {
*ok = false;
} else if (size > 8 * 1024 * 1024) {
// The known color sections are all in the order of a few hundred bytes.
// I skip the ones that are too big, I don't know what to do with them.
*ok = s.skipRawData(size) == size;
} else if (size != 768) { // read the duotone data (524 bytes)
if (size != 768) { // read the duotone data (524 bytes)
// NOTE: A RGB/Gray float image has a 112 bytes ColorModeData that could be
// the "32-bit Toning Options" of Photoshop (starts with 'hdrt').
// Official Adobe specification tells "Only indexed color and duotone
@@ -719,7 +698,7 @@ static bool IsValid(const PSDHeader &header)
qCDebug(LOG_PSDPLUGIN) << "PSD header: invalid number of channels" << header.channel_count;
return false;
}
if (header.width > uint(std::min(300000, PSD_MAX_IMAGE_WIDTH)) || header.height > uint(std::min(300000, PSD_MAX_IMAGE_HEIGHT))) {
if (header.width > std::min(300000, PSD_MAX_IMAGE_WIDTH) || header.height > std::min(300000, PSD_MAX_IMAGE_HEIGHT)) {
qCDebug(LOG_PSDPLUGIN) << "PSD header: invalid image size" << header.width << "x" << header.height;
return false;
}
@@ -1357,7 +1336,7 @@ bool PSDHandler::read(QImage *image)
// CMYK with spots (e.g. CMYKA) ICC conversion to RGBA/RGBX
QImage tmpCmyk;
ScanLineConverter iccConv(img.format());
#if !defined(PSD_NATIVE_CMYK_SUPPORT_DISABLED)
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) && !defined(PSD_NATIVE_CMYK_SUPPORT_DISABLED)
if (header.color_mode == CM_CMYK && img.format() != QImage::Format_CMYK8888) {
auto tmpi = QImage(header.width, 1, QImage::Format_CMYK8888);
if (setColorSpace(tmpi, irs))
@@ -1509,11 +1488,13 @@ bool PSDHandler::read(QImage *image)
if (header.color_mode == CM_RGB && header.depth == 32) {
img.setColorSpace(QColorSpace(QColorSpace::SRgbLinear));
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
if (header.color_mode == CM_GRAYSCALE && header.depth == 32) {
auto qs = QColorSpace(QPointF(0.3127, 0.3291), QColorSpace::TransferFunction::Linear);
qs.setDescription(QStringLiteral("Linear grayscale"));
img.setColorSpace(qs);
}
#endif
}
// XMP data

View File

@@ -160,7 +160,7 @@ static bool LoadQOI(QIODevice *device, const QoiHeader &qoi, QImage &img)
// Handle the byte stream
QByteArray ba;
for (quint32 y = 0, run = 0; y < qoi.Height; ++y) {
if (quint64(ba.size()) < px_len && !device->atEnd()) {
if (quint64(ba.size()) < px_len) {
ba.append(device->read(px_len));
}

View File

@@ -841,9 +841,11 @@ bool LoadRAW(QImageIOHandler *handler, QImage &img)
if (params.output_color == 7) {
img.setColorSpace(QColorSpace(QColorSpace::DisplayP3));
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
if (params.output_color == 8) {
img.setColorSpace(QColorSpace(QColorSpace::Bt2020));
}
#endif
}
// *** Set the metadata

View File

@@ -766,11 +766,15 @@ bool SGIImagePrivate::writeImage(const QImage &image)
auto tcs = QColorSpace();
auto tfmt = image.format();
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
auto cs = image.colorSpace();
if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Cmyk && tfmt == QImage::Format_CMYK8888) {
tcs = QColorSpace(QColorSpace::SRgb);
tfmt = QImage::Format_RGB32;
} else if (hasAlpha && tfmt != QImage::Format_ARGB32) {
#else
if (hasAlpha && tfmt != QImage::Format_ARGB32) {
#endif
tfmt = QImage::Format_ARGB32;
} else if (!hasAlpha && tfmt != QImage::Format_RGB32) {
tfmt = QImage::Format_RGB32;

View File

@@ -72,12 +72,18 @@ const uchar *ScanLineConverter::convertedScanLine(const QImage &image, qint32 y)
if (!cs.isValid()) {
cs = _defaultColorSpace;
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
if (tmp.depth() < 8 && cs.colorModel() == QColorSpace::ColorModel::Gray) {
tmp.convertTo(QImage::Format_Grayscale8);
}
else if (tmp.depth() < 24 && cs.colorModel() == QColorSpace::ColorModel::Rgb) {
tmp.convertTo(tmp.hasAlphaChannel() ? QImage::Format_ARGB32 : QImage::Format_RGB32);
}
#else
if (tmp.depth() < 24) {
tmp.convertTo(tmp.hasAlphaChannel() ? QImage::Format_ARGB32 : QImage::Format_RGB32);
}
#endif
tmp.setColorSpace(cs);
tmp.convertToColorSpace(_colorSpace);
}

View File

@@ -177,10 +177,12 @@ public:
QImage::Format format() const
{
auto format = QImage::Format_Invalid;
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
if (m_pb.colorCount() == 4) {
if (m_pb.bitMask() == 15)
format = QImage::Format_CMYK8888;
}
#endif
if (m_pb.colorCount() == 3) {
if (m_pb.bitMask() == 7)
format = QImage::Format_RGB888;

View File

@@ -82,13 +82,6 @@ enum TGAType {
#define TGA_XMPP_TAGID 0x7002 // Xmp packet preceded by "xMPP" string
#define TGA_ICCP_TAGID 0x7003 // Icc profile preceded by "iCCP" string
/*
* Maximum size of a tag in the developer area.
*
* TGA is a 32-bit format so, a metadata should not be greater than some MB.
*/
#define DEV_TAG_MAX_SIZE (32 * 1024 * 1024)
/** Tga Header. */
struct TgaHeader {
uchar id_length = 0;
@@ -617,7 +610,11 @@ static bool LoadTGA(QIODevice *dev, const TgaHeader &tga, QImage &img)
// Read palette.
if (info.pal) {
QList<QRgb> colorTable;
#if QT_VERSION < QT_VERSION_CHECK(6, 8, 0)
colorTable.resize(tga.colormap_length);
#else
colorTable.resizeForOverwrite(tga.colormap_length);
#endif
if (tga.colormap_size == 32) {
char data[4]; // BGRA
@@ -992,11 +989,15 @@ bool TGAHandler::writeRGBA(const QImage &image)
auto format = image.format();
const bool hasAlpha = image.hasAlphaChannel();
auto tcs = QColorSpace();
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
auto cs = image.colorSpace();
if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Cmyk && image.format() == QImage::Format_CMYK8888) {
format = QImage::Format_RGB32;
tcs = QColorSpace(QColorSpace::SRgb);
} else if (hasAlpha && image.format() != QImage::Format_ARGB32) {
#else
if (hasAlpha && image.format() != QImage::Format_ARGB32) {
#endif
format = QImage::Format_ARGB32;
} else if (!hasAlpha && image.format() != QImage::Format_RGB32) {
format = QImage::Format_RGB32;
@@ -1239,10 +1240,6 @@ bool TGAHandler::readMetadata(QImage &image)
if (!dev->seek(f.offset)) {
return false;
}
if (f.size > DEV_TAG_MAX_SIZE) {
qCWarning(LOG_TGAPLUGIN) << "readMetadata: the size of TAG" << f.tagId << "is larger than" << (DEV_TAG_MAX_SIZE/1024/1024) << "MiB, so it will be ignored";
continue;
}
if (f.tagId == TGA_EXIF_TAGID) {
auto ba = dev->read(f.size);
if (ba.startsWith(QByteArray("eXif"))) {
@@ -1347,7 +1344,7 @@ bool TGAHandler::canRead(QIODevice *device)
TgaHeader tga;
if (!peekHeader(device, tga)) {
qCDebug(LOG_TGAPLUGIN) << "TGAHandler::canRead() error while reading the header";
qCWarning(LOG_TGAPLUGIN) << "TGAHandler::canRead() error while reading the header";
return false;
}

View File

@@ -12,7 +12,6 @@
#include <QImage>
#include <QImageIOHandler>
#include <QIODevice>
// Default maximum width and height for the large image plugins.
#ifndef KIF_LARGE_IMAGE_PIXEL_LIMIT
@@ -133,48 +132,4 @@ inline float fppm2dpi(qint32 ppm, bool *ok = nullptr)
return ppm2dpi_T<float>(ppm, ok);
}
/*!
* \brief deviceRead
* A function for reading from devices.
*
* Similar to QIODevice::read(qint64) but limits the initial memory allocation. Useful for reading corrupted streams.
* \param d The device.
* \param maxSize The maximum size to read.
* \return The byte array read.
*/
static QByteArray deviceRead(QIODevice *d, qint64 maxSize)
{
if (d == nullptr) {
return{};
}
const qint64 blockSize = 32 * 1024 * 1024;
auto devSize = d->isSequential() ? qint64() : d->size();
if (devSize > 0) {
// random access device
maxSize = std::min(maxSize, devSize - d->pos());
return d->read(maxSize);
} else if (maxSize < blockSize) {
// small read
return d->read(maxSize);
}
// sequential device
QByteArray ba;
while (ba.size() < maxSize) {
auto toRead = std::min(blockSize, maxSize - ba.size());
if (toRead + ba.size() > QByteArray::maxSize()) {
break;
}
auto tmp = d->read(toRead);
if (tmp.isEmpty()) {
break;
}
ba.append(tmp);
}
return ba;
}
#endif // UTIL_P_H

View File

@@ -1801,25 +1801,14 @@ bool XCFImageFormat::assignImageBytes(Layer &layer, uint i, uint j, const GimpPr
dataPtr[x + 1] = qFromBigEndian(src[x + 1]);
dataPtr[x + 2] = qFromBigEndian(src[x + 2]);
dataPtr[x + 3] = qfloat16(1);
if (!dataPtr[x + 0].isFinite() || !dataPtr[x + 1].isFinite() || !dataPtr[x + 2].isFinite()) {
if (dataPtr[x + 0].isNaN() || dataPtr[x + 1].isNaN() || dataPtr[x + 2].isNaN()) {
return false;
}
}
}
break;
case QImage::Format_RGBA16FPx4:
for (int y = 0; y < height; y++) {
const size_t bpl = width * sizeof(QRgbaFloat16);
qFromBigEndian<qint16>(tile + y * bpl, width * 4, image.scanLine(y));
const qfloat16 *dataPtr = reinterpret_cast<qfloat16 *>(image.scanLine(y));
for (int x = 0; x < width * 4; ++x) {
if (!dataPtr[x].isFinite()) {
return false;
}
}
}
break;
static_assert(sizeof(QRgbaFloat16) == sizeof(QRgba64), "Different sizes for float and int 16 bit pixels");
#endif
case QImage::Format_RGBA64:
for (int y = 0; y < height; y++) {
@@ -1832,13 +1821,6 @@ bool XCFImageFormat::assignImageBytes(Layer &layer, uint i, uint j, const GimpPr
for (int y = 0; y < height; y++) {
const size_t bpl = width * sizeof(QRgbaFloat32);
qFromBigEndian<qint32>(tile + y * bpl, width * 4, image.scanLine(y));
const float *dataPtr = reinterpret_cast<float *>(image.scanLine(y));
for (int x = 0; x < width * 4; ++x) {
if (!std::isfinite(dataPtr[x])) {
return false;
}
}
}
break;
case QImage::Format_RGBX32FPx4:
@@ -1850,7 +1832,7 @@ bool XCFImageFormat::assignImageBytes(Layer &layer, uint i, uint j, const GimpPr
dataPtr[x + 1] = qFromBigEndian(src[x + 1]);
dataPtr[x + 2] = qFromBigEndian(src[x + 2]);
dataPtr[x + 3] = 1.f;
if (!std::isfinite(dataPtr[x + 0]) || !std::isfinite(dataPtr[x + 1]) || !std::isfinite(dataPtr[x + 2])) {
if (std::isnan(dataPtr[x + 0]) || std::isnan(dataPtr[x + 1]) || std::isnan(dataPtr[x + 2])) {
return false;
}
}