41 #include "compose.hpp"
44 #include "piecewise_lut.h"
51 using std::make_shared;
54 using std::shared_ptr;
55 using boost::optional;
59 static auto constexpr DCI_COEFFICIENT = 48.0 / 52.37;
64 std::shared_ptr<const OpenJPEGImage> xyz_image,
70 int const max_colour = pow (2, 16) - 1;
80 int* xyz_x = xyz_image->data (0);
81 int* xyz_y = xyz_image->data (1);
82 int* xyz_z = xyz_image->data (2);
84 auto lut_in = conversion.out()->double_lut(0, 1, 12,
false);
85 auto lut_out = conversion.in()->double_lut(0, 1, 16,
true);
86 boost::numeric::ublas::matrix<double>
const matrix = conversion.xyz_to_rgb ();
88 double fast_matrix[9] = {
89 matrix (0, 0), matrix (0, 1), matrix (0, 2),
90 matrix (1, 0), matrix (1, 1), matrix (1, 2),
91 matrix (2, 0), matrix (2, 1), matrix (2, 2)
94 int const height = xyz_image->size().height;
95 int const width = xyz_image->size().width;
97 for (
int y = 0; y < height; ++y) {
98 uint8_t* argb_line = argb;
99 for (
int x = 0; x < width; ++x) {
101 DCP_ASSERT (*xyz_x >= 0 && *xyz_y >= 0 && *xyz_z >= 0 && *xyz_x < 4096 && *xyz_y < 4096 && *xyz_z < 4096);
104 s.x = lut_in[*xyz_x++];
105 s.y = lut_in[*xyz_y++];
106 s.z = lut_in[*xyz_z++];
109 s.x /= DCI_COEFFICIENT;
110 s.y /= DCI_COEFFICIENT;
111 s.z /= DCI_COEFFICIENT;
114 d.r = ((s.x * fast_matrix[0]) + (s.y * fast_matrix[1]) + (s.z * fast_matrix[2]));
115 d.g = ((s.x * fast_matrix[3]) + (s.y * fast_matrix[4]) + (s.z * fast_matrix[5]));
116 d.b = ((s.x * fast_matrix[6]) + (s.y * fast_matrix[7]) + (s.z * fast_matrix[8]));
118 d.r = min (d.r, 1.0);
119 d.r = max (d.r, 0.0);
121 d.g = min (d.g, 1.0);
122 d.g = max (d.g, 0.0);
124 d.b = min (d.b, 1.0);
125 d.b = max (d.b, 0.0);
128 *argb_line++ = lut_out[lrint(d.b * max_colour)] * 0xff;
129 *argb_line++ = lut_out[lrint(d.g * max_colour)] * 0xff;
130 *argb_line++ = lut_out[lrint(d.r * max_colour)] * 0xff;
141 shared_ptr<const OpenJPEGImage> xyz_image,
145 optional<NoteHandler> note
157 int* xyz_x = xyz_image->data (0);
158 int* xyz_y = xyz_image->data (1);
159 int* xyz_z = xyz_image->data (2);
161 auto lut_in = conversion.out()->double_lut(0, 1, 12,
false);
162 auto lut_out = conversion.in()->double_lut(0, 1, 16,
true);
163 auto const matrix = conversion.xyz_to_rgb ();
165 double fast_matrix[9] = {
166 matrix (0, 0), matrix (0, 1), matrix (0, 2),
167 matrix (1, 0), matrix (1, 1), matrix (1, 2),
168 matrix (2, 0), matrix (2, 1), matrix (2, 2)
171 int const height = xyz_image->size().height;
172 int const width = xyz_image->size().width;
174 for (
int y = 0; y < height; ++y) {
175 auto rgb_line =
reinterpret_cast<uint16_t*
> (rgb + y * stride);
176 for (
int x = 0; x < width; ++x) {
182 if (cx < 0 || cx > 4095) {
184 note.get()(NoteType::NOTE, String::compose(
"XYZ value %1 out of range", cx));
186 cx = max (min (cx, 4095), 0);
189 if (cy < 0 || cy > 4095) {
191 note.get()(NoteType::NOTE, String::compose(
"XYZ value %1 out of range", cy));
193 cy = max (min (cy, 4095), 0);
196 if (cz < 0 || cz > 4095) {
198 note.get()(NoteType::NOTE, String::compose(
"XYZ value %1 out of range", cz));
200 cz = max (min (cz, 4095), 0);
209 s.x /= DCI_COEFFICIENT;
210 s.y /= DCI_COEFFICIENT;
211 s.z /= DCI_COEFFICIENT;
214 d.r = ((s.x * fast_matrix[0]) + (s.y * fast_matrix[1]) + (s.z * fast_matrix[2]));
215 d.g = ((s.x * fast_matrix[3]) + (s.y * fast_matrix[4]) + (s.z * fast_matrix[5]));
216 d.b = ((s.x * fast_matrix[6]) + (s.y * fast_matrix[7]) + (s.z * fast_matrix[8]));
218 d.r = min (d.r, 1.0);
219 d.r = max (d.r, 0.0);
221 d.g = min (d.g, 1.0);
222 d.g = max (d.g, 0.0);
224 d.b = min (d.b, 1.0);
225 d.b = max (d.b, 0.0);
227 *rgb_line++ = lrint(lut_out[lrint(d.r * 65535)] * 65535);
228 *rgb_line++ = lrint(lut_out[lrint(d.g * 65535)] * 65535);
229 *rgb_line++ = lrint(lut_out[lrint(d.b * 65535)] * 65535);
237 auto const rgb_to_xyz = conversion.rgb_to_xyz ();
238 auto const bradford = conversion.bradford ();
262 dcp::make_inverse_gamma_lut(shared_ptr<const TransferFunction> fn)
289 auto lut_in = conversion.in()->double_lut(0, 1, 12,
false);
290 auto lut_out = make_inverse_gamma_lut(conversion.out());
293 double fast_matrix[9];
296 for (
int y = 0; y < size.height; ++y) {
297 auto p =
reinterpret_cast<uint16_t
const *
> (rgb + y * stride);
298 for (
int x = 0; x < size.width; ++x) {
301 s.r = lut_in[*p++ >> 4];
302 s.g = lut_in[*p++ >> 4];
303 s.b = lut_in[*p++ >> 4];
306 d.x = s.r * fast_matrix[0] + s.g * fast_matrix[1] + s.b * fast_matrix[2];
307 d.y = s.r * fast_matrix[3] + s.g * fast_matrix[4] + s.b * fast_matrix[5];
308 d.z = s.r * fast_matrix[6] + s.g * fast_matrix[7] + s.b * fast_matrix[8];
311 d.x = max (0.0, d.x);
312 d.y = max (0.0, d.y);
313 d.z = max (0.0, d.z);
314 d.x = min (1.0, d.x);
315 d.y = min (1.0, d.y);
316 d.z = min (1.0, d.z);
319 *xyz_x++ = lut_out.lookup(d.x);
320 *xyz_y++ = lut_out.lookup(d.y);
321 *xyz_z++ = lut_out.lookup(d.z);
327 shared_ptr<dcp::OpenJPEGImage>
335 auto xyz = make_shared<OpenJPEGImage>(size);
337 int* xyz_x = xyz->data (0);
338 int* xyz_y = xyz->data (1);
339 int* xyz_z = xyz->data (2);
341 rgb_to_xyz_internal(rgb, xyz_x, xyz_y, xyz_z, size, stride, conversion);
356 rgb_to_xyz_internal(rgb, dst, dst, dst, size, stride, conversion);
A representation of all the parameters involved the colourspace conversion of a YUV image to XYZ (via...
Namespace for everything in libdcp.
void combined_rgb_to_xyz(ColourConversion const &conversion, double *matrix)
void xyz_to_rgb(std::shared_ptr< const OpenJPEGImage >, ColourConversion const &conversion, uint8_t *rgb, int stride, boost::optional< NoteHandler > note=boost::optional< NoteHandler >())
void rgb_to_xyz(uint8_t const *rgb, uint16_t *dst, dcp::Size size, int stride, ColourConversion const &conversion)
void xyz_to_rgba(std::shared_ptr< const OpenJPEGImage >, ColourConversion const &conversion, uint8_t *rgba, int stride)
Conversion between RGB and XYZ.
The integer, two-dimensional size of something.