1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include <memory>
8
9 #include "core/fxcodec/codec/ccodec_iccmodule.h"
10 #include "core/fxcodec/codec/codec_int.h"
11 #include "core/fxcrt/cfx_fixedbufgrow.h"
12
13 namespace {
14
Check3Components(cmsColorSpaceSignature cs,bool bDst)15 bool Check3Components(cmsColorSpaceSignature cs, bool bDst) {
16 switch (cs) {
17 case cmsSigGrayData:
18 return false;
19 case cmsSigCmykData:
20 if (bDst)
21 return false;
22 break;
23 case cmsSigLabData:
24 case cmsSigRgbData:
25 default:
26 break;
27 }
28 return true;
29 }
30
31 } // namespace
32
CLcmsCmm(int srcComponents,cmsHTRANSFORM hTransform,bool isLab)33 CLcmsCmm::CLcmsCmm(int srcComponents, cmsHTRANSFORM hTransform, bool isLab)
34 : m_hTransform(hTransform),
35 m_nSrcComponents(srcComponents),
36 m_bLab(isLab) {}
37
~CLcmsCmm()38 CLcmsCmm::~CLcmsCmm() {
39 cmsDeleteTransform(m_hTransform);
40 }
41
CCodec_IccModule()42 CCodec_IccModule::CCodec_IccModule() : m_nComponents(0) {}
43
~CCodec_IccModule()44 CCodec_IccModule::~CCodec_IccModule() {}
45
CreateTransform_sRGB(const unsigned char * pSrcProfileData,uint32_t dwSrcProfileSize,uint32_t * nSrcComponents)46 std::unique_ptr<CLcmsCmm> CCodec_IccModule::CreateTransform_sRGB(
47 const unsigned char* pSrcProfileData,
48 uint32_t dwSrcProfileSize,
49 uint32_t* nSrcComponents) {
50 *nSrcComponents = 0;
51 cmsHPROFILE srcProfile =
52 cmsOpenProfileFromMem(pSrcProfileData, dwSrcProfileSize);
53 if (!srcProfile)
54 return nullptr;
55
56 cmsHPROFILE dstProfile;
57 dstProfile = cmsCreate_sRGBProfile();
58 if (!dstProfile) {
59 cmsCloseProfile(srcProfile);
60 return nullptr;
61 }
62 int srcFormat;
63 bool bLab = false;
64 cmsColorSpaceSignature srcCS = cmsGetColorSpace(srcProfile);
65
66 *nSrcComponents = cmsChannelsOf(srcCS);
67 // According to PDF spec, number of components must be 1, 3, or 4.
68 if (*nSrcComponents != 1 && *nSrcComponents != 3 && *nSrcComponents != 4) {
69 cmsCloseProfile(srcProfile);
70 cmsCloseProfile(dstProfile);
71 return nullptr;
72 }
73
74 if (srcCS == cmsSigLabData) {
75 srcFormat =
76 COLORSPACE_SH(PT_Lab) | CHANNELS_SH(*nSrcComponents) | BYTES_SH(0);
77 bLab = true;
78 } else {
79 srcFormat =
80 COLORSPACE_SH(PT_ANY) | CHANNELS_SH(*nSrcComponents) | BYTES_SH(1);
81 }
82 cmsColorSpaceSignature dstCS = cmsGetColorSpace(dstProfile);
83 if (!Check3Components(dstCS, true)) {
84 cmsCloseProfile(srcProfile);
85 cmsCloseProfile(dstProfile);
86 return nullptr;
87 }
88
89 cmsHTRANSFORM hTransform = nullptr;
90 int intent = 0;
91 switch (dstCS) {
92 case cmsSigGrayData:
93 hTransform = cmsCreateTransform(srcProfile, srcFormat, dstProfile,
94 TYPE_GRAY_8, intent, 0);
95 break;
96 case cmsSigRgbData:
97 hTransform = cmsCreateTransform(srcProfile, srcFormat, dstProfile,
98 TYPE_BGR_8, intent, 0);
99 break;
100 case cmsSigCmykData:
101 hTransform = cmsCreateTransform(srcProfile, srcFormat, dstProfile,
102 TYPE_CMYK_8, intent, 0);
103 break;
104 default:
105 break;
106 }
107 if (!hTransform) {
108 cmsCloseProfile(srcProfile);
109 cmsCloseProfile(dstProfile);
110 return nullptr;
111 }
112 auto pCmm = pdfium::MakeUnique<CLcmsCmm>(*nSrcComponents, hTransform, bLab);
113 cmsCloseProfile(srcProfile);
114 cmsCloseProfile(dstProfile);
115 return pCmm;
116 }
117
Translate(CLcmsCmm * pTransform,const float * pSrcValues,float * pDestValues)118 void CCodec_IccModule::Translate(CLcmsCmm* pTransform,
119 const float* pSrcValues,
120 float* pDestValues) {
121 if (!pTransform)
122 return;
123
124 uint32_t nSrcComponents = m_nComponents;
125 uint8_t output[4];
126 if (pTransform->m_bLab) {
127 CFX_FixedBufGrow<double, 16> inputs(nSrcComponents);
128 double* input = inputs;
129 for (uint32_t i = 0; i < nSrcComponents; ++i)
130 input[i] = pSrcValues[i];
131 cmsDoTransform(pTransform->m_hTransform, input, output, 1);
132 } else {
133 CFX_FixedBufGrow<uint8_t, 16> inputs(nSrcComponents);
134 uint8_t* input = inputs;
135 for (uint32_t i = 0; i < nSrcComponents; ++i) {
136 input[i] =
137 pdfium::clamp(static_cast<int>(pSrcValues[i] * 255.0f), 0, 255);
138 }
139 cmsDoTransform(pTransform->m_hTransform, input, output, 1);
140 }
141 pDestValues[0] = output[2] / 255.0f;
142 pDestValues[1] = output[1] / 255.0f;
143 pDestValues[2] = output[0] / 255.0f;
144 }
145
TranslateScanline(CLcmsCmm * pTransform,unsigned char * pDest,const unsigned char * pSrc,int32_t pixels)146 void CCodec_IccModule::TranslateScanline(CLcmsCmm* pTransform,
147 unsigned char* pDest,
148 const unsigned char* pSrc,
149 int32_t pixels) {
150 if (pTransform)
151 cmsDoTransform(pTransform->m_hTransform, pSrc, pDest, pixels);
152 }
153