mirror of
https://invent.kde.org/frameworks/kimageformats.git
synced 2026-06-16 19:39:10 -04:00
Compare commits
15 Commits
v6.23.0
...
v6.24.0-rc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae279c55f4 | ||
|
|
836e0a53bb | ||
|
|
5eb09116b0 | ||
|
|
92368ca58f | ||
|
|
a91c7ef72f | ||
|
|
ea2a4aafab | ||
|
|
c254875780 | ||
|
|
f3de2e77c1 | ||
|
|
1ef779f370 | ||
|
|
169a874cba | ||
|
|
ebf77ccdf5 | ||
|
|
359cb039d2 | ||
|
|
f4b91d8a54 | ||
|
|
263b5a88e2 | ||
|
|
8d07f7db1b |
@@ -1,11 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.27)
|
||||
|
||||
set(KF_VERSION "6.23.0") # handled by release scripts
|
||||
set(KF_DEP_VERSION "6.23.0") # handled by release scripts
|
||||
set(KF_VERSION "6.24.0") # handled by release scripts
|
||||
set(KF_DEP_VERSION "6.24.0") # handled by release scripts
|
||||
project(KImageFormats VERSION ${KF_VERSION})
|
||||
|
||||
include(FeatureSummary)
|
||||
find_package(ECM 6.23.0 NO_MODULE)
|
||||
find_package(ECM 6.24.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)
|
||||
|
||||
@@ -106,7 +106,7 @@ add_feature_info(LibJXR LibJXR_FOUND "required for the QImage plugin for JPEG XR
|
||||
|
||||
ecm_set_disabled_deprecation_versions(
|
||||
QT 6.11.0
|
||||
KF 6.21.0
|
||||
KF 6.23.0
|
||||
)
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
@@ -33,10 +33,10 @@ git clone --depth 1 -b master https://invent.kde.org/frameworks/extra-cmake-modu
|
||||
git clone --depth 1 --branch=dev git://code.qt.io/qt/qtbase.git
|
||||
git clone --depth 1 --branch=dev git://code.qt.io/qt/qttools.git
|
||||
git clone --depth 1 -b master https://invent.kde.org/frameworks/karchive.git
|
||||
git clone --depth 1 -b v3.12.0 https://aomedia.googlesource.com/aom
|
||||
git clone --depth 1 -b v1.2.1 https://github.com/AOMediaCodec/libavif.git
|
||||
git clone --depth 1 -b v3.13.1 https://aomedia.googlesource.com/aom
|
||||
git clone --depth 1 -b v1.3.0 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 -b v2.5.4 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 https://github.com/LibRaw/LibRaw
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "ani_p.h"
|
||||
#include "util_p.h"
|
||||
|
||||
#include <QImage>
|
||||
#include <QLoggingCategory>
|
||||
@@ -101,7 +102,7 @@ bool ANIHandler::read(QImage *outImage)
|
||||
}
|
||||
|
||||
const auto frameSize = *(reinterpret_cast<const quint32_le *>(frameSizeData.data()));
|
||||
if (!frameSize) {
|
||||
if (!frameSize || frameSize > quint32(kMaxQVectorSize)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -417,6 +418,9 @@ bool ANIHandler::ensureScanned() const
|
||||
// IART and INAM are technically inside LIST->INFO but "INFO" is supposedly optional
|
||||
// so just handle those two attributes wherever we encounter them
|
||||
} else if (chunkId == "INAM" || chunkId == "IART") {
|
||||
if (chunkSize > kMaxQVectorSize) {
|
||||
return false;
|
||||
}
|
||||
const QByteArray value = device()->read(chunkSize);
|
||||
|
||||
if (static_cast<quint32_le>(value.size()) != chunkSize) {
|
||||
|
||||
@@ -1080,6 +1080,7 @@ QByteArray BODYChunk::deinterleave(const QByteArray &planes, qint32 y, const BMH
|
||||
// (red and green modify operations are unavailable)
|
||||
auto ctlbits = bitplanes > 5 ? 2 : 1;
|
||||
auto max = (1 << (bitplanes - ctlbits)) - 1;
|
||||
auto wrongIdx = false;
|
||||
quint8 prev[3] = {};
|
||||
for (qint32 i = 0, cnt = 0; i < rowLen; ++i) {
|
||||
for (qint32 j = 0; j < 8; ++j, ++cnt) {
|
||||
@@ -1111,7 +1112,7 @@ QByteArray BODYChunk::deinterleave(const QByteArray &planes, qint32 y, const BMH
|
||||
prev[1] = qGreen(pal.at(idx));
|
||||
prev[2] = qBlue(pal.at(idx));
|
||||
} else {
|
||||
qCWarning(LOG_IFFPLUGIN) << "BODYChunk::deinterleave(): palette index" << idx << "is out of range";
|
||||
wrongIdx = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1121,6 +1122,9 @@ QByteArray BODYChunk::deinterleave(const QByteArray &planes, qint32 y, const BMH
|
||||
ba[cnt3 + 2] = char(prev[2]);
|
||||
}
|
||||
}
|
||||
if (wrongIdx) {
|
||||
qCWarning(LOG_IFFPLUGIN) << "BODYChunk::deinterleave(): HAM palette index out of range!";
|
||||
}
|
||||
} else if ((modeId & CAMGChunk::ModeId::HalfBrite) && (cmap) &&
|
||||
(bitplanes >= BITPLANES_HALFBRIDE_MIN && bitplanes <= BITPLANES_HALFBRIDE_MAX)) {
|
||||
// From A Quick Introduction to IFF.txt:
|
||||
@@ -1133,6 +1137,7 @@ QByteArray BODYChunk::deinterleave(const QByteArray &planes, qint32 y, const BMH
|
||||
// absolute colors.
|
||||
ba = QByteArray(rowLen * 8, char());
|
||||
auto palSize = cmap->count();
|
||||
auto wrongIdx = false;
|
||||
for (qint32 i = 0, cnt = 0; i < rowLen; ++i) {
|
||||
for (qint32 j = 0; j < 8; ++j, ++cnt) {
|
||||
quint8 idx = 0, ctl = 0;
|
||||
@@ -1147,10 +1152,13 @@ QByteArray BODYChunk::deinterleave(const QByteArray &planes, qint32 y, const BMH
|
||||
if (idx < palSize) {
|
||||
ba[cnt] = ctl ? idx + palSize : idx;
|
||||
} else {
|
||||
qCWarning(LOG_IFFPLUGIN) << "BODYChunk::deinterleave(): palette index" << idx << "is out of range";
|
||||
wrongIdx = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (wrongIdx) {
|
||||
qCWarning(LOG_IFFPLUGIN) << "BODYChunk::deinterleave(): HalfBrite palette index out of range!";
|
||||
}
|
||||
} else {
|
||||
// From A Quick Introduction to IFF.txt:
|
||||
//
|
||||
@@ -2538,7 +2546,7 @@ static QByteArray decompressVdat(const QByteArray &comp)
|
||||
static QByteArray vdatToIlbmPlane(const QByteArray &vdatData, const BMHDChunk *header)
|
||||
{
|
||||
QByteArray ba(vdatData.size(), char());
|
||||
auto rowLen = header->rowLen();
|
||||
auto rowLen = qint32(header->rowLen());
|
||||
for (auto x = 0, n = 0; x < rowLen; x += 2) {
|
||||
for (auto y = 0, off = x, h = header->height(); y < h; y++, off += rowLen) {
|
||||
if ((off + 1 >= ba.size()) || n + 1 >= vdatData.size()) {
|
||||
@@ -2844,7 +2852,7 @@ bool PLTEChunk::isValid() const
|
||||
if (dataBytes() < 4) {
|
||||
return false;
|
||||
}
|
||||
if (dataBytes() - 4 < total() * 3) {
|
||||
if (dataBytes() - 4 < quint32(total()) * 3) {
|
||||
return false;
|
||||
}
|
||||
return chunkId() == PLTEChunk::defaultChunkId();
|
||||
@@ -3004,7 +3012,7 @@ QByteArray IDATChunk::strideRead(QIODevice *d, qint32 y, const IHDRChunk *header
|
||||
}
|
||||
|
||||
if (header->model() == IHDRChunk::CLut4) {
|
||||
if (rr.size() < header->width() / 2) {
|
||||
if (rr.size() < (qint64(header->width()) + 1) / 2) {
|
||||
return {};
|
||||
}
|
||||
QByteArray tmp(header->width(), char());
|
||||
|
||||
@@ -253,20 +253,27 @@ public:
|
||||
bool jp2ToImage(QImage *img) const
|
||||
{
|
||||
Q_ASSERT(img->depth() == 8 * sizeof(T) || img->depth() == 32 * sizeof(T));
|
||||
for (qint32 c = 0, cc = m_jp2_image->numcomps; c < cc; ++c) {
|
||||
auto cs = cc == 1 ? 1 : 4;
|
||||
if (img->width() < 1 || img->height() < 1) {
|
||||
return false;
|
||||
}
|
||||
auto maxChannels = qint32(img->bytesPerLine() / sizeof(T) / img->width());
|
||||
for (qint32 c = 0, cc = std::min(qint32(m_jp2_image->numcomps), maxChannels); c < cc; ++c) {
|
||||
auto cs = std::min(cc == 1 ? 1 : 4, maxChannels);
|
||||
auto &&jc = m_jp2_image->comps[c];
|
||||
if (jc.data == nullptr)
|
||||
if (jc.data == nullptr) {
|
||||
return false;
|
||||
if (qint32(jc.w) != img->width() || qint32(jc.h) != img->height())
|
||||
}
|
||||
if (qint32(jc.w) != img->width() || qint32(jc.h) != img->height()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// discriminate between int and float (avoid complicating things by creating classes with template specializations)
|
||||
if (std::numeric_limits<T>::is_integer) {
|
||||
auto divisor = 1;
|
||||
if (jc.prec > sizeof(T) * 8) {
|
||||
auto divisor = 1ull;
|
||||
auto prec = std::min(size_t(jc.prec), sizeof(*jc.data) * 8);
|
||||
if (prec > sizeof(T) * 8 && prec < 64) {
|
||||
// convert to the wanted precision (e.g. 16-bit -> 8-bit: divisor = 65535 / 255 = 257)
|
||||
divisor = std::max(1, int(((1ll << jc.prec) - 1) / ((1ll << (sizeof(T) * 8)) - 1)));
|
||||
divisor = std::max(1ull, (((1ull << prec) - 1) / ((1ull << (sizeof(T) * 8)) - 1)));
|
||||
}
|
||||
for (qint32 y = 0, h = img->height(); y < h; ++y) {
|
||||
auto ptr = reinterpret_cast<T *>(img->scanLine(y));
|
||||
|
||||
@@ -2008,6 +2008,11 @@ bool QJpegXLHandler::extractBox(QByteArray &output, size_t container_size)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rawboxsize > 8388608) { // 8MB limit
|
||||
qCWarning(LOG_JXLPLUGIN, "Skipped decoding of big JXL metadata box");
|
||||
return true;
|
||||
}
|
||||
|
||||
output.resize(rawboxsize);
|
||||
status = JxlDecoderSetBoxBuffer(m_decoder, reinterpret_cast<uint8_t *>(output.data()), output.size());
|
||||
if (status != JXL_DEC_SUCCESS) {
|
||||
@@ -2021,7 +2026,7 @@ bool QJpegXLHandler::extractBox(QByteArray &output, size_t container_size)
|
||||
if (status == JXL_DEC_BOX_NEED_MORE_OUTPUT) {
|
||||
size_t bytes_remains = JxlDecoderReleaseBoxBuffer(m_decoder);
|
||||
|
||||
if (output.size() > 4194304) { // approx. 4MB limit for decompressed metadata box
|
||||
if (output.size() > 33554432) { // approx. 32MB (4*8) limit for decompressed metadata box
|
||||
qCWarning(LOG_JXLPLUGIN, "JXL metadata box is too large");
|
||||
m_parseState = ParseJpegXLError;
|
||||
return false;
|
||||
|
||||
@@ -1017,7 +1017,7 @@ inline void rawChannelCopy(uchar *target, qint32 targetChannels, qint32 targetCh
|
||||
|
||||
|
||||
template<class T>
|
||||
inline void cmykToRgb(uchar *target, qint32 targetChannels, const char *source, qint32 sourceChannels, qint32 width, bool alpha = false)
|
||||
inline bool cmykToRgb(uchar *target, qint32 targetChannels, const char *source, qint32 sourceChannels, qint32 width, bool alpha = false)
|
||||
{
|
||||
auto s = reinterpret_cast<const T*>(source);
|
||||
auto t = reinterpret_cast<T*>(target);
|
||||
@@ -1026,7 +1026,7 @@ inline void cmykToRgb(uchar *target, qint32 targetChannels, const char *source,
|
||||
|
||||
if (sourceChannels < 2) {
|
||||
qCDebug(LOG_PSDPLUGIN) << "cmykToRgb: image is not a valid MCH/CMYK!";
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (qint32 w = 0; w < width; ++w) {
|
||||
@@ -1047,6 +1047,7 @@ inline void cmykToRgb(uchar *target, qint32 targetChannels, const char *source,
|
||||
*(pt + 3) = std::numeric_limits<T>::max();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline double finv(double v)
|
||||
@@ -1066,7 +1067,7 @@ inline double gammaCorrection(double linear)
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void labToRgb(uchar *target, qint32 targetChannels, const char *source, qint32 sourceChannels, qint32 width, bool alpha = false)
|
||||
inline bool labToRgb(uchar *target, qint32 targetChannels, const char *source, qint32 sourceChannels, qint32 width, bool alpha = false)
|
||||
{
|
||||
auto s = reinterpret_cast<const T*>(source);
|
||||
auto t = reinterpret_cast<T*>(target);
|
||||
@@ -1075,7 +1076,7 @@ inline void labToRgb(uchar *target, qint32 targetChannels, const char *source, q
|
||||
|
||||
if (sourceChannels < 3) {
|
||||
qCDebug(LOG_PSDPLUGIN) << "labToRgb: image is not a valid LAB!";
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (qint32 w = 0; w < width; ++w) {
|
||||
@@ -1110,6 +1111,7 @@ inline void labToRgb(uchar *target, qint32 targetChannels, const char *source, q
|
||||
*(pt + 3) = std::numeric_limits<T>::max();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool readChannel(QByteArray &target, QDataStream &stream, quint32 compressedSize, quint16 compression)
|
||||
@@ -1450,10 +1452,13 @@ bool PSDHandler::read(QImage *image)
|
||||
// Conversion to RGB
|
||||
if (header.color_mode == CM_CMYK || header.color_mode == CM_MULTICHANNEL) {
|
||||
if (tmpCmyk.isNull()) {
|
||||
if (header.depth == 8)
|
||||
cmykToRgb<quint8>(img.scanLine(y), imgChannels, psdScanline.data(), header.channel_count, header.width, alpha);
|
||||
else if (header.depth == 16)
|
||||
cmykToRgb<quint16>(img.scanLine(y), imgChannels, psdScanline.data(), header.channel_count, header.width, alpha);
|
||||
if (header.depth == 8) {
|
||||
if (!cmykToRgb<quint8>(img.scanLine(y), imgChannels, psdScanline.data(), header.channel_count, header.width, alpha))
|
||||
return false;
|
||||
} else if (header.depth == 16) {
|
||||
if (!cmykToRgb<quint16>(img.scanLine(y), imgChannels, psdScanline.data(), header.channel_count, header.width, alpha))
|
||||
return false;
|
||||
}
|
||||
} else if (header.depth == 8) {
|
||||
rawChannelsCopyToCMYK<quint8>(tmpCmyk.bits(), 4, psdScanline.data(), header.channel_count, header.width);
|
||||
if (auto rgbPtr = iccConv.convertedScanLine(tmpCmyk, 0))
|
||||
@@ -1469,10 +1474,13 @@ bool PSDHandler::read(QImage *image)
|
||||
}
|
||||
}
|
||||
if (header.color_mode == CM_LABCOLOR) {
|
||||
if (header.depth == 8)
|
||||
labToRgb<quint8>(img.scanLine(y), imgChannels, psdScanline.data(), header.channel_count, header.width, alpha);
|
||||
else if (header.depth == 16)
|
||||
labToRgb<quint16>(img.scanLine(y), imgChannels, psdScanline.data(), header.channel_count, header.width, alpha);
|
||||
if (header.depth == 8) {
|
||||
if (!labToRgb<quint8>(img.scanLine(y), imgChannels, psdScanline.data(), header.channel_count, header.width, alpha))
|
||||
return false;
|
||||
} else if (header.depth == 16) {
|
||||
if (!labToRgb<quint16>(img.scanLine(y), imgChannels, psdScanline.data(), header.channel_count, header.width, alpha))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (header.color_mode == CM_RGB) {
|
||||
if (header.depth == 8)
|
||||
|
||||
@@ -319,7 +319,10 @@ bool SGIImagePrivate::readImage(QImage &img)
|
||||
|
||||
if (_rle) {
|
||||
uint l;
|
||||
_starttab = new quint32[_numrows];
|
||||
_starttab = new (std::nothrow) quint32[_numrows];
|
||||
if (_starttab == nullptr) {
|
||||
return false;
|
||||
}
|
||||
for (l = 0; !_stream.atEnd() && l < _numrows; l++) {
|
||||
_stream >> _starttab[l];
|
||||
_starttab[l] -= 512 + _numrows * 2 * sizeof(quint32);
|
||||
@@ -331,7 +334,10 @@ bool SGIImagePrivate::readImage(QImage &img)
|
||||
_starttab[l] = 0;
|
||||
}
|
||||
|
||||
_lengthtab = new quint32[_numrows];
|
||||
_lengthtab = new (std::nothrow) quint32[_numrows];
|
||||
if (_lengthtab == nullptr) {
|
||||
return false;
|
||||
}
|
||||
for (l = 0; !_stream.atEnd() && l < _numrows; l++) {
|
||||
_stream >> _lengthtab[l];
|
||||
if (_stream.status() != QDataStream::Ok) {
|
||||
@@ -794,7 +800,10 @@ bool SGIImagePrivate::writeImage(const QImage &image)
|
||||
_pixmax = 0;
|
||||
_colormap = NORMAL;
|
||||
_numrows = _ysize * _zsize;
|
||||
_starttab = new quint32[_numrows];
|
||||
_starttab = new (std::nothrow) quint32[_numrows];
|
||||
if (_starttab == nullptr) {
|
||||
return false;
|
||||
}
|
||||
_rlemap.setBaseOffset(512 + _numrows * 2 * sizeof(quint32));
|
||||
|
||||
if (!scanData(image, tfmt, tcs)) {
|
||||
|
||||
@@ -731,7 +731,7 @@ static bool LoadTGA(QIODevice *dev, const TgaHeader &tga, QImage &img)
|
||||
if (div == 0)
|
||||
hasAlpha = false;
|
||||
for (int x = x_start; x != x_end; x += x_step) {
|
||||
const int alpha = hasAlpha ? int((src[3]) << (8 - numAlphaBits)) * 255 / div : 255;
|
||||
const int alpha = hasAlpha ? int(quint8(src[3]) << (8 - numAlphaBits)) * 255 / div : 255;
|
||||
scanline[x] = qRgba(src[2], src[1], src[0], alpha);
|
||||
src += 4;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user