EXR: Full support for gray image/colorspace

Starting with Qt 6.8, QColorSpace supports Gray and CMYK color profiles.

- On saving, grayscale images are converted to linear gray profile;
- On loading, a Grayscale image is stored in a QImage::Format_Grayscale16 instead a RGB one;
- ScanlineConverter class was updated to gray conversions.
This commit is contained in:
Mirco Miranda 2024-06-17 15:17:51 +00:00 committed by Albert Astals Cid
parent 63e21ee5f3
commit 81b7263d73
2 changed files with 45 additions and 1 deletions

View File

@ -99,6 +99,11 @@
#define EXR_USE_QT6_FLOAT_IMAGE // default uncommented
#endif
// Qt 6.8 allow to create and use Gray profile, so we can load a Gray image as Grayscale format instead RGB one.
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
#define EXR_GRAY_SUPPORT_ENABLED
#endif
class K_IStream : public Imf::IStream
{
public:
@ -248,10 +253,15 @@ bool EXRHandler::canRead() const
static QImage::Format imageFormat(const Imf::RgbaInputFile &file)
{
auto isRgba = file.channels() & Imf::RgbaChannels::WRITE_A;
#ifdef EXR_GRAY_SUPPORT_ENABLED
auto isGray = file.channels() & Imf::RgbaChannels::WRITE_Y;
#else
auto isGray = false;
#endif
#if defined(EXR_USE_LEGACY_CONVERSIONS)
return (isRgba ? QImage::Format_ARGB32 : QImage::Format_RGB32);
#elif defined(EXR_USE_QT6_FLOAT_IMAGE)
return (isRgba ? QImage::Format_RGBA16FPx4 : QImage::Format_RGBX16FPx4);
return (isRgba ? QImage::Format_RGBA16FPx4 : isGray ? QImage::Format_Grayscale16 : QImage::Format_RGBX16FPx4);
#else
return (isRgba ? QImage::Format_RGBA64 : QImage::Format_RGBX64);
#endif
@ -373,8 +383,17 @@ static void readColorSpace(const Imf::Header &header, QImage &image)
QColorSpace::TransferFunction::Linear);
}
if (!cs.isValid()) {
#ifdef EXR_GRAY_SUPPORT_ENABLED
if (image.format() == QImage::Format_Grayscale16 || image.format() == QImage::Format_Grayscale8) {
cs = QColorSpace(QPointF(0.31271, 0.32902), QColorSpace::TransferFunction::Linear);
cs.setDescription(QStringLiteral("Gray Linear build-in"));
} else {
cs = QColorSpace(QColorSpace::SRgbLinear);
}
#else
cs = QColorSpace(QColorSpace::SRgbLinear);
#endif
}
image.setColorSpace(cs);
#ifdef EXR_CONVERT_TO_SRGB
@ -443,6 +462,13 @@ bool EXRHandler::read(QImage *outImage)
file.readPixels(my, std::min(my + EXR_LINES_PER_BLOCK - 1, dw.max.y));
for (n = 0; n < std::min(EXR_LINES_PER_BLOCK, height - y); ++n) {
if (image.format() == QImage::Format_Grayscale16) { // grayscale image
auto scanLine = reinterpret_cast<quint16 *>(image.scanLine(y + n));
for (int x = 0; x < width; ++x) {
*(scanLine + x) = quint16(qBound(0.f, float(pixels[n][x].r) * 65535.f + 0.5f, 65535.f));
}
continue;
}
#if defined(EXR_USE_LEGACY_CONVERSIONS)
Q_UNUSED(isRgba)
auto scanLine = reinterpret_cast<QRgb *>(image.scanLine(y + n));
@ -639,7 +665,16 @@ bool EXRHandler::write(const QImage &image)
auto convFormat = image.hasAlphaChannel() ? QImage::Format_RGBA64 : QImage::Format_RGBX64;
#endif
ScanLineConverter slc(convFormat);
#ifdef EXR_GRAY_SUPPORT_ENABLED
if (channelsType == Imf::RgbaChannels::WRITE_Y) {
slc.setDefaultSourceColorSpace(QColorSpace(QColorSpace(QColorSpace::SRgb).whitePoint(), QColorSpace::TransferFunction::SRgb)); // Creates a custom grayscale color space
} else {
slc.setDefaultSourceColorSpace(QColorSpace(QColorSpace::SRgb));
}
#else
slc.setDefaultSourceColorSpace(QColorSpace(QColorSpace::SRgb));
#endif
slc.setTargetColorSpace(QColorSpace(QColorSpace::SRgbLinear));
for (int y = 0, n = 0; y < height; y += n) {
for (n = 0; n < std::min(EXR_LINES_PER_BLOCK, height - y); ++n) {

View File

@ -72,9 +72,18 @@ const uchar *ScanLineConverter::convertedScanLine(const QImage &image, qint32 y)
if (!cs.isValid()) {
cs = _defaultColorSpace;
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
if (tmp.depth() < 8 && cs.colorModel() == QColorSpace::ColorModel::Gray) {
tmp.convertTo(QImage::Format_Grayscale8);
}
else if (tmp.depth() < 24 && cs.colorModel() == QColorSpace::ColorModel::Rgb) {
tmp.convertTo(tmp.hasAlphaChannel() ? QImage::Format_ARGB32 : QImage::Format_RGB32);
}
#else
if (tmp.depth() < 24) {
tmp.convertTo(tmp.hasAlphaChannel() ? QImage::Format_ARGB32 : QImage::Format_RGB32);
}
#endif
tmp.setColorSpace(cs);
tmp.convertToColorSpace(_colorSpace);
}