xref: /aosp_15_r20/external/libultrahdr/lib/include/ultrahdr/icc.h (revision 89a0ef05262152531a00a15832a2d3b1e3990773)
1*89a0ef05SAndroid Build Coastguard Worker /*
2*89a0ef05SAndroid Build Coastguard Worker  * Copyright 2022 The Android Open Source Project
3*89a0ef05SAndroid Build Coastguard Worker  *
4*89a0ef05SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*89a0ef05SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*89a0ef05SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*89a0ef05SAndroid Build Coastguard Worker  *
8*89a0ef05SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*89a0ef05SAndroid Build Coastguard Worker  *
10*89a0ef05SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*89a0ef05SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*89a0ef05SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*89a0ef05SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*89a0ef05SAndroid Build Coastguard Worker  * limitations under the License.
15*89a0ef05SAndroid Build Coastguard Worker  */
16*89a0ef05SAndroid Build Coastguard Worker 
17*89a0ef05SAndroid Build Coastguard Worker #ifndef ULTRAHDR_ICC_H
18*89a0ef05SAndroid Build Coastguard Worker #define ULTRAHDR_ICC_H
19*89a0ef05SAndroid Build Coastguard Worker 
20*89a0ef05SAndroid Build Coastguard Worker #include <memory>
21*89a0ef05SAndroid Build Coastguard Worker 
22*89a0ef05SAndroid Build Coastguard Worker #ifndef USE_BIG_ENDIAN_IN_ICC
23*89a0ef05SAndroid Build Coastguard Worker #define USE_BIG_ENDIAN_IN_ICC true
24*89a0ef05SAndroid Build Coastguard Worker #endif
25*89a0ef05SAndroid Build Coastguard Worker 
26*89a0ef05SAndroid Build Coastguard Worker #undef Endian_SwapBE32
27*89a0ef05SAndroid Build Coastguard Worker #undef Endian_SwapBE16
28*89a0ef05SAndroid Build Coastguard Worker #if USE_BIG_ENDIAN_IN_ICC
29*89a0ef05SAndroid Build Coastguard Worker #define Endian_SwapBE32(n) EndianSwap32(n)
30*89a0ef05SAndroid Build Coastguard Worker #define Endian_SwapBE16(n) EndianSwap16(n)
31*89a0ef05SAndroid Build Coastguard Worker #else
32*89a0ef05SAndroid Build Coastguard Worker #define Endian_SwapBE32(n) (n)
33*89a0ef05SAndroid Build Coastguard Worker #define Endian_SwapBE16(n) (n)
34*89a0ef05SAndroid Build Coastguard Worker #endif
35*89a0ef05SAndroid Build Coastguard Worker 
36*89a0ef05SAndroid Build Coastguard Worker #include "ultrahdr/jpegr.h"
37*89a0ef05SAndroid Build Coastguard Worker #include "ultrahdr/gainmapmath.h"
38*89a0ef05SAndroid Build Coastguard Worker #include "ultrahdr/jpegrutils.h"
39*89a0ef05SAndroid Build Coastguard Worker 
40*89a0ef05SAndroid Build Coastguard Worker namespace ultrahdr {
41*89a0ef05SAndroid Build Coastguard Worker 
42*89a0ef05SAndroid Build Coastguard Worker typedef int32_t Fixed;
43*89a0ef05SAndroid Build Coastguard Worker #define Fixed1 (1 << 16)
44*89a0ef05SAndroid Build Coastguard Worker #define MaxS32FitsInFloat 2147483520
45*89a0ef05SAndroid Build Coastguard Worker #define MinS32FitsInFloat (-MaxS32FitsInFloat)
46*89a0ef05SAndroid Build Coastguard Worker #define FixedToFloat(x) ((x)*1.52587890625e-5f)
47*89a0ef05SAndroid Build Coastguard Worker 
48*89a0ef05SAndroid Build Coastguard Worker typedef struct Matrix3x3 {
49*89a0ef05SAndroid Build Coastguard Worker   float vals[3][3];
50*89a0ef05SAndroid Build Coastguard Worker } Matrix3x3;
51*89a0ef05SAndroid Build Coastguard Worker 
52*89a0ef05SAndroid Build Coastguard Worker // A transfer function mapping encoded values to linear values,
53*89a0ef05SAndroid Build Coastguard Worker // represented by this 7-parameter piecewise function:
54*89a0ef05SAndroid Build Coastguard Worker //
55*89a0ef05SAndroid Build Coastguard Worker //   linear = sign(encoded) *  (c*|encoded| + f)       , 0 <= |encoded| < d
56*89a0ef05SAndroid Build Coastguard Worker //          = sign(encoded) * ((a*|encoded| + b)^g + e), d <= |encoded|
57*89a0ef05SAndroid Build Coastguard Worker //
58*89a0ef05SAndroid Build Coastguard Worker // (A simple gamma transfer function sets g to gamma and a to 1.)
59*89a0ef05SAndroid Build Coastguard Worker typedef struct TransferFunction {
60*89a0ef05SAndroid Build Coastguard Worker   float g, a, b, c, d, e, f;
61*89a0ef05SAndroid Build Coastguard Worker } TransferFunction;
62*89a0ef05SAndroid Build Coastguard Worker 
63*89a0ef05SAndroid Build Coastguard Worker static constexpr TransferFunction kSRGB_TransFun = {
64*89a0ef05SAndroid Build Coastguard Worker     2.4f, (float)(1 / 1.055), (float)(0.055 / 1.055), (float)(1 / 12.92), 0.04045f, 0.0f, 0.0f};
65*89a0ef05SAndroid Build Coastguard Worker 
66*89a0ef05SAndroid Build Coastguard Worker static constexpr TransferFunction kLinear_TransFun = {1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
67*89a0ef05SAndroid Build Coastguard Worker 
68*89a0ef05SAndroid Build Coastguard Worker // The D50 illuminant.
69*89a0ef05SAndroid Build Coastguard Worker constexpr float kD50_x = 0.9642f;
70*89a0ef05SAndroid Build Coastguard Worker constexpr float kD50_y = 1.0000f;
71*89a0ef05SAndroid Build Coastguard Worker constexpr float kD50_z = 0.8249f;
72*89a0ef05SAndroid Build Coastguard Worker 
73*89a0ef05SAndroid Build Coastguard Worker enum {
74*89a0ef05SAndroid Build Coastguard Worker   // data_color_space
75*89a0ef05SAndroid Build Coastguard Worker   Signature_CMYK = 0x434D594B,
76*89a0ef05SAndroid Build Coastguard Worker   Signature_Gray = 0x47524159,
77*89a0ef05SAndroid Build Coastguard Worker   Signature_RGB = 0x52474220,
78*89a0ef05SAndroid Build Coastguard Worker 
79*89a0ef05SAndroid Build Coastguard Worker   // pcs
80*89a0ef05SAndroid Build Coastguard Worker   Signature_Lab = 0x4C616220,
81*89a0ef05SAndroid Build Coastguard Worker   Signature_XYZ = 0x58595A20,
82*89a0ef05SAndroid Build Coastguard Worker };
83*89a0ef05SAndroid Build Coastguard Worker 
84*89a0ef05SAndroid Build Coastguard Worker typedef uint32_t FourByteTag;
SetFourByteTag(char a,char b,char c,char d)85*89a0ef05SAndroid Build Coastguard Worker static inline constexpr FourByteTag SetFourByteTag(char a, char b, char c, char d) {
86*89a0ef05SAndroid Build Coastguard Worker   return (((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8) | (uint32_t)d);
87*89a0ef05SAndroid Build Coastguard Worker }
88*89a0ef05SAndroid Build Coastguard Worker 
89*89a0ef05SAndroid Build Coastguard Worker static constexpr char kICCIdentifier[] = "ICC_PROFILE";
90*89a0ef05SAndroid Build Coastguard Worker // 12 for the actual identifier, +2 for the chunk count and chunk index which
91*89a0ef05SAndroid Build Coastguard Worker // will always follow.
92*89a0ef05SAndroid Build Coastguard Worker static constexpr size_t kICCIdentifierSize = 14;
93*89a0ef05SAndroid Build Coastguard Worker 
94*89a0ef05SAndroid Build Coastguard Worker // This is equal to the header size according to the ICC specification (128)
95*89a0ef05SAndroid Build Coastguard Worker // plus the size of the tag count (4).  We include the tag count since we
96*89a0ef05SAndroid Build Coastguard Worker // always require it to be present anyway.
97*89a0ef05SAndroid Build Coastguard Worker static constexpr size_t kICCHeaderSize = 132;
98*89a0ef05SAndroid Build Coastguard Worker 
99*89a0ef05SAndroid Build Coastguard Worker // Contains a signature (4), offset (4), and size (4).
100*89a0ef05SAndroid Build Coastguard Worker static constexpr size_t kICCTagTableEntrySize = 12;
101*89a0ef05SAndroid Build Coastguard Worker 
102*89a0ef05SAndroid Build Coastguard Worker // size should be 20; 4 bytes for type descriptor, 4 bytes reserved, 12
103*89a0ef05SAndroid Build Coastguard Worker // bytes for a single XYZ number type (4 bytes per coordinate).
104*89a0ef05SAndroid Build Coastguard Worker static constexpr size_t kColorantTagSize = 20;
105*89a0ef05SAndroid Build Coastguard Worker 
106*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kDisplay_Profile = SetFourByteTag('m', 'n', 't', 'r');
107*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kRGB_ColorSpace = SetFourByteTag('R', 'G', 'B', ' ');
108*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kXYZ_PCSSpace = SetFourByteTag('X', 'Y', 'Z', ' ');
109*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kACSP_Signature = SetFourByteTag('a', 'c', 's', 'p');
110*89a0ef05SAndroid Build Coastguard Worker 
111*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kTAG_desc = SetFourByteTag('d', 'e', 's', 'c');
112*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kTAG_TextType = SetFourByteTag('m', 'l', 'u', 'c');
113*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kTAG_rXYZ = SetFourByteTag('r', 'X', 'Y', 'Z');
114*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kTAG_gXYZ = SetFourByteTag('g', 'X', 'Y', 'Z');
115*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kTAG_bXYZ = SetFourByteTag('b', 'X', 'Y', 'Z');
116*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kTAG_wtpt = SetFourByteTag('w', 't', 'p', 't');
117*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kTAG_rTRC = SetFourByteTag('r', 'T', 'R', 'C');
118*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kTAG_gTRC = SetFourByteTag('g', 'T', 'R', 'C');
119*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kTAG_bTRC = SetFourByteTag('b', 'T', 'R', 'C');
120*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kTAG_cicp = SetFourByteTag('c', 'i', 'c', 'p');
121*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kTAG_cprt = SetFourByteTag('c', 'p', 'r', 't');
122*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kTAG_A2B0 = SetFourByteTag('A', '2', 'B', '0');
123*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kTAG_B2A0 = SetFourByteTag('B', '2', 'A', '0');
124*89a0ef05SAndroid Build Coastguard Worker 
125*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kTAG_CurveType = SetFourByteTag('c', 'u', 'r', 'v');
126*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kTAG_mABType = SetFourByteTag('m', 'A', 'B', ' ');
127*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kTAG_mBAType = SetFourByteTag('m', 'B', 'A', ' ');
128*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kTAG_ParaCurveType = SetFourByteTag('p', 'a', 'r', 'a');
129*89a0ef05SAndroid Build Coastguard Worker 
130*89a0ef05SAndroid Build Coastguard Worker static constexpr Matrix3x3 kSRGB = {{
131*89a0ef05SAndroid Build Coastguard Worker     // ICC fixed-point (16.16) representation, taken from skcms. Please keep them exactly in sync.
132*89a0ef05SAndroid Build Coastguard Worker     // 0.436065674f, 0.385147095f, 0.143066406f,
133*89a0ef05SAndroid Build Coastguard Worker     // 0.222488403f, 0.716873169f, 0.060607910f,
134*89a0ef05SAndroid Build Coastguard Worker     // 0.013916016f, 0.097076416f, 0.714096069f,
135*89a0ef05SAndroid Build Coastguard Worker     {FixedToFloat(0x6FA2), FixedToFloat(0x6299), FixedToFloat(0x24A0)},
136*89a0ef05SAndroid Build Coastguard Worker     {FixedToFloat(0x38F5), FixedToFloat(0xB785), FixedToFloat(0x0F84)},
137*89a0ef05SAndroid Build Coastguard Worker     {FixedToFloat(0x0390), FixedToFloat(0x18DA), FixedToFloat(0xB6CF)},
138*89a0ef05SAndroid Build Coastguard Worker }};
139*89a0ef05SAndroid Build Coastguard Worker 
140*89a0ef05SAndroid Build Coastguard Worker static constexpr Matrix3x3 kDisplayP3 = {{
141*89a0ef05SAndroid Build Coastguard Worker     {0.515102f, 0.291965f, 0.157153f},
142*89a0ef05SAndroid Build Coastguard Worker     {0.241182f, 0.692236f, 0.0665819f},
143*89a0ef05SAndroid Build Coastguard Worker     {-0.00104941f, 0.0418818f, 0.784378f},
144*89a0ef05SAndroid Build Coastguard Worker }};
145*89a0ef05SAndroid Build Coastguard Worker 
146*89a0ef05SAndroid Build Coastguard Worker static constexpr Matrix3x3 kRec2020 = {{
147*89a0ef05SAndroid Build Coastguard Worker     {0.673459f, 0.165661f, 0.125100f},
148*89a0ef05SAndroid Build Coastguard Worker     {0.279033f, 0.675338f, 0.0456288f},
149*89a0ef05SAndroid Build Coastguard Worker     {-0.00193139f, 0.0299794f, 0.797162f},
150*89a0ef05SAndroid Build Coastguard Worker }};
151*89a0ef05SAndroid Build Coastguard Worker 
152*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kCICPPrimariesSRGB = 1;
153*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kCICPPrimariesP3 = 12;
154*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kCICPPrimariesRec2020 = 9;
155*89a0ef05SAndroid Build Coastguard Worker 
156*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kCICPTrfnSRGB = 1;
157*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kCICPTrfnLinear = 8;
158*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kCICPTrfnPQ = 16;
159*89a0ef05SAndroid Build Coastguard Worker static constexpr uint32_t kCICPTrfnHLG = 18;
160*89a0ef05SAndroid Build Coastguard Worker 
161*89a0ef05SAndroid Build Coastguard Worker enum ParaCurveType {
162*89a0ef05SAndroid Build Coastguard Worker   kExponential_ParaCurveType = 0,
163*89a0ef05SAndroid Build Coastguard Worker   kGAB_ParaCurveType = 1,
164*89a0ef05SAndroid Build Coastguard Worker   kGABC_ParaCurveType = 2,
165*89a0ef05SAndroid Build Coastguard Worker   kGABDE_ParaCurveType = 3,
166*89a0ef05SAndroid Build Coastguard Worker   kGABCDEF_ParaCurveType = 4,
167*89a0ef05SAndroid Build Coastguard Worker };
168*89a0ef05SAndroid Build Coastguard Worker 
169*89a0ef05SAndroid Build Coastguard Worker /**
170*89a0ef05SAndroid Build Coastguard Worker  *  Return the closest int for the given float. Returns MaxS32FitsInFloat for NaN.
171*89a0ef05SAndroid Build Coastguard Worker  */
float_saturate2int(float x)172*89a0ef05SAndroid Build Coastguard Worker static inline int float_saturate2int(float x) {
173*89a0ef05SAndroid Build Coastguard Worker   x = x < MaxS32FitsInFloat ? x : MaxS32FitsInFloat;
174*89a0ef05SAndroid Build Coastguard Worker   x = x > MinS32FitsInFloat ? x : MinS32FitsInFloat;
175*89a0ef05SAndroid Build Coastguard Worker   return (int)x;
176*89a0ef05SAndroid Build Coastguard Worker }
177*89a0ef05SAndroid Build Coastguard Worker 
float_round_to_fixed(float x)178*89a0ef05SAndroid Build Coastguard Worker static inline Fixed float_round_to_fixed(float x) {
179*89a0ef05SAndroid Build Coastguard Worker   return float_saturate2int((float)floor((double)x * Fixed1 + 0.5));
180*89a0ef05SAndroid Build Coastguard Worker }
181*89a0ef05SAndroid Build Coastguard Worker 
float_round_to_unorm16(float x)182*89a0ef05SAndroid Build Coastguard Worker static inline uint16_t float_round_to_unorm16(float x) {
183*89a0ef05SAndroid Build Coastguard Worker   x = x * 65535.f + 0.5f;
184*89a0ef05SAndroid Build Coastguard Worker   if (x > 65535) return 65535;
185*89a0ef05SAndroid Build Coastguard Worker   if (x < 0) return 0;
186*89a0ef05SAndroid Build Coastguard Worker   return static_cast<uint16_t>(x);
187*89a0ef05SAndroid Build Coastguard Worker }
188*89a0ef05SAndroid Build Coastguard Worker 
float_to_table16(const float f,uint8_t * table_16)189*89a0ef05SAndroid Build Coastguard Worker static inline void float_to_table16(const float f, uint8_t* table_16) {
190*89a0ef05SAndroid Build Coastguard Worker   *reinterpret_cast<uint16_t*>(table_16) = Endian_SwapBE16(float_round_to_unorm16(f));
191*89a0ef05SAndroid Build Coastguard Worker }
192*89a0ef05SAndroid Build Coastguard Worker 
isfinitef_(float x)193*89a0ef05SAndroid Build Coastguard Worker static inline bool isfinitef_(float x) { return 0 == x * 0; }
194*89a0ef05SAndroid Build Coastguard Worker 
195*89a0ef05SAndroid Build Coastguard Worker struct ICCHeader {
196*89a0ef05SAndroid Build Coastguard Worker   // Size of the profile (computed)
197*89a0ef05SAndroid Build Coastguard Worker   uint32_t size;
198*89a0ef05SAndroid Build Coastguard Worker   // Preferred CMM type (ignored)
199*89a0ef05SAndroid Build Coastguard Worker   uint32_t cmm_type = 0;
200*89a0ef05SAndroid Build Coastguard Worker   // Version 4.3 or 4.4 if CICP is included.
201*89a0ef05SAndroid Build Coastguard Worker   uint32_t version = Endian_SwapBE32(0x04300000);
202*89a0ef05SAndroid Build Coastguard Worker   // Display device profile
203*89a0ef05SAndroid Build Coastguard Worker   uint32_t profile_class = Endian_SwapBE32(kDisplay_Profile);
204*89a0ef05SAndroid Build Coastguard Worker   // RGB input color space;
205*89a0ef05SAndroid Build Coastguard Worker   uint32_t data_color_space = Endian_SwapBE32(kRGB_ColorSpace);
206*89a0ef05SAndroid Build Coastguard Worker   // Profile connection space.
207*89a0ef05SAndroid Build Coastguard Worker   uint32_t pcs = Endian_SwapBE32(kXYZ_PCSSpace);
208*89a0ef05SAndroid Build Coastguard Worker   // Date and time (ignored)
209*89a0ef05SAndroid Build Coastguard Worker   uint8_t creation_date_time[12] = {0};
210*89a0ef05SAndroid Build Coastguard Worker   // Profile signature
211*89a0ef05SAndroid Build Coastguard Worker   uint32_t signature = Endian_SwapBE32(kACSP_Signature);
212*89a0ef05SAndroid Build Coastguard Worker   // Platform target (ignored)
213*89a0ef05SAndroid Build Coastguard Worker   uint32_t platform = 0;
214*89a0ef05SAndroid Build Coastguard Worker   // Flags: not embedded, can be used independently
215*89a0ef05SAndroid Build Coastguard Worker   uint32_t flags = 0x00000000;
216*89a0ef05SAndroid Build Coastguard Worker   // Device manufacturer (ignored)
217*89a0ef05SAndroid Build Coastguard Worker   uint32_t device_manufacturer = 0;
218*89a0ef05SAndroid Build Coastguard Worker   // Device model (ignored)
219*89a0ef05SAndroid Build Coastguard Worker   uint32_t device_model = 0;
220*89a0ef05SAndroid Build Coastguard Worker   // Device attributes (ignored)
221*89a0ef05SAndroid Build Coastguard Worker   uint8_t device_attributes[8] = {0};
222*89a0ef05SAndroid Build Coastguard Worker   // Relative colorimetric rendering intent
223*89a0ef05SAndroid Build Coastguard Worker   uint32_t rendering_intent = Endian_SwapBE32(1);
224*89a0ef05SAndroid Build Coastguard Worker   // D50 standard illuminant (X, Y, Z)
225*89a0ef05SAndroid Build Coastguard Worker   uint32_t illuminant_X = Endian_SwapBE32(float_round_to_fixed(kD50_x));
226*89a0ef05SAndroid Build Coastguard Worker   uint32_t illuminant_Y = Endian_SwapBE32(float_round_to_fixed(kD50_y));
227*89a0ef05SAndroid Build Coastguard Worker   uint32_t illuminant_Z = Endian_SwapBE32(float_round_to_fixed(kD50_z));
228*89a0ef05SAndroid Build Coastguard Worker   // Profile creator (ignored)
229*89a0ef05SAndroid Build Coastguard Worker   uint32_t creator = 0;
230*89a0ef05SAndroid Build Coastguard Worker   // Profile id checksum (ignored)
231*89a0ef05SAndroid Build Coastguard Worker   uint8_t profile_id[16] = {0};
232*89a0ef05SAndroid Build Coastguard Worker   // Reserved (ignored)
233*89a0ef05SAndroid Build Coastguard Worker   uint8_t reserved[28] = {0};
234*89a0ef05SAndroid Build Coastguard Worker   // Technically not part of header, but required
235*89a0ef05SAndroid Build Coastguard Worker   uint32_t tag_count = 0;
236*89a0ef05SAndroid Build Coastguard Worker };
237*89a0ef05SAndroid Build Coastguard Worker 
238*89a0ef05SAndroid Build Coastguard Worker class IccHelper {
239*89a0ef05SAndroid Build Coastguard Worker  private:
240*89a0ef05SAndroid Build Coastguard Worker   static constexpr uint32_t kTrcTableSize = 65;
241*89a0ef05SAndroid Build Coastguard Worker   static constexpr uint32_t kGridSize = 17;
242*89a0ef05SAndroid Build Coastguard Worker   static constexpr size_t kNumChannels = 3;
243*89a0ef05SAndroid Build Coastguard Worker 
244*89a0ef05SAndroid Build Coastguard Worker   static std::shared_ptr<DataStruct> write_text_tag(const char* text);
245*89a0ef05SAndroid Build Coastguard Worker   static std::string get_desc_string(const uhdr_color_transfer_t tf,
246*89a0ef05SAndroid Build Coastguard Worker                                      const uhdr_color_gamut_t gamut);
247*89a0ef05SAndroid Build Coastguard Worker   static std::shared_ptr<DataStruct> write_xyz_tag(float x, float y, float z);
248*89a0ef05SAndroid Build Coastguard Worker   static std::shared_ptr<DataStruct> write_trc_tag(const int table_entries, const void* table_16);
249*89a0ef05SAndroid Build Coastguard Worker   static std::shared_ptr<DataStruct> write_trc_tag(const TransferFunction& fn);
250*89a0ef05SAndroid Build Coastguard Worker   static float compute_tone_map_gain(const uhdr_color_transfer_t tf, float L);
251*89a0ef05SAndroid Build Coastguard Worker   static std::shared_ptr<DataStruct> write_cicp_tag(uint32_t color_primaries,
252*89a0ef05SAndroid Build Coastguard Worker                                                     uint32_t transfer_characteristics);
253*89a0ef05SAndroid Build Coastguard Worker   static std::shared_ptr<DataStruct> write_mAB_or_mBA_tag(uint32_t type, bool has_a_curves,
254*89a0ef05SAndroid Build Coastguard Worker                                                           const uint8_t* grid_points,
255*89a0ef05SAndroid Build Coastguard Worker                                                           const uint8_t* grid_16);
256*89a0ef05SAndroid Build Coastguard Worker   static void compute_lut_entry(const Matrix3x3& src_to_XYZD50, float rgb[3]);
257*89a0ef05SAndroid Build Coastguard Worker   static std::shared_ptr<DataStruct> write_clut(const uint8_t* grid_points, const uint8_t* grid_16);
258*89a0ef05SAndroid Build Coastguard Worker 
259*89a0ef05SAndroid Build Coastguard Worker   // Checks if a set of xyz tags is equivalent to a 3x3 Matrix. Each input
260*89a0ef05SAndroid Build Coastguard Worker   // tag buffer assumed to be at least kColorantTagSize in size.
261*89a0ef05SAndroid Build Coastguard Worker   static bool tagsEqualToMatrix(const Matrix3x3& matrix, const uint8_t* red_tag,
262*89a0ef05SAndroid Build Coastguard Worker                                 const uint8_t* green_tag, const uint8_t* blue_tag);
263*89a0ef05SAndroid Build Coastguard Worker 
264*89a0ef05SAndroid Build Coastguard Worker  public:
265*89a0ef05SAndroid Build Coastguard Worker   // Output includes JPEG embedding identifier and chunk information, but not
266*89a0ef05SAndroid Build Coastguard Worker   // APPx information.
267*89a0ef05SAndroid Build Coastguard Worker   static std::shared_ptr<DataStruct> writeIccProfile(const uhdr_color_transfer_t tf,
268*89a0ef05SAndroid Build Coastguard Worker                                                      const uhdr_color_gamut_t gamut);
269*89a0ef05SAndroid Build Coastguard Worker   // NOTE: this function is not robust; it can infer gamuts that IccHelper
270*89a0ef05SAndroid Build Coastguard Worker   // writes out but should not be considered a reference implementation for
271*89a0ef05SAndroid Build Coastguard Worker   // robust parsing of ICC profiles or their gamuts.
272*89a0ef05SAndroid Build Coastguard Worker   static uhdr_color_gamut_t readIccColorGamut(void* icc_data, size_t icc_size);
273*89a0ef05SAndroid Build Coastguard Worker };
274*89a0ef05SAndroid Build Coastguard Worker 
275*89a0ef05SAndroid Build Coastguard Worker }  // namespace ultrahdr
276*89a0ef05SAndroid Build Coastguard Worker 
277*89a0ef05SAndroid Build Coastguard Worker #endif  // ULTRAHDR_ICC_H
278