JXR: Fixed image reading on sequential devices

The following changes are done:
- Fixed an error when copying image from sequential device
- Return error when the image exceed 4GB size on writing*
- Enabled JXR tests

(*) Note that when writing an image larger than 4GiB, the JXRLib does not give any error but the resulting saved image id wrong.
This commit is contained in:
Mirco Miranda 2024-10-09 21:34:32 +00:00 committed by Albert Astals Cid
parent 97120b2537
commit ac1006cc66
3 changed files with 22 additions and 14 deletions

View File

@ -7,3 +7,4 @@ Dependencies:
Options: Options:
test-before-installing: True test-before-installing: True
require-passing-tests-on: [ 'Linux', 'FreeBSD', 'Windows' ] require-passing-tests-on: [ 'Linux', 'FreeBSD', 'Windows' ]
cmake-options: "-DKIMAGEFORMATS_JXR=ON"

View File

@ -117,7 +117,7 @@ plugin ('n/a' means no limit, i.e. the limit depends on the format encoding).
- HDR: n/a (large image) - HDR: n/a (large image)
- HEIF: n/a - HEIF: n/a
- JXL: 65,535 x 65,535 pixels, in any case no larger than 256 megapixels - JXL: 65,535 x 65,535 pixels, in any case no larger than 256 megapixels
- JXR: n/a - JXR: n/a, in any case no larger than 4 GB
- PCX: 65,535 x 65,535 pixels - PCX: 65,535 x 65,535 pixels
- PFM: n/a (large image) - PFM: n/a (large image)
- PIC: 65,535 x 65,535 pixels - PIC: 65,535 x 65,535 pixels

View File

@ -484,11 +484,13 @@ public:
qi = qi.convertToFormat(alpha ? QImage::Format_RGBA8888 : QImage::Format_RGB888); qi = qi.convertToFormat(alpha ? QImage::Format_RGBA8888 : QImage::Format_RGB888);
} }
#ifndef JXR_DENY_FLOAT_IMAGE #ifndef JXR_DENY_FLOAT_IMAGE
} else if(qi.format() == QImage::Format_RGBA16FPx4 || // clang-format off
qi.format() == QImage::Format_RGBX16FPx4 || } else if (qi.format() == QImage::Format_RGBA16FPx4 ||
qi.format() == QImage::Format_RGBA32FPx4 || qi.format() == QImage::Format_RGBX16FPx4 ||
qi.format() == QImage::Format_RGBA32FPx4_Premultiplied || qi.format() == QImage::Format_RGBA32FPx4 ||
qi.format() == QImage::Format_RGBX32FPx4) { qi.format() == QImage::Format_RGBA32FPx4_Premultiplied ||
qi.format() == QImage::Format_RGBX32FPx4) {
// clang-format on
auto cs = qi.colorSpace(); auto cs = qi.colorSpace();
if (cs.isValid() && cs.transferFunction() != QColorSpace::TransferFunction::Linear) { if (cs.isValid() && cs.transferFunction() != QColorSpace::TransferFunction::Linear) {
qi = qi.convertedToColorSpace(QColorSpace(QColorSpace::SRgbLinear)); qi = qi.convertedToColorSpace(QColorSpace(QColorSpace::SRgbLinear));
@ -670,9 +672,12 @@ private:
return false; return false;
} }
QByteArray buff(32768 * 4, char()); QByteArray buff(32768 * 4, char());
for (; !source->atEnd();) { for (;;) {
auto read = source->read(buff.data(), buff.size()); auto read = source->read(buff.data(), buff.size());
if (read < 1) { if (read == 0) {
break;
}
if (read < 0) {
return false; return false;
} }
if (target->write(buff.data(), read) != read) { if (target->write(buff.data(), read) != read) {
@ -868,7 +873,7 @@ bool JXRHandler::read(QImage *outImage)
line[x + 3] = hasAlpha ? std::clamp(line[x + 3], float(0), float(1)) : float(1); line[x + 3] = hasAlpha ? std::clamp(line[x + 3], float(0), float(1)) : float(1);
} }
} }
if(!img.colorSpace().isValid()) { if (!img.colorSpace().isValid()) {
img.setColorSpace(QColorSpace(QColorSpace::SRgbLinear)); img.setColorSpace(QColorSpace(QColorSpace::SRgbLinear));
} }
} }
@ -880,6 +885,13 @@ bool JXRHandler::read(QImage *outImage)
bool JXRHandler::write(const QImage &image) bool JXRHandler::write(const QImage &image)
{ {
// JXR is stored in a TIFF V6 container that is limited to 4GiB. The size
// is limited to 4GB to leave room for IFDs, Metadata, etc...
if (qint64(image.sizeInBytes()) > 4000000000ll) {
qCWarning(LOG_JXRPLUGIN) << "JXRHandler::write() image too large: the image cannot exceed 4GB.";
return false;
}
if (!d->initForWriting()) { if (!d->initForWriting()) {
return false; return false;
} }
@ -1064,11 +1076,6 @@ bool JXRHandler::canRead(QIODevice *device)
return false; return false;
} }
// Some tests on sequential devices fail: I reject them for now
if (device->isSequential()) {
return false;
}
// JPEG XR image data is stored in TIFF-like container format (II and 0xBC01 version) // JPEG XR image data is stored in TIFF-like container format (II and 0xBC01 version)
if (device->peek(4) == QByteArray::fromRawData("\x49\x49\xbc\x01", 4)) { if (device->peek(4) == QByteArray::fromRawData("\x49\x49\xbc\x01", 4)) {
return true; return true;