Compare commits

..
Author SHA1 Message Date
Albert Astals Cid 40ed3e4e27 oss-fuzz: Get a newer cmake from pip 2026-10-06 22:38:24 +02:00
Sertonix NorsonandMirco Miranda e539ca748f Enable perceptiveFuzzer for write tests
Fixes kimageformats-write-exr test on Alpine Linux armhf, armv7,
loongarch64, ppc64le, riscv64 and s390x.

Working alternatives are increasing fuzziness to 10 or using 64bpp
formats as compareFormat.
2026-10-06 04:37:46 +02:00
Sertonix Norson cb74a20421 EXIF: always use little-endian for UTF-16
In practice UTF-16 (especially from windows) uses little-endian without
a BOM. By default Qt uses host endianess which causes TIFF_XPTITLE and
TIFF_XPKEYWORDS to not be read correctly.

Fixes c21b50d699
2026-10-05 12:28:36 +02:00
Sertonix NorsonandDaniel Novomeský af34c774d3 avif: increase fuzziness in invalid-exif.avif.json to 44
Fixes kimageformats-read-avif test failure on Alpine Linux s390x

Ref https://invent.kde.org/frameworks/kimageformats/-/merge_requests/530#note_1561068
2026-10-03 23:13:16 +00:00
Sertonix NorsonandAlbert Astals Cid 104643bf09 IFF: fix BODYChunk::deinterleave on big-endian
Qt accesses the data of QImage::Format_RGBX64 and QImage::Format_RGBA64
as host-endian quint16. Having BODYChunk::deinterleave write the data
with host-endian to fix parsing on big-endian systems.
2026-10-03 10:43:42 +00:00
Sertonix NorsonandAlbert Astals Cid 9a45321440 IFF: fix DBODChunk::strideRead on big-endian
On big-endian systems the uint16 data should stay big-endian.
2026-10-03 10:43:42 +00:00
Sertonix NorsonandAlbert Astals Cid f5ba223e15 TIM: fix 16BPP on big-endian
Despite the QImage::scanLine doc only warning about byte order issues
for 32-bpp formats[0] the same warning seems to apply to 16BPP formats
like QImage::Format_RGB555 as well.

[0]: https://doc.qt.io/qt-6/qimage.html#scanLine
2026-10-03 10:34:55 +00:00
Sertonix NorsonandAlbert Astals Cid e23328fda8 FF: replace broken #if Q_LITTLE_ENDIAN
Q_LITTLE_ENDIAN was used incorrectly, it should have been
"#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN"

Use qFromBigEndian since it is more explicit.

