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 "core/fxcodec/icc/iccmodule.h"
8
9 #include <algorithm>
10 #include <memory>
11 #include <vector>
12
13 #include "third_party/base/ptr_util.h"
14 #include "third_party/base/stl_util.h"
15
16 namespace fxcodec {
17
18 namespace {
19
20 // For use with std::unique_ptr<cmsHPROFILE>.
21 struct CmsProfileDeleter {
operator ()fxcodec::__anon46bfc1530111::CmsProfileDeleter22 inline void operator()(cmsHPROFILE p) { cmsCloseProfile(p); }
23 };
24
25 using ScopedCmsProfile = std::unique_ptr<void, CmsProfileDeleter>;
26
Check3Components(cmsColorSpaceSignature cs)27 bool Check3Components(cmsColorSpaceSignature cs) {
28 switch (cs) {
29 case cmsSigGrayData:
30 case cmsSigCmykData:
31 return false;
32 default:
33 return true;
34 }
35 }
36
37 } // namespace
38
CLcmsCmm(cmsHTRANSFORM hTransform,int srcComponents,bool bIsLab,bool bNormal)39 CLcmsCmm::CLcmsCmm(cmsHTRANSFORM hTransform,
40 int srcComponents,
41 bool bIsLab,
42 bool bNormal)
43 : m_hTransform(hTransform),
44 m_nSrcComponents(srcComponents),
45 m_bLab(bIsLab),
46 m_bNormal(bNormal) {}
47
~CLcmsCmm()48 CLcmsCmm::~CLcmsCmm() {
49 cmsDeleteTransform(m_hTransform);
50 }
51
52 // static
CreateTransformSRGB(pdfium::span<const uint8_t> span)53 std::unique_ptr<CLcmsCmm> IccModule::CreateTransformSRGB(
54 pdfium::span<const uint8_t> span) {
55 ScopedCmsProfile srcProfile(cmsOpenProfileFromMem(span.data(), span.size()));
56 if (!srcProfile)
57 return nullptr;
58
59 ScopedCmsProfile dstProfile(cmsCreate_sRGBProfile());
60 if (!dstProfile)
61 return nullptr;
62
63 cmsColorSpaceSignature srcCS = cmsGetColorSpace(srcProfile.get());
64
65 uint32_t nSrcComponents = cmsChannelsOf(srcCS);
66 // According to PDF spec, number of components must be 1, 3, or 4.
67 if (nSrcComponents != 1 && nSrcComponents != 3 && nSrcComponents != 4)
68 return nullptr;
69
70 int srcFormat;
71 bool bLab = false;
72 bool bNormal = false;
73 if (srcCS == cmsSigLabData) {
74 srcFormat =
75 COLORSPACE_SH(PT_Lab) | CHANNELS_SH(nSrcComponents) | BYTES_SH(0);
76 bLab = true;
77 } else {
78 srcFormat =
79 COLORSPACE_SH(PT_ANY) | CHANNELS_SH(nSrcComponents) | BYTES_SH(1);
80 // TODO(thestig): Check to see if lcms2 supports more colorspaces that can
81 // be considered normal.
82 bNormal = srcCS == cmsSigGrayData || srcCS == cmsSigRgbData ||
83 srcCS == cmsSigCmykData;
84 }
85 cmsColorSpaceSignature dstCS = cmsGetColorSpace(dstProfile.get());
86 if (!Check3Components(dstCS))
87 return nullptr;
88
89 cmsHTRANSFORM hTransform = nullptr;
90 const int intent = 0;
91 switch (dstCS) {
92 case cmsSigRgbData:
93 hTransform = cmsCreateTransform(srcProfile.get(), srcFormat,
94 dstProfile.get(), TYPE_BGR_8, intent, 0);
95 break;
96 case cmsSigGrayData:
97 case cmsSigCmykData:
98 // Check3Components() already filtered these types.
99 NOTREACHED();
100 break;
101 default:
102 break;
103 }
104 if (!hTransform)
105 return nullptr;
106
107 return pdfium::MakeUnique<CLcmsCmm>(hTransform, nSrcComponents, bLab,
108 bNormal);
109 }
110
111 // static
Translate(CLcmsCmm * pTransform,uint32_t nSrcComponents,const float * pSrcValues,float * pDestValues)112 void IccModule::Translate(CLcmsCmm* pTransform,
113 uint32_t nSrcComponents,
114 const float* pSrcValues,
115 float* pDestValues) {
116 if (!pTransform)
117 return;
118
119 uint8_t output[4];
120 // TODO(npm): Currently the CmsDoTransform method is part of LCMS and it will
121 // apply some member of m_hTransform to the input. We need to go over all the
122 // places which set transform to verify that only |nSrcComponents| are used.
123 if (pTransform->IsLab()) {
124 std::vector<double> inputs(std::max(nSrcComponents, 16u));
125 for (uint32_t i = 0; i < nSrcComponents; ++i)
126 inputs[i] = pSrcValues[i];
127 cmsDoTransform(pTransform->transform(), inputs.data(), output, 1);
128 } else {
129 std::vector<uint8_t> inputs(std::max(nSrcComponents, 16u));
130 for (uint32_t i = 0; i < nSrcComponents; ++i) {
131 inputs[i] =
132 pdfium::clamp(static_cast<int>(pSrcValues[i] * 255.0f), 0, 255);
133 }
134 cmsDoTransform(pTransform->transform(), inputs.data(), output, 1);
135 }
136 pDestValues[0] = output[2] / 255.0f;
137 pDestValues[1] = output[1] / 255.0f;
138 pDestValues[2] = output[0] / 255.0f;
139 }
140
141 // static
TranslateScanline(CLcmsCmm * pTransform,unsigned char * pDest,const unsigned char * pSrc,int32_t pixels)142 void IccModule::TranslateScanline(CLcmsCmm* pTransform,
143 unsigned char* pDest,
144 const unsigned char* pSrc,
145 int32_t pixels) {
146 if (pTransform)
147 cmsDoTransform(pTransform->transform(), pSrc, pDest, pixels);
148 }
149
150 } // namespace fxcodec
151