cms_interface.h (10260B)
1 /* Copyright (c) the JPEG XL Project Authors. All rights reserved. 2 * 3 * Use of this source code is governed by a BSD-style 4 * license that can be found in the LICENSE file. 5 */ 6 7 /** @addtogroup libjxl_color 8 * @{ 9 * @file cms_interface.h 10 * @brief Interface to allow the injection of different color management systems 11 * (CMSes, also called color management modules, or CMMs) in JPEG XL. 12 * 13 * A CMS is needed by the JPEG XL encoder and decoder to perform colorspace 14 * conversions. This defines an interface that can be implemented for different 15 * CMSes and then passed to the library. 16 */ 17 18 #ifndef JXL_CMS_INTERFACE_H_ 19 #define JXL_CMS_INTERFACE_H_ 20 21 #include <jxl/color_encoding.h> 22 #include <jxl/types.h> 23 #include <stddef.h> 24 #include <stdint.h> 25 26 #if defined(__cplusplus) || defined(c_plusplus) 27 extern "C" { 28 #endif 29 30 /** Parses an ICC profile and populates @p c and @p cmyk with the data. 31 * 32 * @param user_data @ref JxlCmsInterface::set_fields_data passed as-is. 33 * @param icc_data the ICC data to parse. 34 * @param icc_size how many bytes of icc_data are valid. 35 * @param c a @ref JxlColorEncoding to populate if applicable. 36 * @param cmyk a boolean to set to whether the colorspace is a CMYK colorspace. 37 * @return Whether the relevant fields in @p c were successfully populated. 38 */ 39 typedef JXL_BOOL (*jpegxl_cms_set_fields_from_icc_func)(void* user_data, 40 const uint8_t* icc_data, 41 size_t icc_size, 42 JxlColorEncoding* c, 43 JXL_BOOL* cmyk); 44 45 /** Represents an input or output colorspace to a color transform, as a 46 * serialized ICC profile. */ 47 typedef struct { 48 /** The serialized ICC profile. This is guaranteed to be present and valid. */ 49 struct { 50 const uint8_t* data; 51 size_t size; 52 } icc; 53 54 /** Structured representation of the colorspace, if applicable. If all fields 55 * are different from their "unknown" value, then this is equivalent to the 56 * ICC representation of the colorspace. If some are "unknown", those that are 57 * not are still valid and can still be used on their own if they are useful. 58 */ 59 JxlColorEncoding color_encoding; 60 61 /** Number of components per pixel. This can be deduced from the other 62 * representations of the colorspace but is provided for convenience and 63 * validation. */ 64 size_t num_channels; 65 } JxlColorProfile; 66 67 /** Allocates and returns the data needed for @p num_threads parallel transforms 68 * from the @p input colorspace to @p output, with up to @p pixels_per_thread 69 * pixels to transform per call to @ref JxlCmsInterface::run. @p init_data comes 70 * directly from the @ref JxlCmsInterface instance. Since @c run only receives 71 * the data returned by @c init, a reference to @p init_data should be kept 72 * there if access to it is desired in @c run. Likewise for @ref 73 * JxlCmsInterface::destroy. 74 * 75 * The ICC data in @p input and @p output is guaranteed to outlive the @c init / 76 * @c run / @c destroy cycle. 77 * 78 * @param init_data @ref JxlCmsInterface::init_data passed as-is. 79 * @param num_threads the maximum number of threads from which 80 * @ref JxlCmsInterface::run will be called. 81 * @param pixels_per_thread the maximum number of pixels that each call to 82 * @ref JxlCmsInterface::run will have to transform. 83 * @param input_profile the input colorspace for the transform. 84 * @param output_profile the colorspace to which @ref JxlCmsInterface::run 85 * should convert the input data. 86 * @param intensity_target for colorspaces where luminance is relative 87 * (essentially: not PQ), indicates the luminance at which (1, 1, 1) will 88 * be displayed. This is useful for conversions between PQ and a relative 89 * luminance colorspace, in either direction: @p intensity_target cd/m² 90 * in PQ should map to and from (1, 1, 1) in the relative one.\n 91 * It is also used for conversions to and from HLG, as it is 92 * scene-referred while other colorspaces are assumed to be 93 * display-referred. That is, conversions from HLG should apply the OOTF 94 * for a peak display luminance of @p intensity_target, and conversions 95 * to HLG should undo it. The OOTF is a gamma function applied to the 96 * luminance channel (https://www.itu.int/rec/R-REC-BT.2100-2-201807-I 97 * page 7), with the gamma value computed as 98 * <tt>1.2 * 1.111^log2(intensity_target / 1000)</tt> (footnote 2 page 8 99 * of the same document). 100 * @return The data needed for the transform, or @c NULL in case of failure. 101 * This will be passed to the other functions as @c user_data. 102 */ 103 typedef void* (*jpegxl_cms_init_func)(void* init_data, size_t num_threads, 104 size_t pixels_per_thread, 105 const JxlColorProfile* input_profile, 106 const JxlColorProfile* output_profile, 107 float intensity_target); 108 109 /** Returns a buffer that can be used by callers of the interface to store the 110 * input of the conversion or read its result, if they pass it as the input or 111 * output of the @c run function. 112 * @param user_data the data returned by @c init. 113 * @param thread the index of the thread for which to return a buffer. 114 * @return A buffer that can be used by the caller for passing to @c run. 115 */ 116 typedef float* (*jpegxl_cms_get_buffer_func)(void* user_data, size_t thread); 117 118 /** Executes one transform and returns true on success or false on error. It 119 * must be possible to call this from different threads with different values 120 * for @p thread, all between 0 (inclusive) and the value of @p num_threads 121 * passed to @c init (exclusive). It is allowed to implement this by locking 122 * such that the transforms are essentially performed sequentially, if such a 123 * performance profile is acceptable. @p user_data is the data returned by 124 * @c init. 125 * The buffers each contain @p num_pixels × @c num_channels interleaved floating 126 * point (0..1) samples where @c num_channels is the number of color channels of 127 * their respective color profiles. It is guaranteed that the only case in which 128 * they might overlap is if the output has fewer channels than the input, in 129 * which case the pointers may be identical. 130 * For CMYK data, 0 represents the maximum amount of ink while 1 represents no 131 * ink. 132 * @param user_data the data returned by @c init. 133 * @param thread the index of the thread from which the function is being 134 * called. 135 * @param input_buffer the buffer containing the pixel data to be transformed. 136 * @param output_buffer the buffer receiving the transformed pixel data. 137 * @param num_pixels the number of pixels to transform from @p input to 138 * @p output. 139 * @return ::JXL_TRUE on success, ::JXL_FALSE on failure. 140 */ 141 typedef JXL_BOOL (*jpegxl_cms_run_func)(void* user_data, size_t thread, 142 const float* input_buffer, 143 float* output_buffer, 144 size_t num_pixels); 145 146 /** Performs the necessary clean-up and frees the memory allocated for user 147 * data. 148 */ 149 typedef void (*jpegxl_cms_destroy_func)(void*); 150 151 /** 152 * Interface for performing colorspace transforms. The @c init function can be 153 * called several times to instantiate several transforms, including before 154 * other transforms have been destroyed. 155 * 156 * The call sequence for a given colorspace transform could look like the 157 * following: 158 * @dot 159 * digraph calls { 160 * newrank = true 161 * node [shape = box, fontname = monospace] 162 * init [label = "user_data <- init(\l\ 163 * init_data = data,\l\ 164 * num_threads = 3,\l\ 165 * pixels_per_thread = 20,\l\ 166 * input = (sRGB, 3 channels),\l\ 167 * output = (Display-P3, 3 channels),\l\ 168 * intensity_target = 255\l\ 169 * )\l"] 170 * subgraph cluster_0 { 171 * color = lightgrey 172 * label = "thread 1" 173 * labeljust = "c" 174 * run_1_1 [label = "run(\l\ 175 * user_data,\l\ 176 * thread = 1,\l\ 177 * input = in[0],\l\ 178 * output = out[0],\l\ 179 * num_pixels = 20\l\ 180 * )\l"] 181 * run_1_2 [label = "run(\l\ 182 * user_data,\l\ 183 * thread = 1,\l\ 184 * input = in[3],\l\ 185 * output = out[3],\l\ 186 * num_pixels = 20\l\ 187 * )\l"] 188 * } 189 * subgraph cluster_1 { 190 * color = lightgrey 191 * label = "thread 2" 192 * labeljust = "l" 193 * run_2_1 [label = "run(\l\ 194 * user_data,\l\ 195 * thread = 2,\l\ 196 * input = in[1],\l\ 197 * output = out[1],\l\ 198 * num_pixels = 20\l\ 199 * )\l"] 200 * run_2_2 [label = "run(\l\ 201 * user_data,\l\ 202 * thread = 2,\l\ 203 * input = in[4],\l\ 204 * output = out[4],\l\ 205 * num_pixels = 13\l\ 206 * )\l"] 207 * } 208 * subgraph cluster_3 { 209 * color = lightgrey 210 * label = "thread 3" 211 * labeljust = "c" 212 * run_3_1 [label = "run(\l\ 213 * user_data,\l\ 214 * thread = 3,\l\ 215 * input = in[2],\l\ 216 * output = out[2],\l\ 217 * num_pixels = 20\l\ 218 * )\l"] 219 * } 220 * init -> {run_1_1; run_2_1; run_3_1; rank = same} 221 * run_1_1 -> run_1_2 222 * run_2_1 -> run_2_2 223 * {run_1_2; run_2_2, run_3_1} -> "destroy(user_data)" 224 * } 225 * @enddot 226 */ 227 typedef struct { 228 /** CMS-specific data that will be passed to @ref set_fields_from_icc. */ 229 void* set_fields_data; 230 /** Populates a @ref JxlColorEncoding from an ICC profile. */ 231 jpegxl_cms_set_fields_from_icc_func set_fields_from_icc; 232 233 /** CMS-specific data that will be passed to @ref init. */ 234 void* init_data; 235 /** Prepares a colorspace transform as described in the documentation of @ref 236 * jpegxl_cms_init_func. */ 237 jpegxl_cms_init_func init; 238 /** Returns a buffer that can be used as input to @c run. */ 239 jpegxl_cms_get_buffer_func get_src_buf; 240 /** Returns a buffer that can be used as output from @c run. */ 241 jpegxl_cms_get_buffer_func get_dst_buf; 242 /** Executes the transform on a batch of pixels, per @ref jpegxl_cms_run_func. 243 */ 244 jpegxl_cms_run_func run; 245 /** Cleans up the transform. */ 246 jpegxl_cms_destroy_func destroy; 247 } JxlCmsInterface; 248 249 #if defined(__cplusplus) || defined(c_plusplus) 250 } 251 #endif 252 253 #endif /* JXL_CMS_INTERFACE_H_ */ 254 255 /** @} */