Compare commits

..

1 Commits

Author SHA1 Message Date
Mirco Miranda
f728b87ae8 Full range HDR support
EXR, HDR, JXR and PFM formats support High Dynamic Range images (FP values grater than 1).

In summary, here is the list of changes:

    EXR, HDR, JXR and PFM: When working with FP formats, the clamp between 0 and 1 ​​is no longer done.
    EXR: Removed old SDR code and conversions. Due to the lack of a QImage Gray FP format, Gray images are output as RGB FP (recently added code for Qt 6.8 has been removed).
    PFM: Due to the lack of a QImage Gray FP format, Gray images are output as RGB FP.
    HDR: Added rotation and exposure support.

With this patch, EXR, JXR, HDR, PFM behave like Qt's TIFF plugin when working with FP images.
2024-07-11 23:34:28 +02:00
19 changed files with 49 additions and 265 deletions

View File

@@ -1,11 +1,11 @@
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
set(KF_VERSION "6.5.0") # handled by release scripts set(KF_VERSION "6.4.0") # handled by release scripts
set(KF_DEP_VERSION "6.5.0") # handled by release scripts set(KF_DEP_VERSION "6.4.0") # handled by release scripts
project(KImageFormats VERSION ${KF_VERSION}) project(KImageFormats VERSION ${KF_VERSION})
include(FeatureSummary) include(FeatureSummary)
find_package(ECM 6.5.0 NO_MODULE) find_package(ECM 6.4.0 NO_MODULE)
set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://commits.kde.org/extra-cmake-modules") 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) feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES)

View File

