1 // Copyright 2014 The PDFium Authors
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/cpdf_devicecs.h"
8
9 #include <algorithm>
10
11 #include "core/fpdfapi/parser/cpdf_array.h"
12 #include "core/fpdfapi/parser/cpdf_dictionary.h"
13 #include "core/fpdfapi/parser/cpdf_document.h"
14 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
15 #include "core/fpdfapi/parser/cpdf_string.h"
16 #include "core/fxcodec/fx_codec.h"
17 #include "core/fxge/dib/cfx_cmyk_to_srgb.h"
18 #include "third_party/base/check.h"
19 #include "third_party/base/notreached.h"
20
21 namespace {
22
NormalizeChannel(float fVal)23 float NormalizeChannel(float fVal) {
24 return std::clamp(fVal, 0.0f, 1.0f);
25 }
26
27 } // namespace
28
CPDF_DeviceCS(Family family)29 CPDF_DeviceCS::CPDF_DeviceCS(Family family) : CPDF_ColorSpace(family) {
30 DCHECK(family == Family::kDeviceGray || family == Family::kDeviceRGB ||
31 family == Family::kDeviceCMYK);
32 SetComponentsForStockCS(ComponentsForFamily(GetFamily()));
33 }
34
35 CPDF_DeviceCS::~CPDF_DeviceCS() = default;
36
v_Load(CPDF_Document * pDoc,const CPDF_Array * pArray,std::set<const CPDF_Object * > * pVisited)37 uint32_t CPDF_DeviceCS::v_Load(CPDF_Document* pDoc,
38 const CPDF_Array* pArray,
39 std::set<const CPDF_Object*>* pVisited) {
40 // Unlike other classes that inherit from CPDF_ColorSpace, CPDF_DeviceCS is
41 // never loaded by CPDF_ColorSpace.
42 NOTREACHED_NORETURN();
43 }
44
GetRGB(pdfium::span<const float> pBuf,float * R,float * G,float * B) const45 bool CPDF_DeviceCS::GetRGB(pdfium::span<const float> pBuf,
46 float* R,
47 float* G,
48 float* B) const {
49 switch (GetFamily()) {
50 case Family::kDeviceGray:
51 *R = NormalizeChannel(pBuf[0]);
52 *G = *R;
53 *B = *R;
54 return true;
55 case Family::kDeviceRGB:
56 *R = NormalizeChannel(pBuf[0]);
57 *G = NormalizeChannel(pBuf[1]);
58 *B = NormalizeChannel(pBuf[2]);
59 return true;
60 case Family::kDeviceCMYK:
61 if (IsStdConversionEnabled()) {
62 float k = pBuf[3];
63 *R = 1.0f - std::min(1.0f, pBuf[0] + k);
64 *G = 1.0f - std::min(1.0f, pBuf[1] + k);
65 *B = 1.0f - std::min(1.0f, pBuf[2] + k);
66 } else {
67 std::tie(*R, *G, *B) = AdobeCMYK_to_sRGB(
68 NormalizeChannel(pBuf[0]), NormalizeChannel(pBuf[1]),
69 NormalizeChannel(pBuf[2]), NormalizeChannel(pBuf[3]));
70 }
71 return true;
72 default:
73 NOTREACHED_NORETURN();
74 }
75 }
76
TranslateImageLine(pdfium::span<uint8_t> dest_span,pdfium::span<const uint8_t> src_span,int pixels,int image_width,int image_height,bool bTransMask) const77 void CPDF_DeviceCS::TranslateImageLine(pdfium::span<uint8_t> dest_span,
78 pdfium::span<const uint8_t> src_span,
79 int pixels,
80 int image_width,
81 int image_height,
82 bool bTransMask) const {
83 uint8_t* pDestBuf = dest_span.data();
84 const uint8_t* pSrcBuf = src_span.data();
85 switch (GetFamily()) {
86 case Family::kDeviceGray:
87 for (int i = 0; i < pixels; i++) {
88 // Compiler can not conclude that src/dest don't overlap, avoid
89 // duplicate loads.
90 const uint8_t pix = pSrcBuf[i];
91 *pDestBuf++ = pix;
92 *pDestBuf++ = pix;
93 *pDestBuf++ = pix;
94 }
95 break;
96 case Family::kDeviceRGB:
97 fxcodec::ReverseRGB(pDestBuf, pSrcBuf, pixels);
98 break;
99 case Family::kDeviceCMYK:
100 if (bTransMask) {
101 for (int i = 0; i < pixels; i++) {
102 // Compiler can't conclude src/dest don't overlap, avoid interleaved
103 // loads and stores.
104 const uint8_t s0 = pSrcBuf[0];
105 const uint8_t s1 = pSrcBuf[1];
106 const uint8_t s2 = pSrcBuf[2];
107 const int k = 255 - pSrcBuf[3];
108 pDestBuf[0] = ((255 - s0) * k) / 255;
109 pDestBuf[1] = ((255 - s1) * k) / 255;
110 pDestBuf[2] = ((255 - s2) * k) / 255;
111 pDestBuf += 3;
112 pSrcBuf += 4;
113 }
114 } else {
115 if (IsStdConversionEnabled()) {
116 for (int i = 0; i < pixels; i++) {
117 // Compiler can't conclude src/dest don't overlap, avoid
118 // interleaved loads and stores.
119 const uint8_t s0 = pSrcBuf[0];
120 const uint8_t s1 = pSrcBuf[1];
121 const uint8_t s2 = pSrcBuf[2];
122 const uint8_t k = pSrcBuf[3];
123 pDestBuf[2] = 255 - std::min(255, s0 + k);
124 pDestBuf[1] = 255 - std::min(255, s1 + k);
125 pDestBuf[0] = 255 - std::min(255, s2 + k);
126 pSrcBuf += 4;
127 pDestBuf += 3;
128 }
129 } else {
130 for (int i = 0; i < pixels; i++) {
131 std::tie(pDestBuf[2], pDestBuf[1], pDestBuf[0]) =
132 AdobeCMYK_to_sRGB1(pSrcBuf[0], pSrcBuf[1], pSrcBuf[2],
133 pSrcBuf[3]);
134 pSrcBuf += 4;
135 pDestBuf += 3;
136 }
137 }
138 }
139 break;
140 default:
141 NOTREACHED_NORETURN();
142 }
143 }
144