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 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 33 CLcmsCmm::CLcmsCmm(int srcComponents, cmsHTRANSFORM hTransform, bool isLab) 34 : m_hTransform(hTransform), 35 m_nSrcComponents(srcComponents), 36 m_bLab(isLab) {} 37 38 CLcmsCmm::~CLcmsCmm() { 39 cmsDeleteTransform(m_hTransform); 40 } 41 42 CCodec_IccModule::CCodec_IccModule() : m_nComponents(0) {} 43 44 CCodec_IccModule::~CCodec_IccModule() {} 45 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 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 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