@@ -1,19 +0,0 @@
[
{
"minQtVersion" : "6.5.7",
"maxQtVersion" : "6.5.99",
"disableAutoTransform": true,
"fileName" : "orientation6_notranfs.png",
"comment" : "Test with automatic transformation disabled."
},
{
"minQtVersion" : "6.7.3",
"disableAutoTransform": true,
"fileName" : "orientation6_notranfs.png",
"comment" : "Test with automatic transformation disabled."
},
{
"unsupportedFormat" : true,
"comment" : "It is not possible to disable the transformation with the current version of the plugin."
}
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 593 B

View File

@@ -267,13 +267,10 @@ int main(int argc, char **argv)
continue; continue;
} }
TemplateImage::TestFlags flags = TemplateImage::None; bool skipTest = false;
QString comment; QFileInfo expFileInfo = timg.compareImage(skipTest);
QFileInfo expFileInfo = timg.compareImage(flags, comment); if (skipTest) {
if ((flags & TemplateImage::SkipTest) == TemplateImage::SkipTest) { QTextStream(stdout) << "SKIP : " << fi.fileName() << ": image format not supported by current Qt version!\n";
if(comment.isEmpty())
comment = QStringLiteral("image format not supported by current Qt version!");
QTextStream(stdout) << "SKIP : " << fi.fileName() << QStringLiteral(": %1\n").arg(comment);
++skipped; ++skipped;
continue; continue;
} }
@@ -294,7 +291,7 @@ int main(int argc, char **argv)
QImage expImage; QImage expImage;
// inputImage is auto-rotated to final orientation // inputImage is auto-rotated to final orientation
inputReader.setAutoTransform((flags & TemplateImage::DisableAutotransform) != TemplateImage::DisableAutotransform); inputReader.setAutoTransform(true);
if (!expReader.read(&expImage)) { if (!expReader.read(&expImage)) {
QTextStream(stdout) << "ERROR: " << fi.fileName() << ": could not load " << expfilename << ": " << expReader.errorString() << "\n"; QTextStream(stdout) << "ERROR: " << fi.fileName() << ": could not load " << expfilename << ": " << expReader.errorString() << "\n";

View File

@@ -28,10 +28,10 @@ bool TemplateImage::isTemplate() const
return false; return false;
} }
QFileInfo TemplateImage::compareImage(TestFlags &flags, QString& comment) const QFileInfo TemplateImage::compareImage(bool &skipTest) const
{ {
auto fi = jsonImage(flags, comment); auto fi = jsonImage(skipTest);
if ((flags & TestFlag::SkipTest) == TestFlag::SkipTest) { if (skipTest) {
return {}; return {};
} }
if (fi.exists()) { if (fi.exists()) {
@@ -58,9 +58,8 @@ QFileInfo TemplateImage::legacyImage() const
return {}; return {};
} }
QFileInfo TemplateImage::jsonImage(TestFlags &flags, QString& comment) const QFileInfo TemplateImage::jsonImage(bool &skipTest) const
{ {
flags = TestFlag::None;
auto fi = QFileInfo(QStringLiteral("%1.json").arg(m_fi.filePath())); auto fi = QFileInfo(QStringLiteral("%1.json").arg(m_fi.filePath()));
if (!fi.exists()) { if (!fi.exists()) {
return {}; return {};
@@ -87,10 +86,6 @@ QFileInfo TemplateImage::jsonImage(TestFlags &flags, QString& comment) const
auto maxQt = QVersionNumber::fromString(obj.value("maxQtVersion").toString()); auto maxQt = QVersionNumber::fromString(obj.value("maxQtVersion").toString());
auto name = obj.value("fileName").toString(); auto name = obj.value("fileName").toString();
auto unsupportedFormat = obj.value("unsupportedFormat").toBool(); auto unsupportedFormat = obj.value("unsupportedFormat").toBool();
comment = obj.value("comment").toString();
if(obj.value("disableAutoTransform").toBool())
flags |= TestFlag::DisableAutotransform;
// filter // filter
if (name.isEmpty() && !unsupportedFormat) if (name.isEmpty() && !unsupportedFormat)
@@ -100,7 +95,7 @@ QFileInfo TemplateImage::jsonImage(TestFlags &flags, QString& comment) const
if (!maxQt.isNull() && currentQt > maxQt) if (!maxQt.isNull() && currentQt > maxQt)
continue; continue;
if (unsupportedFormat) { if (unsupportedFormat) {
flags |= TestFlag::SkipTest; skipTest = true;
break; break;
} }
return QFileInfo(QStringLiteral("%1/%2").arg(fi.path(), name)); return QFileInfo(QStringLiteral("%1/%2").arg(fi.path(), name));

View File

@@ -16,13 +16,6 @@
class TemplateImage class TemplateImage
{ {
public: public:
enum TestFlag {
None = 0x0,
SkipTest = 0x1,
DisableAutotransform = 0x2
};
Q_DECLARE_FLAGS(TestFlags, TestFlag)
/*! /*!
* \brief TemplateImage * \brief TemplateImage
* \param fi The image to test. * \param fi The image to test.
@@ -49,10 +42,10 @@ public:
/*! /*!
* \brief compareImage * \brief compareImage
* \param flags Flags for modifying test behavior (e.g. image format not supported by current Qt version). * \param skipTest True if the test should be skipped (e.g. image format not supported by current Qt version).
* \return The template image to use for the comparison. * \return The template image to use for the comparison.
*/ */
QFileInfo compareImage(TestFlags &flags, QString& comment) const; QFileInfo compareImage(bool &skipTest) const;
/*! /*!
* \brief suffixes * \brief suffixes
@@ -69,15 +62,13 @@ private:
/*! /*!
* \brief jsonImage * \brief jsonImage
* \param flags Flags for modifying test behavior. * \param skipTest True if the test should be skipped (not supported).
* \return The template image read from the corresponding JSON. * \return The template image read from the corresponding JSON.
*/ */
QFileInfo jsonImage(TestFlags &flags, QString& comment) const; QFileInfo jsonImage(bool &skipTest) const;
private: private:
QFileInfo m_fi; QFileInfo m_fi;
}; };
Q_DECLARE_OPERATORS_FOR_FLAGS(TemplateImage::TestFlags)
#endif // TEMPLATEIMAGE_H #endif // TEMPLATEIMAGE_H

View File

@@ -619,15 +619,7 @@ bool QAVIFHandler::write(const QImage &image)
QImage tmpgrayimage = image.convertToFormat(tmpformat); QImage tmpgrayimage = image.convertToFormat(tmpformat);
avif = avifImageCreate(tmpgrayimage.width(), tmpgrayimage.height(), save_depth, AVIF_PIXEL_FORMAT_YUV400); avif = avifImageCreate(tmpgrayimage.width(), tmpgrayimage.height(), save_depth, AVIF_PIXEL_FORMAT_YUV400);
#if AVIF_VERSION >= 110000
res = avifImageAllocatePlanes(avif, AVIF_PLANES_YUV);
if (res != AVIF_RESULT_OK) {
qWarning("ERROR in avifImageAllocatePlanes: %s", avifResultToString(res));
return false;
}
#else
avifImageAllocatePlanes(avif, AVIF_PLANES_YUV); avifImageAllocatePlanes(avif, AVIF_PLANES_YUV);
#endif
if (tmpgrayimage.colorSpace().isValid()) { if (tmpgrayimage.colorSpace().isValid()) {
avif->colorPrimaries = (avifColorPrimaries)1; avif->colorPrimaries = (avifColorPrimaries)1;
@@ -814,15 +806,7 @@ bool QAVIFHandler::write(const QImage &image)
avif->transferCharacteristics = transfer_to_save; avif->transferCharacteristics = transfer_to_save;
if (iccprofile.size() > 0) { if (iccprofile.size() > 0) {
#if AVIF_VERSION >= 1000000
res = avifImageSetProfileICC(avif, reinterpret_cast<const uint8_t *>(iccprofile.constData()), iccprofile.size());
if (res != AVIF_RESULT_OK) {
qWarning("ERROR in avifImageSetProfileICC: %s", avifResultToString(res));
return false;
}
#else
avifImageSetProfileICC(avif, reinterpret_cast<const uint8_t *>(iccprofile.constData()), iccprofile.size()); avifImageSetProfileICC(avif, reinterpret_cast<const uint8_t *>(iccprofile.constData()), iccprofile.size());
#endif
} }
avifRGBImage rgb; avifRGBImage rgb;
@@ -987,8 +971,6 @@ bool QAVIFHandler::jumpToNextImage()
return false; return false;
} }
avifResult decodeResult;
if (m_decoder->imageIndex >= 0) { if (m_decoder->imageIndex >= 0) {
if (m_decoder->imageCount < 2) { if (m_decoder->imageCount < 2) {
m_parseState = ParseAvifSuccess; m_parseState = ParseAvifSuccess;
@@ -996,16 +978,11 @@ bool QAVIFHandler::jumpToNextImage()
} }
if (m_decoder->imageIndex >= m_decoder->imageCount - 1) { // start from beginning if (m_decoder->imageIndex >= m_decoder->imageCount - 1) { // start from beginning
decodeResult = avifDecoderReset(m_decoder); avifDecoderReset(m_decoder);
if (decodeResult != AVIF_RESULT_OK) {
qWarning("ERROR in avifDecoderReset: %s", avifResultToString(decodeResult));
m_parseState = ParseAvifError;
return false;
}
} }
} }
decodeResult = avifDecoderNextImage(m_decoder); avifResult decodeResult = avifDecoderNextImage(m_decoder);
if (decodeResult != AVIF_RESULT_OK) { if (decodeResult != AVIF_RESULT_OK) {
qWarning("ERROR: Failed to decode Next image in sequence: %s", avifResultToString(decodeResult)); qWarning("ERROR: Failed to decode Next image in sequence: %s", avifResultToString(decodeResult));

View File

@@ -297,27 +297,23 @@ static void readMetadata(const Imf::Header &header, QImage &image)
image.setText(QStringLiteral(META_KEY_XMP_ADOBE), QString::fromStdString(xmp->value())); image.setText(QStringLiteral(META_KEY_XMP_ADOBE), QString::fromStdString(xmp->value()));
} }
// camera metadata /* TODO: OpenEXR 3.2 metadata
if (auto manufacturer = header.findTypedAttribute<Imf::StringAttribute>("cameraMake")) { *
image.setText(QStringLiteral(META_KEY_MANUFACTURER), QString::fromStdString(manufacturer->value())); * New Optional Standard Attributes:
} * - Support automated editorial workflow:
if (auto model = header.findTypedAttribute<Imf::StringAttribute>("cameraModel")) { * reelName, imageCounter, ascFramingDecisionList
image.setText(QStringLiteral(META_KEY_MODEL), QString::fromStdString(model->value())); *
} * - Support forensics (“which other shots used that camera and lens before the camera firmware was updated?”):
if (auto serial = header.findTypedAttribute<Imf::StringAttribute>("cameraSerialNumber")) { * cameraMake, cameraModel, cameraSerialNumber, cameraFirmware, cameraUuid, cameraLabel, lensMake, lensModel,
image.setText(QStringLiteral(META_KEY_SERIALNUMBER), QString::fromStdString(serial->value())); * lensSerialNumber, lensFirmware, cameraColorBalance
} *
* -Support pickup shots (reproduce critical camera settings):
// lens metadata * shutterAngle, cameraCCTSetting, cameraTintSetting
if (auto manufacturer = header.findTypedAttribute<Imf::StringAttribute>("lensMake")) { *
image.setText(QStringLiteral(META_KEY_LENS_MANUFACTURER), QString::fromStdString(manufacturer->value())); * - Support metadata-driven match move:
} * sensorCenterOffset, sensorOverallDimensions, sensorPhotositePitch, sensorAcquisitionRectanglenominalFocalLength,
if (auto model = header.findTypedAttribute<Imf::StringAttribute>("lensModel")) { * effectiveFocalLength, pinholeFocalLength, entrancePupilOffset, tStop(complementing existing 'aperture')
image.setText(QStringLiteral(META_KEY_LENS_MODEL), QString::fromStdString(model->value())); */
}
if (auto serial = header.findTypedAttribute<Imf::StringAttribute>("lensSerialNumber")) {
image.setText(QStringLiteral(META_KEY_LENS_SERIALNUMBER), QString::fromStdString(serial->value()));
}
} }
/*! /*!
@@ -507,26 +503,6 @@ static void setMetadata(const QImage &image, Imf::Header &header)
header.insert("xmp", Imf::StringAttribute(text.toStdString())); header.insert("xmp", Imf::StringAttribute(text.toStdString()));
} }
#endif #endif
if (!key.compare(QStringLiteral(META_KEY_MANUFACTURER), Qt::CaseInsensitive)) {
header.insert("cameraMake", Imf::StringAttribute(text.toStdString()));
}
if (!key.compare(QStringLiteral(META_KEY_MODEL), Qt::CaseInsensitive)) {
header.insert("cameraModel", Imf::StringAttribute(text.toStdString()));
}
if (!key.compare(QStringLiteral(META_KEY_SERIALNUMBER), Qt::CaseInsensitive)) {
header.insert("cameraSerialNumber", Imf::StringAttribute(text.toStdString()));
}
if (!key.compare(QStringLiteral(META_KEY_LENS_MANUFACTURER), Qt::CaseInsensitive)) {
header.insert("lensMake", Imf::StringAttribute(text.toStdString()));
}
if (!key.compare(QStringLiteral(META_KEY_LENS_MODEL), Qt::CaseInsensitive)) {
header.insert("lensModel", Imf::StringAttribute(text.toStdString()));
}
if (!key.compare(QStringLiteral(META_KEY_LENS_SERIALNUMBER), Qt::CaseInsensitive)) {
header.insert("lensSerialNumber", Imf::StringAttribute(text.toStdString()));
}
} }
if (dateTime.isValid()) { if (dateTime.isValid()) {
header.insert("capDate", Imf::StringAttribute(dateTime.toString(QStringLiteral("yyyy:MM:dd HH:mm:ss")).toStdString())); header.insert("capDate", Imf::StringAttribute(dateTime.toString(QStringLiteral("yyyy:MM:dd HH:mm:ss")).toStdString()));
@@ -543,6 +519,8 @@ static void setMetadata(const QImage &image, Imf::Header &header)
// If a file doesnt have a chromaticities attribute, display software should assume that the // If a file doesnt have a chromaticities attribute, display software should assume that the
// files primaries and the white point match Rec. ITU-R BT.709-3. // files primaries and the white point match Rec. ITU-R BT.709-3.
// header.insert("chromaticities", Imf::ChromaticitiesAttribute(Imf::Chromaticities())); // header.insert("chromaticities", Imf::ChromaticitiesAttribute(Imf::Chromaticities()));
// TODO: EXR 3.2 attributes (see readMetadata())
} }
bool EXRHandler::write(const QImage &image) bool EXRHandler::write(const QImage &image)

View File

@@ -16,19 +16,11 @@
#include <jxl/thread_parallel_runner.h> #include <jxl/thread_parallel_runner.h>
#include <string.h> #include <string.h>
// Avoid rotation on buggy Qts (see also https://bugreports.qt.io/browse/QTBUG-126575)
#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 7) && QT_VERSION < QT_VERSION_CHECK(6, 6, 0)) || (QT_VERSION >= QT_VERSION_CHECK(6, 7, 3))
#ifndef JXL_QT_AUTOTRANSFORM
#define JXL_QT_AUTOTRANSFORM
#endif
#endif
QJpegXLHandler::QJpegXLHandler() QJpegXLHandler::QJpegXLHandler()
: m_parseState(ParseJpegXLNotParsed) : m_parseState(ParseJpegXLNotParsed)
, m_quality(90) , m_quality(90)
, m_currentimage_index(0) , m_currentimage_index(0)
, m_previousimage_index(-1) , m_previousimage_index(-1)
, m_transformations(QImageIOHandler::TransformationNone)
, m_decoder(nullptr) , m_decoder(nullptr)
, m_runner(nullptr) , m_runner(nullptr)
, m_next_image_delay(0) , m_next_image_delay(0)
@@ -137,11 +129,6 @@ bool QJpegXLHandler::ensureDecoder()
return false; return false;
} }
#ifdef JXL_QT_AUTOTRANSFORM
// Let Qt handle the orientation.
JxlDecoderSetKeepOrientation(m_decoder, true);
#endif
int num_worker_threads = QThread::idealThreadCount(); int num_worker_threads = QThread::idealThreadCount();
if (!m_runner && num_worker_threads >= 4) { if (!m_runner && num_worker_threads >= 4) {
/* use half of the threads because plug-in is usually used in environment /* use half of the threads because plug-in is usually used in environment
@@ -581,25 +568,10 @@ bool QJpegXLHandler::write(const QImage &image)
pixel_format.endianness = JXL_NATIVE_ENDIAN; pixel_format.endianness = JXL_NATIVE_ENDIAN;
pixel_format.align = 0; pixel_format.align = 0;
output_info.orientation = JXL_ORIENT_IDENTITY;
output_info.num_color_channels = 3; output_info.num_color_channels = 3;
output_info.animation.tps_numerator = 10; output_info.animation.tps_numerator = 10;
output_info.animation.tps_denominator = 1; output_info.animation.tps_denominator = 1;
output_info.orientation = JXL_ORIENT_IDENTITY;
if (m_transformations == QImageIOHandler::TransformationMirror) {
output_info.orientation = JXL_ORIENT_FLIP_HORIZONTAL;
} else if (m_transformations == QImageIOHandler::TransformationRotate180) {
output_info.orientation = JXL_ORIENT_ROTATE_180;
} else if (m_transformations == QImageIOHandler::TransformationFlip) {
output_info.orientation = JXL_ORIENT_FLIP_VERTICAL;
} else if (m_transformations == QImageIOHandler::TransformationFlipAndRotate90) {
output_info.orientation = JXL_ORIENT_TRANSPOSE;
} else if (m_transformations == QImageIOHandler::TransformationRotate90) {
output_info.orientation = JXL_ORIENT_ROTATE_90_CW;
} else if (m_transformations == QImageIOHandler::TransformationMirrorAndRotate90) {
output_info.orientation = JXL_ORIENT_ANTI_TRANSPOSE;
} else if (m_transformations == QImageIOHandler::TransformationRotate270) {
output_info.orientation = JXL_ORIENT_ROTATE_90_CCW;
}
if (save_depth > 8) { // 16bit depth if (save_depth > 8) { // 16bit depth
pixel_format.data_type = JXL_TYPE_UINT16; pixel_format.data_type = JXL_TYPE_UINT16;
@@ -805,24 +777,14 @@ bool QJpegXLHandler::write(const QImage &image)
QVariant QJpegXLHandler::option(ImageOption option) const QVariant QJpegXLHandler::option(ImageOption option) const
{ {
if (!supportsOption(option)) {
return QVariant();
}
if (option == Quality) { if (option == Quality) {
return m_quality; return m_quality;
} }
if (!ensureParsed()) { if (!supportsOption(option) || !ensureParsed()) {
#ifdef JXL_QT_AUTOTRANSFORM
if (option == ImageTransformation) {
return int(m_transformations);
}
#endif
return QVariant(); return QVariant();
} }
switch (option) { switch (option) {
case Size: case Size:
return QSize(m_basicinfo.xsize, m_basicinfo.ysize); return QSize(m_basicinfo.xsize, m_basicinfo.ysize);
@@ -832,31 +794,9 @@ QVariant QJpegXLHandler::option(ImageOption option) const
} else { } else {
return false; return false;
} }
#ifdef JXL_QT_AUTOTRANSFORM
case ImageTransformation:
if (m_basicinfo.orientation == JXL_ORIENT_IDENTITY) {
return int(QImageIOHandler::TransformationNone);
} else if (m_basicinfo.orientation == JXL_ORIENT_FLIP_HORIZONTAL) {
return int(QImageIOHandler::TransformationMirror);
} else if (m_basicinfo.orientation == JXL_ORIENT_ROTATE_180) {
return int(QImageIOHandler::TransformationRotate180);
} else if (m_basicinfo.orientation == JXL_ORIENT_FLIP_VERTICAL) {
return int(QImageIOHandler::TransformationFlip);
} else if (m_basicinfo.orientation == JXL_ORIENT_TRANSPOSE) {
return int(QImageIOHandler::TransformationFlipAndRotate90);
} else if (m_basicinfo.orientation == JXL_ORIENT_ROTATE_90_CW) {
return int(QImageIOHandler::TransformationRotate90);
} else if (m_basicinfo.orientation == JXL_ORIENT_ANTI_TRANSPOSE) {
return int(QImageIOHandler::TransformationMirrorAndRotate90);
} else if (m_basicinfo.orientation == JXL_ORIENT_ROTATE_90_CCW) {
return int(QImageIOHandler::TransformationRotate270);
}
#endif
default: default:
return QVariant(); return QVariant();
} }
return QVariant();
} }
void QJpegXLHandler::setOption(ImageOption option, const QVariant &value) void QJpegXLHandler::setOption(ImageOption option, const QVariant &value)
@@ -870,14 +810,6 @@ void QJpegXLHandler::setOption(ImageOption option, const QVariant &value)
m_quality = 90; m_quality = 90;
} }
return; return;
#ifdef JXL_QT_AUTOTRANSFORM
case ImageTransformation:
if (auto t = value.toInt()) {
if (t > 0 && t < 8)
m_transformations = QImageIOHandler::Transformations(t);
}
break;
#endif
default: default:
break; break;
} }
@@ -886,11 +818,7 @@ void QJpegXLHandler::setOption(ImageOption option, const QVariant &value)
bool QJpegXLHandler::supportsOption(ImageOption option) const bool QJpegXLHandler::supportsOption(ImageOption option) const
{ {
auto supported = option == Quality || option == Size || option == Animation; return option == Quality || option == Size || option == Animation;
#ifdef JXL_QT_AUTOTRANSFORM
supported = supported || option == ImageTransformation;
#endif
return supported;
} }
int QJpegXLHandler::imageCount() const int QJpegXLHandler::imageCount() const

View File

@@ -64,7 +64,6 @@ private:
int m_quality; int m_quality;
int m_currentimage_index; int m_currentimage_index;
int m_previousimage_index; int m_previousimage_index;
QImageIOHandler::Transformations m_transformations;
QByteArray m_rawData; QByteArray m_rawData;

View File

@@ -308,11 +308,6 @@ static bool readImage4(QImage &img, QDataStream &s, const PCXHEADER &header)
return false; return false;
} }
if (header.BytesPerLine < (header.width() / 8)) {
qWarning() << "PCX image has invalid BytesPerLine value";
return false;
}
for (int y = 0; y < header.height(); ++y) { for (int y = 0; y < header.height(); ++y) {
if (s.atEnd()) { if (s.atEnd()) {
return false; return false;
@@ -349,47 +344,6 @@ static bool readImage4(QImage &img, QDataStream &s, const PCXHEADER &header)
return true; return true;
} }
static bool readImage4v2(QImage &img, QDataStream &s, const PCXHEADER &header)
{
QByteArray buf(header.BytesPerLine, 0);
img = imageAlloc(header.width(), header.height(), QImage::Format_Indexed8);
img.setColorCount(16);
if (img.isNull()) {
qWarning() << "Failed to allocate image, invalid dimensions?" << QSize(header.width(), header.height());
return false;
}
for (int y = 0; y < header.height(); ++y) {
if (s.atEnd()) {
return false;
}
if (!readLine(s, buf, header)) {
return false;
}
uchar *p = img.scanLine(y);
if (!p) {
return false;
}
const unsigned int bpl = std::min(header.BytesPerLine, static_cast<quint16>(header.width() / 2));
for (unsigned int x = 0; x < bpl; ++x) {
p[x * 2] = (buf[x] & 240) >> 4;
p[x * 2 + 1] = buf[x] & 15;
}
}
// Read the palette
for (int i = 0; i < 16; ++i) {
img.setColor(i, header.ColorMap.color(i));
}
return (s.status() == QDataStream::Ok);
}
static bool readImage8(QImage &img, QDataStream &s, const PCXHEADER &header) static bool readImage8(QImage &img, QDataStream &s, const PCXHEADER &header)
{ {
QByteArray buf(header.BytesPerLine, 0); QByteArray buf(header.BytesPerLine, 0);
@@ -464,8 +418,6 @@ static bool readImage24(QImage &img, QDataStream &s, const PCXHEADER &header)
return false; return false;
} }
const unsigned int bpl = std::min(header.BytesPerLine, static_cast<quint16>(header.width()));
for (int y = 0; y < header.height(); ++y) { for (int y = 0; y < header.height(); ++y) {
if (s.atEnd()) { if (s.atEnd()) {
return false; return false;
@@ -482,8 +434,7 @@ static bool readImage24(QImage &img, QDataStream &s, const PCXHEADER &header)
} }
uint *p = (uint *)img.scanLine(y); uint *p = (uint *)img.scanLine(y);
for (int x = 0; x < header.width(); ++x) {
for (unsigned int x = 0; x < bpl; ++x) {
p[x] = qRgb(r_buf[x], g_buf[x], b_buf[x]); p[x] = qRgb(r_buf[x], g_buf[x], b_buf[x]);
} }
} }
@@ -721,8 +672,6 @@ bool PCXHandler::read(QImage *outImage)
ok = readImage1(img, s, header); ok = readImage1(img, s, header);
} else if (header.Bpp == 1 && header.NPlanes == 4) { } else if (header.Bpp == 1 && header.NPlanes == 4) {
ok = readImage4(img, s, header); ok = readImage4(img, s, header);
} else if (header.Bpp == 4 && header.NPlanes == 1) {
ok = readImage4v2(img, s, header);
} else if (header.Bpp == 8 && header.NPlanes == 1) { } else if (header.Bpp == 8 && header.NPlanes == 1) {
ok = readImage8(img, s, header); ok = readImage8(img, s, header);
} else if (header.Bpp == 8 && header.NPlanes == 3) { } else if (header.Bpp == 8 && header.NPlanes == 3) {

View File

@@ -433,7 +433,7 @@ inline void rgbToRgbX(uchar *target, const uchar *source, qint32 targetSize, qin
#define T_FLAGS(a) (((a) >> 31) & 0x1) #define T_FLAGS(a) (((a) >> 31) & 0x1)
// clang-format on // clang-format on
#define DEFAULT_IMAGE_QUALITY (C_IQ(3) | C_OC(1) | C_CW(1) | C_AW(1) | C_BT(1) | C_HS(0) | C_FLAGS(1)) #define DEFAULT_QUALITY (C_IQ(3) | C_OC(1) | C_CW(1) | C_AW(1) | C_BT(1) | C_HS(0) | C_FLAGS(1))
void setParams(QImageIOHandler *handler, LibRaw *rawProcessor) void setParams(QImageIOHandler *handler, LibRaw *rawProcessor)
{ {
@@ -497,7 +497,7 @@ void setParams(QImageIOHandler *handler, LibRaw *rawProcessor)
quality |= C_FLAGS(1); quality |= C_FLAGS(1);
} }
if (quality == -1) { if (quality == -1) {
quality = DEFAULT_IMAGE_QUALITY; quality = DEFAULT_QUALITY;
} }
Q_ASSERT(T_FLAGS(quality)); Q_ASSERT(T_FLAGS(quality));

View File

@@ -24,22 +24,15 @@
#define META_KEY_HOSTCOMPUTER "HostComputer" #define META_KEY_HOSTCOMPUTER "HostComputer"
#define META_KEY_LATITUDE "Latitude" #define META_KEY_LATITUDE "Latitude"
#define META_KEY_LONGITUDE "Longitude" #define META_KEY_LONGITUDE "Longitude"
#define META_KEY_HOSTCOMPUTER "HostComputer"
#define META_KEY_MANUFACTURER "Manufacturer"
#define META_KEY_MODEL "Model"
#define META_KEY_OWNER "Owner" #define META_KEY_OWNER "Owner"
#define META_KEY_SOFTWARE "Software" #define META_KEY_SOFTWARE "Software"
#define META_KEY_TITLE "Title" #define META_KEY_TITLE "Title"
#define META_KEY_XML_GIMP "XML:org.gimp.xml" #define META_KEY_XML_GIMP "XML:org.gimp.xml"
#define META_KEY_XMP_ADOBE "XML:com.adobe.xmp" #define META_KEY_XMP_ADOBE "XML:com.adobe.xmp"
// Camera info metadata keys
#define META_KEY_MANUFACTURER "Manufacturer"
#define META_KEY_MODEL "Model"
#define META_KEY_SERIALNUMBER "SerialNumber"
// Lens info metadata keys
#define META_KEY_LENS_MANUFACTURER "LensManufacturer"
#define META_KEY_LENS_MODEL "LensModel"
#define META_KEY_LENS_SERIALNUMBER "LensSerialNumber"
// QList uses some extra space for stuff, hence the 32 here suggested by Thiago Macieira // QList uses some extra space for stuff, hence the 32 here suggested by Thiago Macieira
static constexpr int kMaxQVectorSize = std::numeric_limits<int>::max() - 32; static constexpr int kMaxQVectorSize = std::numeric_limits<int>::max() - 32;

View File

@@ -1672,12 +1672,8 @@ bool XCFImageFormat::assignImageBytes(Layer &layer, uint i, uint j, const GimpPr
for (int y = 0; y < height; y++) { for (int y = 0; y < height; y++) {
uchar *dataPtr = bits + y * bytesPerLine; uchar *dataPtr = bits + y * bytesPerLine;
uchar *alphaPtr = nullptr; uchar *alphaPtr = nullptr;
if (layer.alpha_tiles.size() > j && layer.alpha_tiles.at(j).size() > i) { if (!layer.alpha_tiles.isEmpty())
QImage &alphaTile = layer.alpha_tiles[j][i]; alphaPtr = layer.alpha_tiles[j][i].scanLine(y);
if (alphaTile.width() >= width && alphaTile.height() > y) {
alphaPtr = alphaTile.scanLine(y);
}
}
if (bpc == 4) { if (bpc == 4) {
#ifdef USE_FLOAT_IMAGES #ifdef USE_FLOAT_IMAGES
if (precision < GimpPrecision::GIMP_PRECISION_HALF_LINEAR) { if (precision < GimpPrecision::GIMP_PRECISION_HALF_LINEAR) {