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/fpdfapi/page/pageint.h"
8
9 #include <limits.h>
10
11 #include <algorithm>
12
13 #include "core/fpdfapi/cpdf_modulemgr.h"
14 #include "core/fpdfapi/parser/cpdf_array.h"
15 #include "core/fpdfapi/parser/cpdf_dictionary.h"
16 #include "core/fpdfapi/parser/cpdf_document.h"
17 #include "core/fpdfapi/parser/cpdf_stream.h"
18 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
19 #include "core/fpdfapi/parser/cpdf_string.h"
20 #include "core/fxcodec/fx_codec.h"
21
22 namespace {
23
NormalizeChannel(FX_FLOAT fVal)24 FX_FLOAT NormalizeChannel(FX_FLOAT fVal) {
25 return std::min(std::max(fVal, 0.0f), 1.0f);
26 }
27
28 } // namespace
29
ComponentsForFamily(int family)30 uint32_t ComponentsForFamily(int family) {
31 if (family == PDFCS_DEVICERGB)
32 return 3;
33 if (family == PDFCS_DEVICEGRAY)
34 return 1;
35 ASSERT(family == PDFCS_DEVICECMYK);
36 return 4;
37 }
38
sRGB_to_AdobeCMYK(FX_FLOAT R,FX_FLOAT G,FX_FLOAT B,FX_FLOAT & c,FX_FLOAT & m,FX_FLOAT & y,FX_FLOAT & k)39 void sRGB_to_AdobeCMYK(FX_FLOAT R,
40 FX_FLOAT G,
41 FX_FLOAT B,
42 FX_FLOAT& c,
43 FX_FLOAT& m,
44 FX_FLOAT& y,
45 FX_FLOAT& k) {
46 c = 1.0f - R;
47 m = 1.0f - G;
48 y = 1.0f - B;
49 k = c;
50 if (m < k) {
51 k = m;
52 }
53 if (y < k) {
54 k = y;
55 }
56 }
57
ReverseRGB(uint8_t * pDestBuf,const uint8_t * pSrcBuf,int pixels)58 void ReverseRGB(uint8_t* pDestBuf, const uint8_t* pSrcBuf, int pixels) {
59 if (pDestBuf == pSrcBuf) {
60 for (int i = 0; i < pixels; i++) {
61 uint8_t temp = pDestBuf[2];
62 pDestBuf[2] = pDestBuf[0];
63 pDestBuf[0] = temp;
64 pDestBuf += 3;
65 }
66 } else {
67 for (int i = 0; i < pixels; i++) {
68 *pDestBuf++ = pSrcBuf[2];
69 *pDestBuf++ = pSrcBuf[1];
70 *pDestBuf++ = pSrcBuf[0];
71 pSrcBuf += 3;
72 }
73 }
74 }
75
CPDF_DeviceCS(CPDF_Document * pDoc,int family)76 CPDF_DeviceCS::CPDF_DeviceCS(CPDF_Document* pDoc, int family)
77 : CPDF_ColorSpace(pDoc, family, ComponentsForFamily(family)) {
78 ASSERT(family == PDFCS_DEVICEGRAY || family == PDFCS_DEVICERGB ||
79 family == PDFCS_DEVICECMYK);
80 }
81
GetRGB(FX_FLOAT * pBuf,FX_FLOAT & R,FX_FLOAT & G,FX_FLOAT & B) const82 bool CPDF_DeviceCS::GetRGB(FX_FLOAT* pBuf,
83 FX_FLOAT& R,
84 FX_FLOAT& G,
85 FX_FLOAT& B) const {
86 switch (m_Family) {
87 case PDFCS_DEVICEGRAY:
88 R = NormalizeChannel(*pBuf);
89 G = R;
90 B = R;
91 break;
92 case PDFCS_DEVICERGB:
93 R = NormalizeChannel(pBuf[0]);
94 G = NormalizeChannel(pBuf[1]);
95 B = NormalizeChannel(pBuf[2]);
96 break;
97 case PDFCS_DEVICECMYK:
98 if (m_dwStdConversion) {
99 FX_FLOAT k = pBuf[3];
100 R = 1.0f - std::min(1.0f, pBuf[0] + k);
101 G = 1.0f - std::min(1.0f, pBuf[1] + k);
102 B = 1.0f - std::min(1.0f, pBuf[2] + k);
103 } else {
104 AdobeCMYK_to_sRGB(pBuf[0], pBuf[1], pBuf[2], pBuf[3], R, G, B);
105 }
106 break;
107 default:
108 ASSERT(false);
109 return false;
110 }
111 return true;
112 }
113
v_GetCMYK(FX_FLOAT * pBuf,FX_FLOAT & c,FX_FLOAT & m,FX_FLOAT & y,FX_FLOAT & k) const114 bool CPDF_DeviceCS::v_GetCMYK(FX_FLOAT* pBuf,
115 FX_FLOAT& c,
116 FX_FLOAT& m,
117 FX_FLOAT& y,
118 FX_FLOAT& k) const {
119 if (m_Family != PDFCS_DEVICECMYK)
120 return false;
121
122 c = pBuf[0];
123 m = pBuf[1];
124 y = pBuf[2];
125 k = pBuf[3];
126 return true;
127 }
128
SetRGB(FX_FLOAT * pBuf,FX_FLOAT R,FX_FLOAT G,FX_FLOAT B) const129 bool CPDF_DeviceCS::SetRGB(FX_FLOAT* pBuf,
130 FX_FLOAT R,
131 FX_FLOAT G,
132 FX_FLOAT B) const {
133 switch (m_Family) {
134 case PDFCS_DEVICEGRAY:
135 if (R != G || R != B)
136 return false;
137 *pBuf = R;
138 return true;
139 case PDFCS_DEVICERGB:
140 pBuf[0] = R;
141 pBuf[1] = G;
142 pBuf[2] = B;
143 return true;
144 case PDFCS_DEVICECMYK:
145 sRGB_to_AdobeCMYK(R, G, B, pBuf[0], pBuf[1], pBuf[2], pBuf[3]);
146 return true;
147 default:
148 ASSERT(false);
149 return false;
150 }
151 }
152
v_SetCMYK(FX_FLOAT * pBuf,FX_FLOAT c,FX_FLOAT m,FX_FLOAT y,FX_FLOAT k) const153 bool CPDF_DeviceCS::v_SetCMYK(FX_FLOAT* pBuf,
154 FX_FLOAT c,
155 FX_FLOAT m,
156 FX_FLOAT y,
157 FX_FLOAT k) const {
158 switch (m_Family) {
159 case PDFCS_DEVICEGRAY:
160 return false;
161 case PDFCS_DEVICERGB:
162 AdobeCMYK_to_sRGB(c, m, y, k, pBuf[0], pBuf[1], pBuf[2]);
163 return true;
164 case PDFCS_DEVICECMYK:
165 pBuf[0] = c;
166 pBuf[1] = m;
167 pBuf[2] = y;
168 pBuf[3] = k;
169 return true;
170 default:
171 ASSERT(false);
172 return false;
173 }
174 }
175
TranslateImageLine(uint8_t * pDestBuf,const uint8_t * pSrcBuf,int pixels,int image_width,int image_height,bool bTransMask) const176 void CPDF_DeviceCS::TranslateImageLine(uint8_t* pDestBuf,
177 const uint8_t* pSrcBuf,
178 int pixels,
179 int image_width,
180 int image_height,
181 bool bTransMask) const {
182 switch (m_Family) {
183 case PDFCS_DEVICEGRAY:
184 for (int i = 0; i < pixels; i++) {
185 *pDestBuf++ = pSrcBuf[i];
186 *pDestBuf++ = pSrcBuf[i];
187 *pDestBuf++ = pSrcBuf[i];
188 }
189 break;
190 case PDFCS_DEVICERGB:
191 ReverseRGB(pDestBuf, pSrcBuf, pixels);
192 break;
193 case PDFCS_DEVICECMYK:
194 if (bTransMask) {
195 for (int i = 0; i < pixels; i++) {
196 int k = 255 - pSrcBuf[3];
197 pDestBuf[0] = ((255 - pSrcBuf[0]) * k) / 255;
198 pDestBuf[1] = ((255 - pSrcBuf[1]) * k) / 255;
199 pDestBuf[2] = ((255 - pSrcBuf[2]) * k) / 255;
200 pDestBuf += 3;
201 pSrcBuf += 4;
202 }
203 } else {
204 for (int i = 0; i < pixels; i++) {
205 if (m_dwStdConversion) {
206 uint8_t k = pSrcBuf[3];
207 pDestBuf[2] = 255 - std::min(255, pSrcBuf[0] + k);
208 pDestBuf[1] = 255 - std::min(255, pSrcBuf[1] + k);
209 pDestBuf[0] = 255 - std::min(255, pSrcBuf[2] + k);
210 } else {
211 AdobeCMYK_to_sRGB1(pSrcBuf[0], pSrcBuf[1], pSrcBuf[2], pSrcBuf[3],
212 pDestBuf[2], pDestBuf[1], pDestBuf[0]);
213 }
214 pSrcBuf += 4;
215 pDestBuf += 3;
216 }
217 }
218 break;
219 default:
220 ASSERT(false);
221 break;
222 }
223 }
224
CPDF_IccProfile(const uint8_t * pData,uint32_t dwSize)225 CPDF_IccProfile::CPDF_IccProfile(const uint8_t* pData, uint32_t dwSize)
226 : m_bsRGB(false), m_pTransform(nullptr), m_nSrcComponents(0) {
227 if (dwSize == 3144 &&
228 FXSYS_memcmp(pData + 0x190, "sRGB IEC61966-2.1", 17) == 0) {
229 m_bsRGB = true;
230 m_nSrcComponents = 3;
231 } else if (CPDF_ModuleMgr::Get()->GetIccModule()) {
232 m_pTransform = CPDF_ModuleMgr::Get()->GetIccModule()->CreateTransform_sRGB(
233 pData, dwSize, m_nSrcComponents);
234 }
235 }
~CPDF_IccProfile()236 CPDF_IccProfile::~CPDF_IccProfile() {
237 if (m_pTransform) {
238 CPDF_ModuleMgr::Get()->GetIccModule()->DestroyTransform(m_pTransform);
239 }
240 }
241