summaryrefslogtreecommitdiffstats
path: root/third_party/jpeg-xl/lib/include/jxl/cms_interface.h
blob: 684281e6415be20080f7bf23d47130187e72e171 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
/* Copyright (c) the JPEG XL Project Authors. All rights reserved.
 *
 * Use of this source code is governed by a BSD-style
 * license that can be found in the LICENSE file.
 */

/** @addtogroup libjxl_common
 * @{
 * @file cms_interface.h
 * @brief Interface to allow the injection of different color management systems
 * (CMSes, also called color management modules, or CMMs) in JPEG XL.
 *
 * A CMS is needed by the JPEG XL encoder and decoder to perform colorspace
 * conversions. This defines an interface that can be implemented for different
 * CMSes and then passed to the library.
 */

#ifndef JXL_CMS_INTERFACE_H_
#define JXL_CMS_INTERFACE_H_

#include <jxl/color_encoding.h>
#include <jxl/types.h>

#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif

/** Represents an input or output colorspace to a color transform, as a
 * serialized ICC profile. */
typedef struct {
  /** The serialized ICC profile. This is guaranteed to be present and valid. */
  struct {
    const uint8_t* data;
    size_t size;
  } icc;

  /** Structured representation of the colorspace, if applicable. If all fields
   * are different from their "unknown" value, then this is equivalent to the
   * ICC representation of the colorspace. If some are "unknown", those that are
   * not are still valid and can still be used on their own if they are useful.
   */
  JxlColorEncoding color_encoding;

  /** Number of components per pixel. This can be deduced from the other
   * representations of the colorspace but is provided for convenience and
   * validation. */
  size_t num_channels;
} JxlColorProfile;

/** Allocates and returns the data needed for @p num_threads parallel transforms
 * from the @p input colorspace to @p output, with up to @p pixels_per_thread
 * pixels to transform per call to JxlCmsInterface::run. @p init_data comes
 * directly from the JxlCmsInterface instance. Since @c run only receives the
 * data returned by @c init, a reference to @p init_data should be kept there
 * if access to it is desired in @c run. Likewise for JxlCmsInterface::destroy.
 *
 * The ICC data in @p input and @p output is guaranteed to outlive the @c init /
 * @c run / @c destroy cycle.
 *
 * @param init_data JxlCmsInterface::init_data passed as-is.
 * @param num_threads the maximum number of threads from which
 *        JxlCmsInterface::run will be called.
 * @param pixels_per_thread the maximum number of pixels that each call to
 *        JxlCmsInterface::run will have to transform.
 * @param input_profile the input colorspace for the transform.
 * @param output_profile the colorspace to which JxlCmsInterface::run should
 *        convert the input data.
 * @param intensity_target for colorspaces where luminance is relative
 *        (essentially: not PQ), indicates the luminance at which (1, 1, 1) will
 *        be displayed. This is useful for conversions between PQ and a relative
 *        luminance colorspace, in either direction: @p intensity_target cd/m²
 *        in PQ should map to and from (1, 1, 1) in the relative one.\n
 *        It is also used for conversions to and from HLG, as it is
 *        scene-referred while other colorspaces are assumed to be
 *        display-referred. That is, conversions from HLG should apply the OOTF
 *        for a peak display luminance of @p intensity_target, and conversions
 *        to HLG should undo it. The OOTF is a gamma function applied to the
 *        luminance channel (https://www.itu.int/rec/R-REC-BT.2100-2-201807-I
 *        page 7), with the gamma value computed as
 *        <tt>1.2 * 1.111^log2(intensity_target / 1000)</tt> (footnote 2 page 8
 *        of the same document).
 * @return The data needed for the transform, or @c NULL in case of failure.
 *         This will be passed to the other functions as @c user_data.
 */
typedef void* (*jpegxl_cms_init_func)(void* init_data, size_t num_threads,
                                      size_t pixels_per_thread,
                                      const JxlColorProfile* input_profile,
                                      const JxlColorProfile* output_profile,
                                      float intensity_target);

/** Returns a buffer that can be used by callers of the interface to store the
 * input of the conversion or read its result, if they pass it as the input or
 * output of the @c run function.
 * @param user_data the data returned by @c init.
 * @param thread the index of the thread for which to return a buffer.
 * @return A buffer that can be used by the caller for passing to @c run.
 */
typedef float* (*jpegxl_cms_get_buffer_func)(void* user_data, size_t thread);

