Use lcms2 for color profiles

This commit is contained in:
2024-08-24 16:37:06 +02:00
parent ff5053b626
commit bc29dc7d34
8 changed files with 183 additions and 25 deletions
+121
View File
@@ -3,6 +3,7 @@
#include <cstring>
#include <QElapsedTimer>
#include <QFloat16>
#include <lcms2.h>
using F16 = qfloat16;
@@ -79,6 +80,7 @@ RawImage::RawImage(RawImage &&d)
RawImage::RawImage(const QImage &img)
{
qDebug() << img;
setICCProfile(img.colorSpace().iccProfile());
if(img.format() == QImage::Format_RGBX8888)
{
allocate(img.width(), img.height(), 3, UINT8);
@@ -828,3 +830,122 @@ bool RawImage::valid() const
{
return m_width > 0 && m_height > 0;
}
void RawImage::setICCProfile(const QByteArray &icc)
{
if(icc.size())
m_iccProfile = std::vector<uint8_t>(icc.begin(), icc.end());
}
void RawImage::setICCProfile(const LibXISF::ByteArray &icc)
{
if(icc.size())
m_iccProfile = std::vector<uint8_t>(icc.data(), icc.data() + icc.size());
}
void RawImage::convertTosRGB()
{
if(m_channels == 1 || m_iccProfile.empty())
return;
cmsUInt32Number type = TYPE_RGBA_8;
switch(m_type)
{
case UINT8:
type = TYPE_RGBA_8;
break;
case UINT16:
type = TYPE_RGBA_16;
break;
case FLOAT16:
type = TYPE_RGBA_HALF_FLT;
break;
case FLOAT32:
type = TYPE_RGBA_FLT;
break;
default:
return;
}
cmsHPROFILE inProfile = cmsOpenProfileFromMem(m_iccProfile.data(), m_iccProfile.size());
cmsHPROFILE outProfile = cmsCreate_sRGBProfile();
if(inProfile && outProfile)
{
cmsHTRANSFORM transform = cmsCreateTransform(inProfile, type, outProfile, type, INTENT_PERCEPTUAL, cmsFLAGS_COPY_ALPHA);
std::unique_ptr<PixelType[]> tmp = std::move(m_pixels);
allocate(m_width, m_height, m_channels, m_type);
if(transform)
{
cmsDoTransform(transform, tmp.get(), m_pixels.get(), size());
cmsDeleteTransform(transform);
}
else
{
qDebug() << "Failed to create color transform";
}
}
else
{
qDebug() << "Failed to open icc profile";
}
cmsCloseProfile(inProfile);
cmsCloseProfile(outProfile);
}
void RawImage::generateLUT()
{
if(m_channels == 1 || m_iccProfile.empty())
return;
const int LUT_SIZE = 32;
const float LUT_SIZEF = LUT_SIZE - 1;
std::vector<qfloat16> lut(LUT_SIZE * LUT_SIZE * LUT_SIZE * 4);
m_lut.resize(lut.size());
for(int z = 0; z < LUT_SIZE; z++)
{
for(int y = 0; y < LUT_SIZE; y++)
{
qfloat16 *line = &lut[(z*LUT_SIZE*LUT_SIZE + y*LUT_SIZE) * 4];
for(int x = 0; x < LUT_SIZE; x++)
{
line[x*4 + 0] = x / LUT_SIZEF;
line[x*4 + 1] = y / LUT_SIZEF;
line[x*4 + 2] = z / LUT_SIZEF;
line[x*4 + 3] = 1.0f;
}
}
}
cmsHPROFILE inProfile = cmsOpenProfileFromMem(m_iccProfile.data(), m_iccProfile.size());
cmsHPROFILE outProfile = cmsCreate_sRGBProfile();
if(inProfile && outProfile)
{
cmsHTRANSFORM transform = cmsCreateTransform(inProfile, TYPE_RGBA_HALF_FLT, outProfile, TYPE_RGBA_HALF_FLT, INTENT_PERCEPTUAL, cmsFLAGS_COPY_ALPHA);
if(transform)
{
cmsDoTransform(transform, &lut[0], &m_lut[0], lut.size()/4);
cmsDeleteTransform(transform);
}
else
{
qDebug() << "Failed to create color transform";
m_lut.clear();
}
}
else
{
qDebug() << "Failed to open icc profile";
m_lut.clear();
}
cmsCloseProfile(inProfile);
cmsCloseProfile(outProfile);
}
const std::vector<uint16_t> &RawImage::getLUT() const
{
return m_lut;
}