X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Frgb_xyz.cc;h=a8766b8e4000a565db972964ef1dda0263f91ab8;hb=b68a460c3ef877d95c0939b5ee02928f35e9f263;hp=08616a64bb1b845288d1005562e0a3d82e45c22f;hpb=f9cba324c8160a70b108d9e5b60a4ccad6ee9be2;p=libdcp.git diff --git a/src/rgb_xyz.cc b/src/rgb_xyz.cc index 08616a64..a8766b8e 100644 --- a/src/rgb_xyz.cc +++ b/src/rgb_xyz.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2015 Carl Hetherington + Copyright (C) 2013-2021 Carl Hetherington This file is part of libdcp. @@ -16,46 +16,54 @@ You should have received a copy of the GNU General Public License along with libdcp. If not, see . + In addition, as a special exception, the copyright holders give + permission to link the code of portions of this program with the + OpenSSL library under certain conditions as described in each + individual source file, and distribute linked combinations + including the two. + + You must obey the GNU General Public License in all respects + for all of the code used other than OpenSSL. If you modify + file(s) with this exception, you may extend this exception to your + version of the file(s), but you are not obligated to do so. If you + do not wish to do so, delete this exception statement from your + version. If you delete this exception statement from all source + files in the program, then also delete it here. */ -#include "rgb_xyz.h" -#include "openjpeg_image.h" -#include "colour_matrix.h" + +/** @file rgb_xyz.cc + * @brief Conversion between RGB and XYZ + */ + + #include "colour_conversion.h" -#include "transfer_function.h" -#include "dcp_assert.h" #include "compose.hpp" +#include "dcp_assert.h" +#include "openjpeg_image.h" +#include "rgb_xyz.h" +#include "transfer_function.h" #include -using std::min; -using std::max; + using std::cout; -using boost::shared_ptr; +using std::make_shared; +using std::max; +using std::min; +using std::shared_ptr; using boost::optional; using namespace dcp; -#define DCI_COEFFICIENT (48.0 / 52.37) - -/** Convert an XYZ image to RGBA. - * @param xyz_image Image in XYZ. - * @param conversion Colour conversion to use. - * @param argb Buffer to fill with RGBA data. The format of the data is: - * - *
- *  Byte   /- 0 -------|- 1 --------|- 2 --------|- 3 --------|- 4 --------|- 5 --------| ...
- *         |(0, 0) Blue|(0, 0)Green |(0, 0) Red  |(0, 0) Alpha|(0, 1) Blue |(0, 1) Green| ...
- *  
- * - * So that the first byte is the blue component of the pixel at x=0, y=0, the second - * is the green component, and so on. - * - * Lines are packed so that the second row directly follows the first. - */ + +static auto constexpr DCI_COEFFICIENT = 48.0 / 52.37; + + void dcp::xyz_to_rgba ( - boost::shared_ptr xyz_image, + std::shared_ptr xyz_image, ColourConversion const & conversion, - uint8_t* argb + uint8_t* argb, + int stride ) { int const max_colour = pow (2, 16) - 1; @@ -122,20 +130,11 @@ dcp::xyz_to_rgba ( *argb_line++ = 0xff; } - /* 4 bytes per pixel */ - argb += width * 4; + argb += stride; } } -/** Convert an XYZ image to 48bpp RGB. - * @param xyz_image Frame in XYZ. - * @param conversion Colour conversion to use. - * @param rgb Buffer to fill with RGB data. Format is packed RGB - * 16:16:16, 48bpp, 16R, 16G, 16B, with the 2-byte value for each - * R/G/B component stored as little-endian; i.e. AV_PIX_FMT_RGB48LE. - * @param stride Stride for RGB data in bytes. - * @param note Optional handler for any notes that may be made during the conversion (e.g. when clamping occurs). - */ + void dcp::xyz_to_rgb ( shared_ptr xyz_image, @@ -160,7 +159,7 @@ dcp::xyz_to_rgb ( double const * lut_in = conversion.out()->lut (12, false); double const * lut_out = conversion.in()->lut (16, true); - boost::numeric::ublas::matrix const matrix = conversion.xyz_to_rgb (); + auto const matrix = conversion.xyz_to_rgb (); double fast_matrix[9] = { matrix (0, 0), matrix (0, 1), matrix (0, 2), @@ -172,7 +171,7 @@ dcp::xyz_to_rgb ( int const width = xyz_image->size().width; for (int y = 0; y < height; ++y) { - uint16_t* rgb_line = reinterpret_cast (rgb + y * stride); + auto rgb_line = reinterpret_cast (rgb + y * stride); for (int x = 0; x < width; ++x) { int cx = *xyz_x++; @@ -181,21 +180,21 @@ dcp::xyz_to_rgb ( if (cx < 0 || cx > 4095) { if (note) { - note.get() (DCP_NOTE, String::compose ("XYZ value %1 out of range", cx)); + note.get()(NoteType::NOTE, String::compose("XYZ value %1 out of range", cx)); } cx = max (min (cx, 4095), 0); } if (cy < 0 || cy > 4095) { if (note) { - note.get() (DCP_NOTE, String::compose ("XYZ value %1 out of range", cy)); + note.get()(NoteType::NOTE, String::compose("XYZ value %1 out of range", cy)); } cy = max (min (cy, 4095), 0); } if (cz < 0 || cz > 4095) { if (note) { - note.get() (DCP_NOTE, String::compose ("XYZ value %1 out of range", cz)); + note.get()(NoteType::NOTE, String::compose("XYZ value %1 out of range", cz)); } cz = max (min (cz, 4095), 0); } @@ -231,12 +230,33 @@ dcp::xyz_to_rgb ( } } -/** @param rgb RGB data; packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, - * with the 2-byte value for each R/G/B component stored as - * little-endian; i.e. AV_PIX_FMT_RGB48LE. - * @param size of RGB image in pixels. - * @param stride of RGB data in pixels. - */ +void +dcp::combined_rgb_to_xyz (ColourConversion const & conversion, double* matrix) +{ + auto const rgb_to_xyz = conversion.rgb_to_xyz (); + auto const bradford = conversion.bradford (); + + matrix[0] = (bradford (0, 0) * rgb_to_xyz (0, 0) + bradford (0, 1) * rgb_to_xyz (1, 0) + bradford (0, 2) * rgb_to_xyz (2, 0)) + * DCI_COEFFICIENT * 65535; + matrix[1] = (bradford (0, 0) * rgb_to_xyz (0, 1) + bradford (0, 1) * rgb_to_xyz (1, 1) + bradford (0, 2) * rgb_to_xyz (2, 1)) + * DCI_COEFFICIENT * 65535; + matrix[2] = (bradford (0, 0) * rgb_to_xyz (0, 2) + bradford (0, 1) * rgb_to_xyz (1, 2) + bradford (0, 2) * rgb_to_xyz (2, 2)) + * DCI_COEFFICIENT * 65535; + matrix[3] = (bradford (1, 0) * rgb_to_xyz (0, 0) + bradford (1, 1) * rgb_to_xyz (1, 0) + bradford (1, 2) * rgb_to_xyz (2, 0)) + * DCI_COEFFICIENT * 65535; + matrix[4] = (bradford (1, 0) * rgb_to_xyz (0, 1) + bradford (1, 1) * rgb_to_xyz (1, 1) + bradford (1, 2) * rgb_to_xyz (2, 1)) + * DCI_COEFFICIENT * 65535; + matrix[5] = (bradford (1, 0) * rgb_to_xyz (0, 2) + bradford (1, 1) * rgb_to_xyz (1, 2) + bradford (1, 2) * rgb_to_xyz (2, 2)) + * DCI_COEFFICIENT * 65535; + matrix[6] = (bradford (2, 0) * rgb_to_xyz (0, 0) + bradford (2, 1) * rgb_to_xyz (1, 0) + bradford (2, 2) * rgb_to_xyz (2, 0)) + * DCI_COEFFICIENT * 65535; + matrix[7] = (bradford (2, 0) * rgb_to_xyz (0, 1) + bradford (2, 1) * rgb_to_xyz (1, 1) + bradford (2, 2) * rgb_to_xyz (2, 1)) + * DCI_COEFFICIENT * 65535; + matrix[8] = (bradford (2, 0) * rgb_to_xyz (0, 2) + bradford (2, 1) * rgb_to_xyz (1, 2) + bradford (2, 2) * rgb_to_xyz (2, 2)) + * DCI_COEFFICIENT * 65535; +} + + shared_ptr dcp::rgb_to_xyz ( uint8_t const * rgb, @@ -246,7 +266,7 @@ dcp::rgb_to_xyz ( optional note ) { - shared_ptr xyz (new OpenJPEGImage (size)); + auto xyz = make_shared(size); struct { double r, g, b; @@ -256,30 +276,19 @@ dcp::rgb_to_xyz ( double x, y, z; } d; - double const * lut_in = conversion.in()->lut (12, false); - double const * lut_out = conversion.out()->lut (16, true); - boost::numeric::ublas::matrix const rgb_to_xyz = conversion.rgb_to_xyz (); - boost::numeric::ublas::matrix const bradford = conversion.bradford (); + auto const * lut_in = conversion.in()->lut (12, false); + auto const * lut_out = conversion.out()->lut (16, true); /* This is is the product of the RGB to XYZ matrix, the Bradford transform and the DCI companding */ - double fast_matrix[9] = { - (bradford (0, 0) * rgb_to_xyz (0, 0) + bradford (0, 1) * rgb_to_xyz (1, 0) + bradford (0, 2) * rgb_to_xyz (2, 0)) * DCI_COEFFICIENT * 65535, - (bradford (0, 0) * rgb_to_xyz (0, 1) + bradford (0, 1) * rgb_to_xyz (1, 1) + bradford (0, 2) * rgb_to_xyz (2, 1)) * DCI_COEFFICIENT * 65535, - (bradford (0, 0) * rgb_to_xyz (0, 2) + bradford (0, 1) * rgb_to_xyz (1, 2) + bradford (0, 2) * rgb_to_xyz (2, 2)) * DCI_COEFFICIENT * 65535, - (bradford (1, 0) * rgb_to_xyz (0, 0) + bradford (1, 1) * rgb_to_xyz (1, 0) + bradford (1, 2) * rgb_to_xyz (2, 0)) * DCI_COEFFICIENT * 65535, - (bradford (1, 0) * rgb_to_xyz (0, 1) + bradford (1, 1) * rgb_to_xyz (1, 1) + bradford (1, 2) * rgb_to_xyz (2, 1)) * DCI_COEFFICIENT * 65535, - (bradford (1, 0) * rgb_to_xyz (0, 2) + bradford (1, 1) * rgb_to_xyz (1, 2) + bradford (1, 2) * rgb_to_xyz (2, 2)) * DCI_COEFFICIENT * 65535, - (bradford (2, 0) * rgb_to_xyz (0, 0) + bradford (2, 1) * rgb_to_xyz (1, 0) + bradford (2, 2) * rgb_to_xyz (2, 0)) * DCI_COEFFICIENT * 65535, - (bradford (2, 0) * rgb_to_xyz (0, 1) + bradford (2, 1) * rgb_to_xyz (1, 1) + bradford (2, 2) * rgb_to_xyz (2, 1)) * DCI_COEFFICIENT * 65535, - (bradford (2, 0) * rgb_to_xyz (0, 2) + bradford (2, 1) * rgb_to_xyz (1, 2) + bradford (2, 2) * rgb_to_xyz (2, 2)) * DCI_COEFFICIENT * 65535 - }; + double fast_matrix[9]; + combined_rgb_to_xyz (conversion, fast_matrix); int clamped = 0; int* xyz_x = xyz->data (0); int* xyz_y = xyz->data (1); int* xyz_z = xyz->data (2); for (int y = 0; y < size.height; ++y) { - uint16_t const * p = reinterpret_cast (rgb + y * stride); + auto p = reinterpret_cast (rgb + y * stride); for (int x = 0; x < size.width; ++x) { /* In gamma LUT (converting 16-bit to 12-bit) */ @@ -313,33 +322,8 @@ dcp::rgb_to_xyz ( } if (clamped && note) { - note.get() (DCP_NOTE, String::compose ("%1 XYZ value(s) clamped", clamped)); + note.get()(NoteType::NOTE, String::compose("%1 XYZ value(s) clamped", clamped)); } return xyz; } - - -/** @param xyz_16 XYZ image data in packed 16:16:16, 48bpp, 16X, 16Y, - * 16Z, with the 2-byte value for each X/Y/Z component stored as - * little-endian. - */ -shared_ptr -dcp::xyz_to_xyz (uint8_t const * xyz_16, dcp::Size size, int stride) -{ - shared_ptr xyz_12 (new OpenJPEGImage (size)); - - int jn = 0; - for (int y = 0; y < size.height; ++y) { - uint16_t const * p = reinterpret_cast (xyz_16 + y * stride); - for (int x = 0; x < size.width; ++x) { - /* Truncate 16-bit to 12-bit */ - xyz_12->data(0)[jn] = *p++ >> 4; - xyz_12->data(1)[jn] = *p++ >> 4; - xyz_12->data(2)[jn] = *p++ >> 4; - ++jn; - } - } - - return xyz_12; -}