Use lcms2 for color profiles
This commit is contained in:
+121
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user