blob: e17b2e2d0013b45a8deba31f0f32cbd302ecdbcb [file] [log] [blame]
// Copyright 2014 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
#include <memory>
#include "core/fxcodec/codec/codec_int.h"
#include "core/fxcodec/fx_codec.h"
#include "core/fxcrt/cfx_fixedbufgrow.h"
#if defined(USE_SYSTEM_LCMS2)
#include <lcms2.h>
#else
#include "third_party/lcms/include/lcms2.h"
#endif
namespace {
bool Check3Components(cmsColorSpaceSignature cs, bool bDst) {
switch (cs) {
case cmsSigGrayData:
return false;
case cmsSigCmykData:
if (bDst)
return false;
break;
case cmsSigLabData:
case cmsSigRgbData:
default:
break;
}
return true;
}
} // namespace
CLcmsCmm::CLcmsCmm(int srcComponents, cmsHTRANSFORM hTransform, bool isLab)
: m_hTransform(hTransform),
m_nSrcComponents(srcComponents),
m_bLab(isLab) {}
CLcmsCmm::~CLcmsCmm() {
cmsDeleteTransform(m_hTransform);
}
CCodec_IccModule::CCodec_IccModule() : m_nComponents(0) {}
CCodec_IccModule::~CCodec_IccModule() {}
std::unique_ptr<CLcmsCmm> CCodec_IccModule::CreateTransform_sRGB(
const unsigned char* pSrcProfileData,
uint32_t dwSrcProfileSize,
uint32_t* nSrcComponents) {
*nSrcComponents = 0;
cmsHPROFILE srcProfile =
cmsOpenProfileFromMem(pSrcProfileData, dwSrcProfileSize);
if (!srcProfile)
return nullptr;
cmsHPROFILE dstProfile;
dstProfile = cmsCreate_sRGBProfile();
if (!dstProfile) {
cmsCloseProfile(srcProfile);
return nullptr;
}
int srcFormat;
bool bLab = false;
cmsColorSpaceSignature srcCS = cmsGetColorSpace(srcProfile);
*nSrcComponents = cmsChannelsOf(srcCS);
// According to PDF spec, number of components must be 1, 3, or 4.
if (*nSrcComponents != 1 && *nSrcComponents != 3 && *nSrcComponents != 4) {
cmsCloseProfile(srcProfile);
cmsCloseProfile(dstProfile);
return nullptr;
}
if (srcCS == cmsSigLabData) {
srcFormat =
COLORSPACE_SH(PT_Lab) | CHANNELS_SH(*nSrcComponents) | BYTES_SH(0);
bLab = true;
} else {
srcFormat =
COLORSPACE_SH(PT_ANY) | CHANNELS_SH(*nSrcComponents) | BYTES_SH(1);
if (srcCS == cmsSigRgbData && T_DOSWAP(Icc_FORMAT_DEFAULT)) {
srcFormat |= DOSWAP_SH(1);
}
}
cmsColorSpaceSignature dstCS = cmsGetColorSpace(dstProfile);
if (!Check3Components(dstCS, true)) {
cmsCloseProfile(srcProfile);
cmsCloseProfile(dstProfile);
return nullptr;
}
cmsHTRANSFORM hTransform = nullptr;
int intent = 0;
switch (dstCS) {
case cmsSigGrayData:
hTransform = cmsCreateTransform(srcProfile, srcFormat, dstProfile,
TYPE_GRAY_8, intent, 0);
break;
case cmsSigRgbData:
hTransform = cmsCreateTransform(srcProfile, srcFormat, dstProfile,
TYPE_BGR_8, intent, 0);
break;
case cmsSigCmykData:
hTransform = cmsCreateTransform(
srcProfile, srcFormat, dstProfile,
T_DOSWAP(Icc_FORMAT_DEFAULT) ? TYPE_KYMC_8 : TYPE_CMYK_8, intent, 0);
break;
default:
break;
}
if (!hTransform) {
cmsCloseProfile(srcProfile);
cmsCloseProfile(dstProfile);
return nullptr;
}
auto pCmm = pdfium::MakeUnique<CLcmsCmm>(*nSrcComponents, hTransform, bLab);
cmsCloseProfile(srcProfile);
cmsCloseProfile(dstProfile);
return pCmm;
}
void CCodec_IccModule::Translate(CLcmsCmm* pTransform,
const float* pSrcValues,
float* pDestValues) {
if (!pTransform)
return;
uint32_t nSrcComponents = m_nComponents;
uint8_t output[4];
if (pTransform->m_bLab) {
CFX_FixedBufGrow<double, 16> inputs(nSrcComponents);
double* input = inputs;
for (uint32_t i = 0; i < nSrcComponents; ++i)
input[i] = pSrcValues[i];
cmsDoTransform(pTransform->m_hTransform, input, output, 1);
} else {
CFX_FixedBufGrow<uint8_t, 16> inputs(nSrcComponents);
uint8_t* input = inputs;
for (uint32_t i = 0; i < nSrcComponents; ++i) {
input[i] =
pdfium::clamp(static_cast<int>(pSrcValues[i] * 255.0f), 0, 255);
}
cmsDoTransform(pTransform->m_hTransform, input, output, 1);
}
pDestValues[0] = output[2] / 255.0f;
pDestValues[1] = output[1] / 255.0f;
pDestValues[2] = output[0] / 255.0f;
}
void CCodec_IccModule::TranslateScanline(CLcmsCmm* pTransform,
unsigned char* pDest,
const unsigned char* pSrc,
int32_t pixels) {
if (pTransform)
cmsDoTransform(pTransform->m_hTransform, pSrc, pDest, pixels);
}