Fixes 6d5e61f0b0
2026-10-03 10:22:23 +00:00
Mirco MirandaandNicolas Fella 8b8eb91f2b Disable LSAN due to obsolete JXRLIB on CI 2026-10-02 16:02:55 +02:00
Nicolas Fella 5e3c759e21 Update version to 6.32.0 2026-10-02 15:49:57 +02:00
9 changed files with 31 additions and 26 deletions
+1 -1
View File
@@ -9,4 +9,4 @@ Options:
require-passing-tests-on: ['Linux', 'FreeBSD', 'Windows'] require-passing-tests-on: ['Linux', 'FreeBSD', 'Windows']
cmake-options: "-DKIMAGEFORMATS_WITH_KNOWN_CRASHES_JXR=ON -DKIMAGEFORMATS_HEIF=ON -DKIMAGEFORMATS_HEIC_TEST:STRING=OFF -DKIMAGEFORMATS_HEIF_TEST:STRING=OFF -DKIMAGEFORMATS_HEJ2_TEST:STRING=OFF -DKIMAGEFORMATS_AVCI_TEST:STRING=OFF" cmake-options: "-DKIMAGEFORMATS_WITH_KNOWN_CRASHES_JXR=ON -DKIMAGEFORMATS_HEIF=ON -DKIMAGEFORMATS_HEIC_TEST:STRING=OFF -DKIMAGEFORMATS_HEIF_TEST:STRING=OFF -DKIMAGEFORMATS_HEJ2_TEST:STRING=OFF -DKIMAGEFORMATS_AVCI_TEST:STRING=OFF"
per-test-timeout: 90 per-test-timeout: 90
enable-lsan: True enable-lsan: False
+1 -1
View File
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.30) cmake_minimum_required(VERSION 3.30)
set(KF_VERSION "6.31.0") # handled by release scripts set(KF_VERSION "6.32.0") # handled by release scripts
set(KF_DEP_VERSION "6.31.0") # handled by release scripts set(KF_DEP_VERSION "6.31.0") # handled by release scripts
project(KImageFormats VERSION ${KF_VERSION}) project(KImageFormats VERSION ${KF_VERSION})
+3 -1
View File
@@ -21,9 +21,11 @@
################################################################################ ################################################################################
apt-get update && \ apt-get update && \
apt-get install -y cmake make autoconf automake autopoint libtool \ apt-get install -y make autoconf automake autopoint libtool \
wget po4a ninja-build pkgconf wget po4a ninja-build pkgconf
pip install cmake
git clone --depth 1 https://github.com/madler/zlib.git git clone --depth 1 https://github.com/madler/zlib.git
git clone --depth 1 -b v1.5.7 https://github.com/facebook/zstd.git git clone --depth 1 -b v1.5.7 https://github.com/facebook/zstd.git
wget https://sourceware.org/pub/bzip2/bzip2-1.0.8.tar.gz wget https://sourceware.org/pub/bzip2/bzip2-1.0.8.tar.gz
+1 -1
View File
@@ -1,7 +1,7 @@
[ [
{ {
"fileName": "invalid-exif.jpg", "fileName": "invalid-exif.jpg",
"fuzziness": 30, "fuzziness": 44,
"description": "Minimum fuzziness value to pass the test on all architectures." "description": "Minimum fuzziness value to pass the test on all architectures."
} }
] ]
+1 -1
View File
@@ -428,7 +428,7 @@ int formatTest(const QString &suffix, bool createTemplates)
// This comparison is only to understand if the plugin has written a completely wrong image. I therefore have no // This comparison is only to understand if the plugin has written a completely wrong image. I therefore have no
// qualms about converting them to a more convenient format or to tolerate slightly different pixels. // qualms about converting them to a more convenient format or to tolerate slightly different pixels.
auto compareFormat = writtenImage.hasAlphaChannel() ? QImage::Format_ARGB32 : QImage::Format_RGB32; auto compareFormat = writtenImage.hasAlphaChannel() ? QImage::Format_ARGB32 : QImage::Format_RGB32;
if (!fuzzyeq(writtenImage.convertToFormat(compareFormat), tmplImage.convertToFormat(compareFormat), 5)) { if (!fuzzyeq(writtenImage.convertToFormat(compareFormat), tmplImage.convertToFormat(compareFormat), 5, true)) {
++failed; ++failed;
QTextStream(stdout) << "FAIL : re-reading the data resulted in a different image " << formatName << "\n"; QTextStream(stdout) << "FAIL : re-reading the data resulted in a different image " << formatName << "\n";
continue; continue;
+14 -11
View File
@@ -1271,33 +1271,34 @@ QByteArray BODYChunk::deinterleave(const QByteArray &planes, qint32 y, const BMH
// from the PNG format into the Amiga (ILBM) bitmap format. // from the PNG format into the Amiga (ILBM) bitmap format.
ba = QByteArray(rowLen * 64, char()); // the RGBX QT format is 64-bits ba = QByteArray(rowLen * 64, char()); // the RGBX QT format is 64-bits
quint16 *data = reinterpret_cast<quint16*>(ba.data());
const qint32 order[] = { 1, 0, 3, 2, 5, 4, 7, 6 }; const qint32 order[] = { 1, 0, 3, 2, 5, 4, 7, 6 };
for (qint32 i = 0, cnt = 0, p = bitplanes / 8; i < rowLen; ++i) { for (qint32 i = 0, cnt = 0, p = bitplanes / 8; i < rowLen; ++i) {
for (qint32 j = 0; j < 8; ++j, cnt += 8) { for (qint32 j = 0; j < 8; ++j, cnt += 8) {
for (qint32 k = 0; k < p; ++k) { for (qint32 k = 0; k < p; ++k) {
auto k8 = k * 8; auto k8 = k * 8;
auto msk = (1 << (7 - j)); auto msk = (1 << (7 - j));
auto idx = cnt + order[k]; auto idx = (cnt + order[k]) / 2;
auto shift = (order[k] % 2) * 8;
if (planes.at(k8 * rowLen + i) & msk) if (planes.at(k8 * rowLen + i) & msk)
ba[idx] |= 0x01; data[idx] |= 0x01 << shift;
if (planes.at((1 + k8) * rowLen + i) & msk) if (planes.at((1 + k8) * rowLen + i) & msk)
ba[idx] |= 0x02; data[idx] |= 0x02 << shift;
if (planes.at((2 + k8) * rowLen + i) & msk) if (planes.at((2 + k8) * rowLen + i) & msk)
ba[idx] |= 0x04; data[idx] |= 0x04 << shift;
if (planes.at((3 + k8) * rowLen + i) & msk) if (planes.at((3 + k8) * rowLen + i) & msk)
ba[idx] |= 0x08; data[idx] |= 0x08 << shift;
if (planes.at((4 + k8) * rowLen + i) & msk) if (planes.at((4 + k8) * rowLen + i) & msk)
ba[idx] |= 0x10; data[idx] |= 0x10 << shift;
if (planes.at((5 + k8) * rowLen + i) & msk) if (planes.at((5 + k8) * rowLen + i) & msk)
ba[idx] |= 0x20; data[idx] |= 0x20 << shift;
if (planes.at((6 + k8) * rowLen + i) & msk) if (planes.at((6 + k8) * rowLen + i) & msk)
ba[idx] |= 0x40; data[idx] |= 0x40 << shift;
if (planes.at((7 + k8) * rowLen + i) & msk) if (planes.at((7 + k8) * rowLen + i) & msk)
ba[idx] |= 0x80; data[idx] |= 0x80 << shift;
} }
if (p == 6) { // RGBX wants unused X data set to 0xFF if (p == 6) { // RGBX wants unused X data set to 0xFF
ba[cnt + 6] = char(0xFF); data[cnt / 2 + 3] = 0xFFFF;
ba[cnt + 7] = char(0xFF);
} }
} }
} }
@@ -4083,6 +4084,7 @@ QByteArray DBODChunk::strideRead(QIODevice *d, qint32, const DGBLChunk *header,
return {}; return {};
} }
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
// byte swap // byte swap
if (auto count = pel->count()) { if (auto count = pel->count()) {
if (pel->depth() / count == 16) { if (pel->depth() / count == 16) {
@@ -4091,6 +4093,7 @@ QByteArray DBODChunk::strideRead(QIODevice *d, qint32, const DGBLChunk *header,
} }
} }
} }
#endif
return planes; return planes;
} }
+1 -5
View File
@@ -176,11 +176,7 @@ bool FFHandler::read(QImage *image)
qCWarning(LOG_FFPLUGIN) << "FFHandler::read() error while reading image scanline"; qCWarning(LOG_FFPLUGIN) << "FFHandler::read() error while reading image scanline";
return false; return false;
} }
#if Q_LITTLE_ENDIAN qFromBigEndian<quint16>(line, size / 2, line);
for (auto i = 0; i < size; i += 2) {
std::swap(line[i], line[i + 1]);
}
#endif
} }
img.setColorSpace(QColorSpace(QColorSpace::SRgb)); img.setColorSpace(QColorSpace(QColorSpace::SRgb));
+6 -5
View File
@@ -13,6 +13,7 @@
#include <QDataStream> #include <QDataStream>
#include <QHash> #include <QHash>
#include <QStringDecoder> #include <QStringDecoder>
#include <QStringEncoder>
#include <QTimeZone> #include <QTimeZone>
// TIFF 6 specs // TIFF 6 specs
@@ -1748,9 +1749,10 @@ void MicroExif::setUtf16String(Tags &tags, quint16 tagId, const QString &s)
tags.remove(tagId); tags.remove(tagId);
return; return;
} }
auto s16 = s.toStdU16String();
QStringEncoder fromUtf16(QStringEncoder::Utf16LE, QStringEncoder::Flag::Stateless);
QByteArray ba = fromUtf16(s);
QList<quint8> uba; QList<quint8> uba;
auto ba = QByteArrayView(reinterpret_cast<char*>(s16.data()), s.size() * 2);
for(auto&& c : ba) for(auto&& c : ba)
uba.append(quint8(c)); uba.append(quint8(c));
uba.append(quint8('\0')); uba.append(quint8('\0'));
@@ -1763,7 +1765,6 @@ QString MicroExif::utf16String(const Tags &tags, quint16 tagId)
auto ba = tags.value(tagId).value<QList<quint8>>(); auto ba = tags.value(tagId).value<QList<quint8>>();
if (ba.isEmpty()) if (ba.isEmpty())
return {}; return {};
auto p16 = reinterpret_cast<char16_t*>(ba.data()); QStringDecoder toUtf16(QStringDecoder::Utf16LE, QStringDecoder::Flag::Stateless);
auto sz = std::max(ba.size() / 2 - 1, qsizetype()); return toUtf16(QByteArrayView(ba.data(), std::max(ba.size() - 2, qsizetype())));
return QString::fromUtf16(p16, sz);
} }
+3
View File
@@ -311,6 +311,9 @@ bool TIMHandler::read(QImage *image)
qCWarning(LOG_TIMPLUGIN) << "TIMHandler::read() error while reading image scanline"; qCWarning(LOG_TIMPLUGIN) << "TIMHandler::read() error while reading image scanline";
return false; return false;
} }
if (img.format() == QImage::Format_RGB555) {
qFromLittleEndian<quint16>(line, size / 2, line);
}
if (conv_4bpp) { if (conv_4bpp) {
for (auto x = 0, w = qint32(tmpBuff.size()); x < w; ++x) { for (auto x = 0, w = qint32(tmpBuff.size()); x < w; ++x) {
auto &&v = tmpBuff.at(x); auto &&v = tmpBuff.at(x);