/** Executes one transform and returns true on success or false on error. It
 * must be possible to call this from different threads with different values
 * for @p thread, all between 0 (inclusive) and the value of @p num_threads
 * passed to @c init (exclusive). It is allowed to implement this by locking
 * such that the transforms are essentially performed sequentially, if such a
 * performance profile is acceptable. @p user_data is the data returned by
 * @c init.
 * The buffers each contain @p num_pixels × @c num_channels interleaved floating
 * point (0..1) samples where @c num_channels is the number of color channels of
 * their respective color profiles. It is guaranteed that the only case in which
 * they might overlap is if the output has fewer channels than the input, in
 * which case the pointers may be identical.
 * For CMYK data, 0 represents the maximum amount of ink while 1 represents no
 * ink.
 * @param user_data the data returned by @c init.
 * @param thread the index of the thread from which the function is being
 *        called.
 * @param input_buffer the buffer containing the pixel data to be transformed.
 * @param output_buffer the buffer receiving the transformed pixel data.
 * @param num_pixels the number of pixels to transform from @p input to
 * @p output.
 * @return JXL_TRUE on success, JXL_FALSE on failure.
 */
typedef JXL_BOOL (*jpegxl_cms_run_func)(void* user_data, size_t thread,
                                        const float* input_buffer,
                                        float* output_buffer,
                                        size_t num_pixels);

/** Performs the necessary clean-up and frees the memory allocated for user
 * data.
 */
typedef void (*jpegxl_cms_destroy_func)(void*);

/**
 * Interface for performing colorspace transforms. The @c init function can be
 * called several times to instantiate several transforms, including before
 * other transforms have been destroyed.
 *
 * The call sequence for a given colorspace transform could look like the
 * following:
 * @dot
 * digraph calls {
 *   newrank = true
 *   node [shape = box, fontname = monospace]
 *   init [label = "user_data <- init(\l\
 *     init_data = data,\l\
 *     num_threads = 3,\l\
 *     pixels_per_thread = 20,\l\
 *     input = (sRGB, 3 channels),\l\
 *     output = (Display-P3, 3 channels),\l\
 *     intensity_target = 255\l\
 *   )\l"]
 *   subgraph cluster_0 {
 *   color = lightgrey
 *   label = "thread 1"
 *   labeljust = "c"
 *   run_1_1 [label = "run(\l\
 *     user_data,\l\
 *     thread = 1,\l\
 *     input = in[0],\l\
 *     output = out[0],\l\
 *     num_pixels = 20\l\
 *   )\l"]
 *   run_1_2 [label = "run(\l\
 *     user_data,\l\
 *     thread = 1,\l\
 *     input = in[3],\l\
 *     output = out[3],\l\
 *     num_pixels = 20\l\
 *   )\l"]
 *   }
 *   subgraph cluster_1 {
 *   color = lightgrey
 *   label = "thread 2"
 *   labeljust = "l"
 *   run_2_1 [label = "run(\l\
 *     user_data,\l\
 *     thread = 2,\l\
 *     input = in[1],\l\
 *     output = out[1],\l\
 *     num_pixels = 20\l\
 *   )\l"]
 *   run_2_2 [label = "run(\l\
 *     user_data,\l\
 *     thread = 2,\l\
 *     input = in[4],\l\
 *     output = out[4],\l\
 *     num_pixels = 13\l\
 *   )\l"]
 *   }
 *   subgraph cluster_3 {
 *   color = lightgrey
 *   label = "thread 3"
 *   labeljust = "c"
 *   run_3_1 [label = "run(\l\
 *     user_data,\l\
 *     thread = 3,\l\
 *     input = in[2],\l\
 *     output = out[2],\l\
 *     num_pixels = 20\l\
 *   )\l"]
 *   }
 *   init -> {run_1_1; run_2_1; run_3_1; rank = same}
 *   run_1_1 -> run_1_2
 *   run_2_1 -> run_2_2
 *   {run_1_2; run_2_2, run_3_1} -> "destroy(user_data)"
 * }
 * @enddot
 */
typedef struct {
  /** CMS-specific data that will be passed to @ref init. */
  void* init_data;
  /** Prepares a colorspace transform as described in the documentation of @ref
   * jpegxl_cms_init_func. */
  jpegxl_cms_init_func init;
  /** Returns a buffer that can be used as input to @c run. */
  jpegxl_cms_get_buffer_func get_src_buf;
  /** Returns a buffer that can be used as output from @c run. */
  jpegxl_cms_get_buffer_func get_dst_buf;
  /** Executes the transform on a batch of pixels, per @ref jpegxl_cms_run_func.
   */
  jpegxl_cms_run_func run;
  /** Cleans up the transform. */
  jpegxl_cms_destroy_func destroy;
} JxlCmsInterface;

#if defined(__cplusplus) || defined(c_plusplus)
}
#endif

#endif /* JXL_CMS_INTERFACE_H_ */

/** @} */