summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2025-05-05 00:42:36 +0200
committerCarl Hetherington <cth@carlh.net>2025-10-14 20:50:53 +0200
commit2e9e778462a86e9c35e1758eb95cced4ddd5468d (patch)
tree8cd6b2bbfbfa564fc5c81cafd76c4abdd7923e9c /test
parent6ee5579ba47f120f731c11f47417d690d6ce1325 (diff)
Move rgb_xyz into colour_conversion.
Diffstat (limited to 'test')
-rw-r--r--test/colour_conversion_test.cc222
-rw-r--r--test/decryption_test.cc1
-rw-r--r--test/rgb_xyz_test.cc256
-rw-r--r--test/round_trip_test.cc23
-rw-r--r--test/wscript1
5 files changed, 232 insertions, 271 deletions
diff --git a/test/colour_conversion_test.cc b/test/colour_conversion_test.cc
index 54708753..f445d2e6 100644
--- a/test/colour_conversion_test.cc
+++ b/test/colour_conversion_test.cc
@@ -31,16 +31,36 @@
files in the program, then also delete it here.
*/
-#include "gamma_transfer_function.h"
+
#include "colour_conversion.h"
+#include "gamma_transfer_function.h"
#include "modified_gamma_transfer_function.h"
+#include "openjpeg_image.h"
+#include "piecewise_lut.h"
+#include "stream_operators.h"
+#include <boost/bind/bind.hpp>
+#include <boost/random.hpp>
+#include <boost/scoped_array.hpp>
#include <boost/test/unit_test.hpp>
#include <cmath>
+
+using std::cout;
+using std::list;
+using std::make_shared;
+using std::max;
using std::pow;
using std::shared_ptr;
+using std::shared_ptr;
+using std::string;
+using boost::optional;
+using boost::scoped_array;
+#if BOOST_VERSION >= 106100
+using namespace boost::placeholders;
+#endif
using namespace dcp;
+
static void
check_gamma (shared_ptr<const TransferFunction> tf, int bit_depth, bool inverse, float gamma)
{
@@ -154,3 +174,203 @@ BOOST_AUTO_TEST_CASE (colour_conversion_bradford_test)
BOOST_CHECK_CLOSE (b(2, 1), 0.0119945, 0.1);
BOOST_CHECK_CLOSE (b(2, 2), 0.7785377, 0.1);
}
+
+
+static
+void
+rgb_xyz_test_case(std::function<void (uint16_t*)> write_pixel)
+{
+ srand(0);
+ dcp::Size const size(640, 480);
+
+ scoped_array<uint8_t> rgb(new uint8_t[size.width * size.height * 6]);
+ for (int y = 0; y < size.height; ++y) {
+ uint16_t* p = reinterpret_cast<uint16_t*>(rgb.get() + y * size.width * 6);
+ for (int x = 0; x < size.width; ++x) {
+ write_pixel(p);
+ p += 3;
+ }
+ }
+
+ auto xyz = dcp::rgb_to_xyz(rgb.get(), size, size.width * 6, dcp::ColourConversion::srgb_to_dcp());
+
+ for (int y = 0; y < size.height; ++y) {
+ uint16_t* p = reinterpret_cast<uint16_t*>(rgb.get() + y * size.width * 6);
+ for (int x = 0; x < size.width; ++x) {
+
+ double cr = *p++ / 65535.0;
+ double cg = *p++ / 65535.0;
+ double cb = *p++ / 65535.0;
+
+ /* Input gamma */
+
+ if (cr < 0.04045) {
+ cr /= 12.92;
+ } else {
+ cr = pow ((cr + 0.055) / 1.055, 2.4);
+ }
+
+ if (cg < 0.04045) {
+ cg /= 12.92;
+ } else {
+ cg = pow ((cg + 0.055) / 1.055, 2.4);
+ }
+
+ if (cb < 0.04045) {
+ cb /= 12.92;
+ } else {
+ cb = pow ((cb + 0.055) / 1.055, 2.4);
+ }
+
+ /* Matrix */
+
+ double cx = cr * 0.4124564 + cg * 0.3575761 + cb * 0.1804375;
+ double cy = cr * 0.2126729 + cg * 0.7151522 + cb * 0.0721750;
+ double cz = cr * 0.0193339 + cg * 0.1191920 + cb * 0.9503041;
+
+ /* Compand */
+
+ cx *= 48 / 52.37;
+ cy *= 48 / 52.37;
+ cz *= 48 / 52.37;
+
+ /* Output gamma */
+
+ cx = pow (cx, 1 / 2.6);
+ cy = pow (cy, 1 / 2.6);
+ cz = pow (cz, 1 / 2.6);
+
+ BOOST_REQUIRE_CLOSE (cx * 4095, xyz->data(0)[y * size.width + x], 1);
+ BOOST_REQUIRE_CLOSE (cy * 4095, xyz->data(1)[y * size.width + x], 1);
+ BOOST_REQUIRE_CLOSE (cz * 4095, xyz->data(2)[y * size.width + x], 1);
+ }
+ }
+}
+
+
+/** Convert a test image from sRGB to XYZ and check that the transforms are right */
+BOOST_AUTO_TEST_CASE(rgb_xyz_test)
+{
+ {
+ int counter = 0;
+ rgb_xyz_test_case([&counter](uint16_t* p) {
+ p[0] = p[1] = p[2] = (counter << 4);
+ ++counter;
+ if (counter >= 4096) {
+ counter = 0;
+ }
+ });
+ }
+
+ boost::random::mt19937 rng(1);
+ boost::random::uniform_int_distribution<> dist(0, 4095);
+
+ rgb_xyz_test_case([&rng, &dist](uint16_t* p) {
+ p[0] = dist(rng) << 4;
+ p[1] = dist(rng) << 4;
+ p[2] = dist(rng) << 4;
+ });
+}
+
+
+/** Check the piecewise LUT that is used for inverse gamma calculation */
+BOOST_AUTO_TEST_CASE (rgb_xyz_lut_test)
+{
+ auto conversion = dcp::ColourConversion::rec709_to_dcp();
+ auto lut = dcp::make_inverse_gamma_lut(conversion.out_j2k());
+
+ for (double x = 0; x < 1; x += 0.000001) {
+ BOOST_CHECK(std::abs(lut.lookup(x) - lrint(pow(x, 1 / 2.6) * 4095)) < 2);
+ }
+}
+
+
+static list<string> notes;
+
+static void
+note_handler (dcp::NoteType n, string s)
+{
+ BOOST_REQUIRE_EQUAL (n, dcp::NoteType::NOTE);
+ notes.push_back (s);
+}
+
+/** Check that xyz_to_rgb clamps XYZ values correctly */
+BOOST_AUTO_TEST_CASE (xyz_rgb_range_test)
+{
+ auto xyz = make_shared<dcp::OpenJPEGImage>(dcp::Size(2, 2));
+
+ xyz->data(0)[0] = -4;
+ xyz->data(0)[1] = 6901;
+ xyz->data(0)[2] = 0;
+ xyz->data(0)[3] = 4095;
+ xyz->data(1)[0] = -4;
+ xyz->data(1)[1] = 6901;
+ xyz->data(1)[2] = 0;
+ xyz->data(1)[3] = 4095;
+ xyz->data(2)[0] = -4;
+ xyz->data(2)[1] = 6901;
+ xyz->data(2)[2] = 0;
+ xyz->data(2)[3] = 4095;
+
+ scoped_array<uint8_t> rgb (new uint8_t[2 * 2 * 6]);
+
+ notes.clear ();
+ dcp::xyz_to_rgb (
+ xyz, dcp::ColourConversion::srgb_to_dcp(), rgb.get(), 2 * 6, boost::optional<dcp::NoteHandler>(boost::bind(&note_handler, _1, _2))
+ );
+
+ /* The 6 out-of-range samples should have been noted */
+ BOOST_REQUIRE_EQUAL (notes.size(), 6U);
+ auto i = notes.begin ();
+ BOOST_REQUIRE_EQUAL (*i++, "XYZ value -4 out of range");
+ BOOST_REQUIRE_EQUAL (*i++, "XYZ value -4 out of range");
+ BOOST_REQUIRE_EQUAL (*i++, "XYZ value -4 out of range");
+ BOOST_REQUIRE_EQUAL (*i++, "XYZ value 6901 out of range");
+ BOOST_REQUIRE_EQUAL (*i++, "XYZ value 6901 out of range");
+ BOOST_REQUIRE_EQUAL (*i++, "XYZ value 6901 out of range");
+
+ /* And those samples should have been clamped, so check that they give the same result
+ as inputs at the extremes (0 and 4095).
+ */
+
+ auto buffer = reinterpret_cast<uint16_t*> (rgb.get ());
+ BOOST_REQUIRE_EQUAL (buffer[0 * 3 + 0], buffer[2 * 3 + 1]);
+ BOOST_REQUIRE_EQUAL (buffer[0 * 3 + 1], buffer[2 * 3 + 1]);
+ BOOST_REQUIRE_EQUAL (buffer[0 * 3 + 2], buffer[2 * 3 + 2]);
+
+ BOOST_REQUIRE_EQUAL (buffer[1 * 3 + 0], buffer[3 * 3 + 0]);
+ BOOST_REQUIRE_EQUAL (buffer[1 * 3 + 1], buffer[3 * 3 + 1]);
+ BOOST_REQUIRE_EQUAL (buffer[1 * 3 + 2], buffer[3 * 3 + 2]);
+}
+
+/** Convert an image from RGB to XYZ and back again */
+BOOST_AUTO_TEST_CASE (rgb_xyz_round_trip_test)
+{
+ srand (0);
+ dcp::Size const size (640, 480);
+
+ scoped_array<uint8_t> rgb (new uint8_t[size.width * size.height * 6]);
+ for (int y = 0; y < size.height; ++y) {
+ uint16_t* p = reinterpret_cast<uint16_t*> (rgb.get() + y * size.width * 6);
+ for (int x = 0; x < size.width; ++x) {
+ /* Write a 12-bit random number for each component */
+ for (int c = 0; c < 3; ++c) {
+ *p = (rand () & 0xfff) << 4;
+ ++p;
+ }
+ }
+ }
+
+ auto xyz = dcp::rgb_to_xyz(rgb.get(), size, size.width * 6, dcp::ColourConversion::srgb_to_dcp());
+ scoped_array<uint8_t> back (new uint8_t[size.width * size.height * 6]);
+ dcp::xyz_to_rgb(xyz, dcp::ColourConversion::srgb_to_dcp(), back.get(), size.width * 6);
+
+#if 0
+ uint16_t* p = reinterpret_cast<uint16_t*> (rgb.get ());
+ uint16_t* q = reinterpret_cast<uint16_t*> (back.get ());
+ for (int i = 0; i < (size.width * size.height); ++i) {
+ /* XXX: doesn't quite work */
+ // BOOST_REQUIRE_EQUAL (*p++, *q++);
+ }
+#endif
+}
diff --git a/test/decryption_test.cc b/test/decryption_test.cc
index 66402e24..061b50c8 100644
--- a/test/decryption_test.cc
+++ b/test/decryption_test.cc
@@ -47,7 +47,6 @@
#include "reel_picture_asset.h"
#include "reel_sound_asset.h"
#include "reel_smpte_text_asset.h"
-#include "rgb_xyz.h"
#include "smpte_text_asset.h"
#include "sound_asset.h"
#include "sound_asset_writer.h"
diff --git a/test/rgb_xyz_test.cc b/test/rgb_xyz_test.cc
deleted file mode 100644
index 59ace3d2..00000000
--- a/test/rgb_xyz_test.cc
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- Copyright (C) 2014-2021 Carl Hetherington <cth@carlh.net>
-
- This file is part of libdcp.
-
- libdcp is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- libdcp is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with libdcp. If not, see <http://www.gnu.org/licenses/>.
-
- 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 "colour_conversion.h"
-#include "openjpeg_image.h"
-#include "piecewise_lut.h"
-#include "rgb_xyz.h"
-#include "stream_operators.h"
-#include <boost/bind/bind.hpp>
-#include <boost/random.hpp>
-#include <boost/scoped_array.hpp>
-#include <boost/test/unit_test.hpp>
-
-
-using std::cout;
-using std::list;
-using std::make_shared;
-using std::max;
-using std::shared_ptr;
-using std::string;
-using boost::optional;
-using boost::scoped_array;
-#if BOOST_VERSION >= 106100
-using namespace boost::placeholders;
-#endif
-
-
-static
-void
-rgb_xyz_test_case (std::function<void (uint16_t*)> write_pixel)
-{
- srand (0);
- dcp::Size const size (640, 480);
-
- scoped_array<uint8_t> rgb (new uint8_t[size.width * size.height * 6]);
- for (int y = 0; y < size.height; ++y) {
- uint16_t* p = reinterpret_cast<uint16_t*> (rgb.get() + y * size.width * 6);
- for (int x = 0; x < size.width; ++x) {
- write_pixel (p);
- p += 3;
- }
- }
-
- auto xyz = dcp::rgb_to_xyz(rgb.get(), size, size.width * 6, dcp::ColourConversion::srgb_to_dcp());
-
- for (int y = 0; y < size.height; ++y) {
- uint16_t* p = reinterpret_cast<uint16_t*> (rgb.get() + y * size.width * 6);
- for (int x = 0; x < size.width; ++x) {
-
- double cr = *p++ / 65535.0;
- double cg = *p++ / 65535.0;
- double cb = *p++ / 65535.0;
-
- /* Input gamma */
-
- if (cr < 0.04045) {
- cr /= 12.92;
- } else {
- cr = pow ((cr + 0.055) / 1.055, 2.4);
- }
-
- if (cg < 0.04045) {
- cg /= 12.92;
- } else {
- cg = pow ((cg + 0.055) / 1.055, 2.4);
- }
-
- if (cb < 0.04045) {
- cb /= 12.92;
- } else {
- cb = pow ((cb + 0.055) / 1.055, 2.4);
- }
-
- /* Matrix */
-
- double cx = cr * 0.4124564 + cg * 0.3575761 + cb * 0.1804375;
- double cy = cr * 0.2126729 + cg * 0.7151522 + cb * 0.0721750;
- double cz = cr * 0.0193339 + cg * 0.1191920 + cb * 0.9503041;
-
- /* Compand */
-
- cx *= 48 / 52.37;
- cy *= 48 / 52.37;
- cz *= 48 / 52.37;
-
- /* Output gamma */
-
- cx = pow (cx, 1 / 2.6);
- cy = pow (cy, 1 / 2.6);
- cz = pow (cz, 1 / 2.6);
-
- BOOST_REQUIRE_CLOSE (cx * 4095, xyz->data(0)[y * size.width + x], 1);
- BOOST_REQUIRE_CLOSE (cy * 4095, xyz->data(1)[y * size.width + x], 1);
- BOOST_REQUIRE_CLOSE (cz * 4095, xyz->data(2)[y * size.width + x], 1);
- }
- }
-}
-
-
-/** Convert a test image from sRGB to XYZ and check that the transforms are right */
-BOOST_AUTO_TEST_CASE (rgb_xyz_test)
-{
- {
- int counter = 0;
- rgb_xyz_test_case ([&counter](uint16_t* p) {
- p[0] = p[1] = p[2] = (counter << 4);
- ++counter;
- if (counter >= 4096) {
- counter = 0;
- }
- });
- }
-
- boost::random::mt19937 rng(1);
- boost::random::uniform_int_distribution<> dist(0, 4095);
-
- rgb_xyz_test_case ([&rng, &dist](uint16_t* p) {
- p[0] = dist(rng) << 4;
- p[1] = dist(rng) << 4;
- p[2] = dist(rng) << 4;
- });
-}
-
-
-/** Check the piecewise LUT that is used for inverse gamma calculation */
-BOOST_AUTO_TEST_CASE (rgb_xyz_lut_test)
-{
- auto conversion = dcp::ColourConversion::rec709_to_dcp();
- auto lut = dcp::make_inverse_gamma_lut(conversion.out_j2k());
-
- for (double x = 0; x < 1; x += 0.000001) {
- BOOST_CHECK(std::abs(lut.lookup(x) - lrint(pow(x, 1 / 2.6) * 4095)) < 2);
- }
-}
-
-
-static list<string> notes;
-
-static void
-note_handler (dcp::NoteType n, string s)
-{
- BOOST_REQUIRE_EQUAL (n, dcp::NoteType::NOTE);
- notes.push_back (s);
-}
-
-/** Check that xyz_to_rgb clamps XYZ values correctly */
-BOOST_AUTO_TEST_CASE (xyz_rgb_range_test)
-{
- auto xyz = make_shared<dcp::OpenJPEGImage>(dcp::Size(2, 2));
-
- xyz->data(0)[0] = -4;
- xyz->data(0)[1] = 6901;
- xyz->data(0)[2] = 0;
- xyz->data(0)[3] = 4095;
- xyz->data(1)[0] = -4;
- xyz->data(1)[1] = 6901;
- xyz->data(1)[2] = 0;
- xyz->data(1)[3] = 4095;
- xyz->data(2)[0] = -4;
- xyz->data(2)[1] = 6901;
- xyz->data(2)[2] = 0;
- xyz->data(2)[3] = 4095;
-
- scoped_array<uint8_t> rgb (new uint8_t[2 * 2 * 6]);
-
- notes.clear ();
- dcp::xyz_to_rgb (
- xyz, dcp::ColourConversion::srgb_to_dcp(), rgb.get(), 2 * 6, boost::optional<dcp::NoteHandler>(boost::bind(&note_handler, _1, _2))
- );
-
- /* The 6 out-of-range samples should have been noted */
- BOOST_REQUIRE_EQUAL (notes.size(), 6U);
- auto i = notes.begin ();
- BOOST_REQUIRE_EQUAL (*i++, "XYZ value -4 out of range");
- BOOST_REQUIRE_EQUAL (*i++, "XYZ value -4 out of range");
- BOOST_REQUIRE_EQUAL (*i++, "XYZ value -4 out of range");
- BOOST_REQUIRE_EQUAL (*i++, "XYZ value 6901 out of range");
- BOOST_REQUIRE_EQUAL (*i++, "XYZ value 6901 out of range");
- BOOST_REQUIRE_EQUAL (*i++, "XYZ value 6901 out of range");
-
- /* And those samples should have been clamped, so check that they give the same result
- as inputs at the extremes (0 and 4095).
- */
-
- auto buffer = reinterpret_cast<uint16_t*> (rgb.get ());
- BOOST_REQUIRE_EQUAL (buffer[0 * 3 + 0], buffer[2 * 3 + 1]);
- BOOST_REQUIRE_EQUAL (buffer[0 * 3 + 1], buffer[2 * 3 + 1]);
- BOOST_REQUIRE_EQUAL (buffer[0 * 3 + 2], buffer[2 * 3 + 2]);
-
- BOOST_REQUIRE_EQUAL (buffer[1 * 3 + 0], buffer[3 * 3 + 0]);
- BOOST_REQUIRE_EQUAL (buffer[1 * 3 + 1], buffer[3 * 3 + 1]);
- BOOST_REQUIRE_EQUAL (buffer[1 * 3 + 2], buffer[3 * 3 + 2]);
-}
-
-/** Convert an image from RGB to XYZ and back again */
-BOOST_AUTO_TEST_CASE (rgb_xyz_round_trip_test)
-{
- srand (0);
- dcp::Size const size (640, 480);
-
- scoped_array<uint8_t> rgb (new uint8_t[size.width * size.height * 6]);
- for (int y = 0; y < size.height; ++y) {
- uint16_t* p = reinterpret_cast<uint16_t*> (rgb.get() + y * size.width * 6);
- for (int x = 0; x < size.width; ++x) {
- /* Write a 12-bit random number for each component */
- for (int c = 0; c < 3; ++c) {
- *p = (rand () & 0xfff) << 4;
- ++p;
- }
- }
- }
-
- auto xyz = dcp::rgb_to_xyz(rgb.get(), size, size.width * 6, dcp::ColourConversion::srgb_to_dcp());
- scoped_array<uint8_t> back (new uint8_t[size.width * size.height * 6]);
- dcp::xyz_to_rgb(xyz, dcp::ColourConversion::srgb_to_dcp(), back.get(), size.width * 6);
-
-#if 0
- uint16_t* p = reinterpret_cast<uint16_t*> (rgb.get ());
- uint16_t* q = reinterpret_cast<uint16_t*> (back.get ());
- for (int i = 0; i < (size.width * size.height); ++i) {
- /* XXX: doesn't quite work */
- // BOOST_REQUIRE_EQUAL (*p++, *q++);
- }
-#endif
-}
diff --git a/test/round_trip_test.cc b/test/round_trip_test.cc
index 1e87912a..c512c6a8 100644
--- a/test/round_trip_test.cc
+++ b/test/round_trip_test.cc
@@ -31,24 +31,23 @@
files in the program, then also delete it here.
*/
+
#include "certificate.h"
+#include "certificate_chain.h"
+#include "colour_conversion.h"
+#include "cpl.h"
#include "decrypted_kdm.h"
#include "encrypted_kdm.h"
-#include "certificate_chain.h"
#include "mono_j2k_picture_asset.h"
-#include "sound_asset.h"
-#include "reel.h"
-#include "test.h"
-#include "cpl.h"
-#include "mono_j2k_picture_frame.h"
-#include "certificate_chain.h"
-#include "mono_j2k_picture_asset_writer.h"
#include "mono_j2k_picture_asset_reader.h"
-#include "reel_picture_asset.h"
-#include "reel_mono_picture_asset.h"
+#include "mono_j2k_picture_asset_writer.h"
+#include "mono_j2k_picture_frame.h"
#include "openjpeg_image.h"
-#include "rgb_xyz.h"
-#include "colour_conversion.h"
+#include "reel.h"
+#include "reel_mono_picture_asset.h"
+#include "reel_picture_asset.h"
+#include "sound_asset.h"
+#include "test.h"
#include <boost/test/unit_test.hpp>
#include <boost/scoped_array.hpp>
#include <iostream>
diff --git a/test/wscript b/test/wscript
index 5e94b1f7..ebb3a1e3 100644
--- a/test/wscript
+++ b/test/wscript
@@ -107,7 +107,6 @@ def build(bld):
read_change_write_test.cc
reel_asset_test.cc
recovery_test.cc
- rgb_xyz_test.cc
round_trip_test.cc
scope_guard_test.cc
search_test.cc