Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
icc_transform.cpp
Go to the documentation of this file.
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/fxcodec/icc/icc_transform.h"
8
9#include <stdint.h>
10
11#include <algorithm>
12#include <memory>
13
14#include "core/fxcrt/data_vector.h"
15#include "third_party/base/memory/ptr_util.h"
16#include "third_party/base/notreached.h"
17#include "third_party/base/numerics/safe_conversions.h"
18
19namespace fxcodec {
20
21namespace {
22
23// For use with std::unique_ptr<cmsHPROFILE>.
24struct CmsProfileDeleter {
25 inline void operator()(cmsHPROFILE p) { cmsCloseProfile(p); }
26};
27
28using ScopedCmsProfile = std::unique_ptr<void, CmsProfileDeleter>;
29
30bool Check3Components(cmsColorSpaceSignature cs) {
31 switch (cs) {
32 case cmsSigGrayData:
33 case cmsSigCmykData:
34 return false;
35 default:
36 return true;
37 }
38}
39
40} // namespace
41
42IccTransform::IccTransform(cmsHTRANSFORM hTransform,
43 int srcComponents,
44 bool bIsLab,
45 bool bNormal)
46 : m_hTransform(hTransform),
47 m_nSrcComponents(srcComponents),
48 m_bLab(bIsLab),
49 m_bNormal(bNormal) {}
50
52 cmsDeleteTransform(m_hTransform);
53}
54
55// static
56std::unique_ptr<IccTransform> IccTransform::CreateTransformSRGB(
57 pdfium::span<const uint8_t> span) {
58 ScopedCmsProfile srcProfile(cmsOpenProfileFromMem(
59 span.data(), pdfium::base::checked_cast<cmsUInt32Number>(span.size())));
60 if (!srcProfile)
61 return nullptr;
62
63 ScopedCmsProfile dstProfile(cmsCreate_sRGBProfile());
64 if (!dstProfile)
65 return nullptr;
66
67 cmsColorSpaceSignature srcCS = cmsGetColorSpace(srcProfile.get());
68 uint32_t nSrcComponents = cmsChannelsOf(srcCS);
69
70 if (!IsValidIccComponents(nSrcComponents)) {
71 return nullptr;
72 }
73
74 int srcFormat;
75 bool bLab = false;
76 bool bNormal = false;
77 if (srcCS == cmsSigLabData) {
78 srcFormat =
79 COLORSPACE_SH(PT_Lab) | CHANNELS_SH(nSrcComponents) | BYTES_SH(0);
80 bLab = true;
81 } else {
82 srcFormat =
83 COLORSPACE_SH(PT_ANY) | CHANNELS_SH(nSrcComponents) | BYTES_SH(1);
84 // TODO(thestig): Check to see if lcms2 supports more colorspaces that can
85 // be considered normal.
86 bNormal = srcCS == cmsSigGrayData || srcCS == cmsSigRgbData ||
87 srcCS == cmsSigCmykData;
88 }
89 cmsColorSpaceSignature dstCS = cmsGetColorSpace(dstProfile.get());
90 if (!Check3Components(dstCS))
91 return nullptr;
92
93 cmsHTRANSFORM hTransform = nullptr;
94 switch (dstCS) {
95 case cmsSigRgbData:
96 hTransform =
97 cmsCreateTransform(srcProfile.get(), srcFormat, dstProfile.get(),
98 TYPE_BGR_8, INTENT_PERCEPTUAL, /*dwFlags=*/0);
99 break;
100 case cmsSigGrayData:
101 case cmsSigCmykData:
102 // Check3Components() already filtered these types.
103 NOTREACHED_NORETURN();
104 default:
105 break;
106 }
107 if (!hTransform)
108 return nullptr;
109
110 // Private ctor.
111 return pdfium::WrapUnique(
112 new IccTransform(hTransform, nSrcComponents, bLab, bNormal));
113}
114
115void IccTransform::Translate(pdfium::span<const float> pSrcValues,
116 pdfium::span<float> pDestValues) {
117 uint8_t output[4];
118 // TODO(npm): Currently the CmsDoTransform method is part of LCMS and it will
119 // apply some member of m_hTransform to the input. We need to go over all the
120 // places which set transform to verify that only `pSrcValues.size()`
121 // components are used.
122 if (m_bLab) {
123 DataVector<double> inputs(std::max<size_t>(pSrcValues.size(), 16));
124 for (uint32_t i = 0; i < pSrcValues.size(); ++i)
125 inputs[i] = pSrcValues[i];
126 cmsDoTransform(m_hTransform, inputs.data(), output, 1);
127 } else {
128 DataVector<uint8_t> inputs(std::max<size_t>(pSrcValues.size(), 16));
129 for (size_t i = 0; i < pSrcValues.size(); ++i) {
130 inputs[i] = std::clamp(static_cast<int>(pSrcValues[i] * 255.0f), 0, 255);
131 }
132 cmsDoTransform(m_hTransform, inputs.data(), output, 1);
133 }
134 pDestValues[0] = output[2] / 255.0f;
135 pDestValues[1] = output[1] / 255.0f;
136 pDestValues[2] = output[0] / 255.0f;
137}
138
139void IccTransform::TranslateScanline(pdfium::span<uint8_t> pDest,
140 pdfium::span<const uint8_t> pSrc,
141 int32_t pixels) {
142 cmsDoTransform(m_hTransform, pSrc.data(), pDest.data(), pixels);
143}
144
145// static
146bool IccTransform::IsValidIccComponents(int components) {
147 // According to PDF spec, number of components must be 1, 3, or 4.
148 return components == 1 || components == 3 || components == 4;
149}
150
151} // namespace fxcodec
static bool IsValidIccComponents(int components)
void Translate(pdfium::span< const float > pSrcValues, pdfium::span< float > pDestValues)
void TranslateScanline(pdfium::span< uint8_t > pDest, pdfium::span< const uint8_t > pSrc, int pixels)