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.
This commit is contained in:
Mirco Miranda
2024-06-20 15:45:08 +02:00
committed by Albert Astals Cid
parent 4c0f49295b
commit f5a6de7280
24 changed files with 715 additions and 309 deletions

View File

@ -109,7 +109,7 @@ public:
QImage::Format format() const
{
if (isValid()) {
return isBlackAndWhite() ? QImage::Format_Grayscale16 : QImage::Format_RGBX32FPx4;
return QImage::Format_RGBX32FPx4;
}
return QImage::Format_Invalid;
}
@ -155,7 +155,7 @@ public:
d->rollbackTransaction();
return ok;
}
} ;
};
class PFMHandlerPrivate
{
@ -215,42 +215,26 @@ bool PFMHandler::read(QImage *image)
}
for (auto y = 0, h = img.height(); y < h; ++y) {
float f;
if (header.isBlackAndWhite()) {
auto line = reinterpret_cast<quint16*>(img.scanLine(header.isPhotoshop() ? y : h - y - 1));
for (auto x = 0, w = img.width(); x < w; ++x) {
s >> f;
// QColorSpace does not handle gray linear profile, so I have to convert to non-linear
f = f < 0.0031308f ? (f * 12.92f) : (1.055 * std::pow(f, 1.0 / 2.4) - 0.055);
line[x] = quint16(std::clamp(f, float(0), float(1)) * std::numeric_limits<quint16>::max() + float(0.5));
if (s.status() != QDataStream::Ok) {
qCWarning(LOG_PFMPLUGIN) << "PFMHandler::read() detected corrupted data";
return false;
}
auto bw = header.isBlackAndWhite();
auto line = reinterpret_cast<float *>(img.scanLine(header.isPhotoshop() ? y : h - y - 1));
for (auto x = 0, n = img.width() * 4; x < n; x += 4) {
line[x + 3] = float(1);
s >> line[x];
if (bw) {
line[x + 1] = line[x];
line[x + 2] = line[x];
} else {
s >> line[x + 1];
s >> line[x + 2];
}
} else {
auto line = reinterpret_cast<float*>(img.scanLine(header.isPhotoshop() ? y : h - y - 1));
for (auto x = 0, n = img.width() * 4; x < n; x += 4) {
s >> f;
line[x] = std::clamp(f, float(0), float(1));
s >> f;
line[x + 1] = std::clamp(f, float(0), float(1));
s >> f;
line[x + 2] = std::clamp(f, float(0), float(1));
line[x + 3] = float(1);
if (s.status() != QDataStream::Ok) {
qCWarning(LOG_PFMPLUGIN) << "PFMHandler::read() detected corrupted data";
return false;
}
if (s.status() != QDataStream::Ok) {
qCWarning(LOG_PFMPLUGIN) << "PFMHandler::read() detected corrupted data";
return false;
}
}
}
if (!header.isBlackAndWhite()) {
img.setColorSpace(QColorSpace(QColorSpace::SRgbLinear));
}
img.setColorSpace(QColorSpace(QColorSpace::SRgbLinear));
*image = img;
return true;