• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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