• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/fxcrt/check.h"
18 #include "core/fxcrt/compiler_specific.h"
19 #include "core/fxcrt/notreached.h"
20 #include "core/fxge/dib/cfx_cmyk_to_srgb.h"
21 
22 namespace {
23 
NormalizeChannel(float fVal)24 float NormalizeChannel(float fVal) {
25   return std::clamp(fVal, 0.0f, 1.0f);
26 }
27 
28 }  // namespace
29 
CPDF_DeviceCS(Family family)30 CPDF_DeviceCS::CPDF_DeviceCS(Family family) : CPDF_ColorSpace(family) {
31   DCHECK(family == Family::kDeviceGray || family == Family::kDeviceRGB ||
32          family == Family::kDeviceCMYK);
33   SetComponentsForStockCS(ComponentsForFamily(GetFamily()));
34 }
35 
36 CPDF_DeviceCS::~CPDF_DeviceCS() = default;
37 
v_Load(CPDF_Document * pDoc,const CPDF_Array * pArray,std::set<const CPDF_Object * > * pVisited)38 uint32_t CPDF_DeviceCS::v_Load(CPDF_Document* pDoc,
39                                const CPDF_Array* pArray,
40                                std::set<const CPDF_Object*>* pVisited) {
41   // Unlike other classes that inherit from CPDF_ColorSpace, CPDF_DeviceCS is
42   // never loaded by CPDF_ColorSpace.
43   NOTREACHED_NORETURN();
44 }
45 
GetRGB(pdfium::span<const float> pBuf) const46 std::optional<FX_RGB_STRUCT<float>> CPDF_DeviceCS::GetRGB(
47     pdfium::span<const float> pBuf) const {
48   switch (GetFamily()) {
49     case Family::kDeviceGray: {
50       const float pix = NormalizeChannel(pBuf.front());
51       return FX_RGB_STRUCT<float>{pix, pix, pix};
52     }
53     case Family::kDeviceRGB: {
54       const auto& rgb =
55           fxcrt::reinterpret_span<const FX_RGB_STRUCT<float>>(pBuf).front();
56       return FX_RGB_STRUCT<float>{
57           NormalizeChannel(rgb.red),
58           NormalizeChannel(rgb.green),
59           NormalizeChannel(rgb.blue),
60       };
61     }
62     case Family::kDeviceCMYK: {
63       const auto& cmyk =
64           fxcrt::reinterpret_span<const FX_CMYK_STRUCT<float>>(pBuf).front();
65       if (IsStdConversionEnabled()) {
66         return FX_RGB_STRUCT<float>{
67             1.0f - std::min(1.0f, cmyk.cyan + cmyk.key),
68             1.0f - std::min(1.0f, cmyk.magenta + cmyk.key),
69             1.0f - std::min(1.0f, cmyk.yellow + cmyk.key),
70         };
71       }
72       return AdobeCMYK_to_sRGB(
73           NormalizeChannel(cmyk.cyan), NormalizeChannel(cmyk.magenta),
74           NormalizeChannel(cmyk.yellow), NormalizeChannel(cmyk.key));
75     }
76     default:
77       NOTREACHED_NORETURN();
78   }
79 }
80 
TranslateImageLine(pdfium::span<uint8_t> dest_span,pdfium::span<const uint8_t> src_span,int pixels,int image_width,int image_height,bool bTransMask) const81 void CPDF_DeviceCS::TranslateImageLine(pdfium::span<uint8_t> dest_span,
82                                        pdfium::span<const uint8_t> src_span,
83                                        int pixels,
84                                        int image_width,
85                                        int image_height,
86                                        bool bTransMask) const {
87   auto rgb_out = fxcrt::reinterpret_span<FX_RGB_STRUCT<uint8_t>>(dest_span);
88   switch (GetFamily()) {
89     case Family::kDeviceGray:
90       CHECK(!bTransMask);  // bTransMask only allowed for CMYK colorspaces.
91       // Compiler can't conclude src/dest don't overlap, avoid interleaved
92       // loads and stores by not using an auto& reference here.
93       for (const auto pix : src_span.first(pixels)) {
94         rgb_out.front().red = pix;
95         rgb_out.front().green = pix;
96         rgb_out.front().blue = pix;
97         rgb_out = rgb_out.subspan(1);
98       }
99       break;
100     case Family::kDeviceRGB:
101       CHECK(!bTransMask);  // bTransMask only allowed for CMYK colorspaces.
102       fxcodec::ReverseRGB(dest_span, src_span, pixels);
103       break;
104     case Family::kDeviceCMYK: {
105       auto cmyk_in =
106           fxcrt::reinterpret_span<const FX_CMYK_STRUCT<uint8_t>>(src_span);
107       if (bTransMask) {
108         // Compiler can't conclude src/dest don't overlap, avoid interleaved
109         // loads and stores by not using an auto& reference here.
110         for (const auto cmyk : cmyk_in.first(pixels)) {
111           const int k = 255 - cmyk.key;
112           rgb_out.front().red = ((255 - cmyk.cyan) * k) / 255;
113           rgb_out.front().green = ((255 - cmyk.magenta) * k) / 255;
114           rgb_out.front().blue = ((255 - cmyk.yellow) * k) / 255;
115           rgb_out = rgb_out.subspan(1);
116         }
117         break;
118       }
119       if (IsStdConversionEnabled()) {
120         // Compiler can't conclude src/dest don't overlap, avoid interleaved
121         // loads and stores by not using am auto& reference here,
122         for (const auto cmyk : cmyk_in.first(pixels)) {
123           const uint8_t k = cmyk.key;
124           rgb_out.front().blue = 255 - std::min(255, cmyk.cyan + k);
125           rgb_out.front().green = 255 - std::min(255, cmyk.magenta + k);
126           rgb_out.front().red = 255 - std::min(255, cmyk.yellow + k);
127           rgb_out = rgb_out.subspan(1);
128         }
129         break;
130       }
131       for (const auto& cmyk : cmyk_in.first(pixels)) {
132         // TODO(tsepez): maybe this is a FX_BGR_STRUCT in reality?
133         FX_RGB_STRUCT<uint8_t> rgb =
134             AdobeCMYK_to_sRGB1(cmyk.cyan, cmyk.magenta, cmyk.yellow, cmyk.key);
135         rgb_out.front().red = rgb.blue;
136         rgb_out.front().green = rgb.green;
137         rgb_out.front().blue = rgb.red;
138         rgb_out = rgb_out.subspan(1);
139       }
140       break;
141     }
142     default:
143       NOTREACHED_NORETURN();
144   }
145 }
146