libjxl

FORK: libjxl patches used on blog
git clone https://git.neptards.moe/blog/libjxl.git
Log | Files | Refs | Submodules | README | LICENSE

color_management_test.cc (17367B)


      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 #include <jxl/cms.h>
      7 #include <jxl/cms_interface.h>
      8 #include <stdint.h>
      9 
     10 #include <algorithm>
     11 #include <cstddef>
     12 #include <cstdint>
     13 #include <cstdio>
     14 #include <cstdlib>
     15 #include <ostream>
     16 #include <string>
     17 #include <utility>
     18 #include <vector>
     19 
     20 #include "lib/jxl/base/common.h"
     21 #include "lib/jxl/base/compiler_specific.h"
     22 #include "lib/jxl/base/span.h"
     23 #include "lib/jxl/cms/color_encoding_cms.h"
     24 #include "lib/jxl/cms/opsin_params.h"
     25 #include "lib/jxl/color_encoding_internal.h"
     26 #include "lib/jxl/enc_xyb.h"
     27 #include "lib/jxl/image.h"
     28 #include "lib/jxl/image_bundle.h"
     29 #include "lib/jxl/image_metadata.h"
     30 #include "lib/jxl/image_ops.h"
     31 #include "lib/jxl/image_test_utils.h"
     32 #include "lib/jxl/test_utils.h"
     33 #include "lib/jxl/testing.h"
     34 
     35 namespace jxl {
     36 
     37 std::ostream& operator<<(std::ostream& os, const CIExy& xy) {
     38   return os << "{x=" << xy.x << ", y=" << xy.y << "}";
     39 }
     40 
     41 std::ostream& operator<<(std::ostream& os, const PrimariesCIExy& primaries) {
     42   return os << "{r=" << primaries.r << ", g=" << primaries.g
     43             << ", b=" << primaries.b << "}";
     44 }
     45 
     46 namespace {
     47 
     48 using ::testing::ElementsAre;
     49 using ::testing::FloatNear;
     50 
     51 // Small enough to be fast. If changed, must update Generate*.
     52 constexpr size_t kWidth = 16;
     53 
     54 constexpr size_t kNumThreads = 1;  // only have a single row.
     55 
     56 MATCHER_P(HasSameFieldsAs, expected, "") {
     57   if (arg.GetRenderingIntent() != expected.GetRenderingIntent()) {
     58     *result_listener << "which has a different rendering intent: "
     59                      << ToString(arg.GetRenderingIntent()) << " instead of "
     60                      << ToString(expected.GetRenderingIntent());
     61     return false;
     62   }
     63   if (arg.GetColorSpace() != expected.GetColorSpace()) {
     64     *result_listener << "which has a different color space: "
     65                      << ToString(arg.GetColorSpace()) << " instead of "
     66                      << ToString(expected.GetColorSpace());
     67     return false;
     68   }
     69   if (arg.GetWhitePointType() != expected.GetWhitePointType()) {
     70     *result_listener << "which has a different white point: "
     71                      << ToString(arg.GetWhitePointType()) << " instead of "
     72                      << ToString(expected.GetWhitePointType());
     73     return false;
     74   }
     75   if (arg.HasPrimaries() &&
     76       arg.GetPrimariesType() != expected.GetPrimariesType()) {
     77     *result_listener << "which has different primaries: "
     78                      << ToString(arg.GetPrimariesType()) << " instead of "
     79                      << ToString(expected.GetPrimariesType());
     80     return false;
     81   }
     82   if (!arg.Tf().IsSame(expected.Tf())) {
     83     static const auto tf_to_string =
     84         [](const jxl::cms::CustomTransferFunction& tf) {
     85           if (tf.have_gamma) {
     86             return "g" + ToString(tf.GetGamma());
     87           }
     88           return ToString(tf.transfer_function);
     89         };
     90     *result_listener << "which has a different transfer function: "
     91                      << tf_to_string(arg.Tf()) << " instead of "
     92                      << tf_to_string(expected.Tf());
     93     return false;
     94   }
     95   return true;
     96 }
     97 
     98 struct Globals {
     99   // TODO(deymo): Make this a const.
    100   static Globals* GetInstance() {
    101     static Globals ret;
    102     return &ret;
    103   }
    104 
    105  private:
    106   Globals() {
    107     in_gray = GenerateGray();
    108     in_color = GenerateColor();
    109     JXL_ASSIGN_OR_DIE(out_gray, ImageF::Create(kWidth, 1));
    110     JXL_ASSIGN_OR_DIE(out_color, ImageF::Create(kWidth * 3, 1));
    111 
    112     c_native = ColorEncoding::LinearSRGB(/*is_gray=*/false);
    113     c_gray = ColorEncoding::LinearSRGB(/*is_gray=*/true);
    114   }
    115 
    116   static ImageF GenerateGray() {
    117     JXL_ASSIGN_OR_DIE(ImageF gray, ImageF::Create(kWidth, 1));
    118     float* JXL_RESTRICT row = gray.Row(0);
    119     // Increasing left to right
    120     for (uint32_t x = 0; x < kWidth; ++x) {
    121       row[x] = x * 1.0f / (kWidth - 1);  // [0, 1]
    122     }
    123     return gray;
    124   }
    125 
    126   static ImageF GenerateColor() {
    127     JXL_ASSIGN_OR_DIE(ImageF image, ImageF::Create(kWidth * 3, 1));
    128     float* JXL_RESTRICT interleaved = image.Row(0);
    129     std::fill(interleaved, interleaved + kWidth * 3, 0.0f);
    130 
    131     // [0, 4): neutral
    132     for (int32_t x = 0; x < 4; ++x) {
    133       interleaved[3 * x + 0] = x * 1.0f / 3;  // [0, 1]
    134       interleaved[3 * x + 2] = interleaved[3 * x + 1] = interleaved[3 * x + 0];
    135     }
    136 
    137     // [4, 13): pure RGB with low/medium/high saturation
    138     for (int32_t c = 0; c < 3; ++c) {
    139       interleaved[3 * (4 + c) + c] = 0.08f + c * 0.01f;
    140       interleaved[3 * (7 + c) + c] = 0.75f + c * 0.01f;
    141       interleaved[3 * (10 + c) + c] = 1.0f;
    142     }
    143 
    144     // [13, 16): impure, not quite saturated RGB
    145     interleaved[3 * 13 + 0] = 0.86f;
    146     interleaved[3 * 13 + 2] = interleaved[3 * 13 + 1] = 0.16f;
    147     interleaved[3 * 14 + 1] = 0.87f;
    148     interleaved[3 * 14 + 2] = interleaved[3 * 14 + 0] = 0.16f;
    149     interleaved[3 * 15 + 2] = 0.88f;
    150     interleaved[3 * 15 + 1] = interleaved[3 * 15 + 0] = 0.16f;
    151 
    152     return image;
    153   }
    154 
    155  public:
    156   // ImageF so we can use VerifyRelativeError; all are interleaved RGB.
    157   ImageF in_gray;
    158   ImageF in_color;
    159   ImageF out_gray;
    160   ImageF out_color;
    161   ColorEncoding c_native;
    162   ColorEncoding c_gray;
    163 };
    164 
    165 class ColorManagementTest
    166     : public ::testing::TestWithParam<test::ColorEncodingDescriptor> {
    167  public:
    168   // "Same" pixels after converting g->c_native -> c -> g->c_native.
    169   static void VerifyPixelRoundTrip(const ColorEncoding& c) {
    170     Globals* g = Globals::GetInstance();
    171     const ColorEncoding& c_native = c.IsGray() ? g->c_gray : g->c_native;
    172     const JxlCmsInterface& cms = *JxlGetDefaultCms();
    173     ColorSpaceTransform xform_fwd(cms);
    174     ColorSpaceTransform xform_rev(cms);
    175     const float intensity_target =
    176         c.Tf().IsHLG() ? 1000 : kDefaultIntensityTarget;
    177     ASSERT_TRUE(
    178         xform_fwd.Init(c_native, c, intensity_target, kWidth, kNumThreads));
    179     ASSERT_TRUE(
    180         xform_rev.Init(c, c_native, intensity_target, kWidth, kNumThreads));
    181 
    182     const size_t thread = 0;
    183     const ImageF& in = c.IsGray() ? g->in_gray : g->in_color;
    184     ImageF* JXL_RESTRICT out = c.IsGray() ? &g->out_gray : &g->out_color;
    185     ASSERT_TRUE(
    186         xform_fwd.Run(thread, in.Row(0), xform_fwd.BufDst(thread), kWidth));
    187     ASSERT_TRUE(
    188         xform_rev.Run(thread, xform_fwd.BufDst(thread), out->Row(0), kWidth));
    189 
    190     // With lcms2, this value is lower: 5E-5
    191     double max_l1 = 7E-4;
    192     // Most are lower; reached 3E-7 with D60 AP0.
    193     double max_rel = 4E-7;
    194     if (c.IsGray()) max_rel = 2E-5;
    195     JXL_ASSERT_OK(VerifyRelativeError(in, *out, max_l1, max_rel, _));
    196   }
    197 };
    198 JXL_GTEST_INSTANTIATE_TEST_SUITE_P(ColorManagementTestInstantiation,
    199                                    ColorManagementTest,
    200                                    ::testing::ValuesIn(test::AllEncodings()));
    201 
    202 // Exercises the ColorManagement interface for ALL ColorEncoding synthesizable
    203 // via enums.
    204 TEST_P(ColorManagementTest, VerifyAllProfiles) {
    205   ColorEncoding c = ColorEncodingFromDescriptor(GetParam());
    206   printf("%s\n", Description(c).c_str());
    207 
    208   // Can create profile.
    209   ASSERT_TRUE(c.CreateICC());
    210 
    211   // Can set an equivalent ColorEncoding from the generated ICC profile.
    212   ColorEncoding c3;
    213   ASSERT_TRUE(c3.SetICC(IccBytes(c.ICC()), JxlGetDefaultCms()));
    214   EXPECT_THAT(c3, HasSameFieldsAs(c));
    215 
    216   VerifyPixelRoundTrip(c);
    217 }
    218 
    219 testing::Matcher<CIExy> CIExyIs(const double x, const double y) {
    220   static constexpr double kMaxError = 1e-4;
    221   return testing::AllOf(
    222       testing::Field(&CIExy::x, testing::DoubleNear(x, kMaxError)),
    223       testing::Field(&CIExy::y, testing::DoubleNear(y, kMaxError)));
    224 }
    225 
    226 testing::Matcher<PrimariesCIExy> PrimariesAre(
    227     const testing::Matcher<CIExy>& r, const testing::Matcher<CIExy>& g,
    228     const testing::Matcher<CIExy>& b) {
    229   return testing::AllOf(testing::Field(&PrimariesCIExy::r, r),
    230                         testing::Field(&PrimariesCIExy::g, g),
    231                         testing::Field(&PrimariesCIExy::b, b));
    232 }
    233 
    234 TEST_F(ColorManagementTest, sRGBChromaticity) {
    235   const ColorEncoding sRGB = ColorEncoding::SRGB();
    236   EXPECT_THAT(sRGB.GetWhitePoint(), CIExyIs(0.3127, 0.3290));
    237   EXPECT_THAT(sRGB.GetPrimaries(),
    238               PrimariesAre(CIExyIs(0.64, 0.33), CIExyIs(0.30, 0.60),
    239                            CIExyIs(0.15, 0.06)));
    240 }
    241 
    242 TEST_F(ColorManagementTest, D2700Chromaticity) {
    243   std::vector<uint8_t> icc_data =
    244       jxl::test::ReadTestData("jxl/color_management/sRGB-D2700.icc");
    245   IccBytes icc;
    246   Bytes(icc_data).AppendTo(icc);
    247   ColorEncoding sRGB_D2700;
    248   ASSERT_TRUE(sRGB_D2700.SetICC(std::move(icc), JxlGetDefaultCms()));
    249 
    250   EXPECT_THAT(sRGB_D2700.GetWhitePoint(), CIExyIs(0.45986, 0.41060));
    251   // The illuminant-relative chromaticities of this profile's primaries are the
    252   // same as for sRGB. It is the PCS-relative chromaticities that would be
    253   // different.
    254   EXPECT_THAT(sRGB_D2700.GetPrimaries(),
    255               PrimariesAre(CIExyIs(0.64, 0.33), CIExyIs(0.30, 0.60),
    256                            CIExyIs(0.15, 0.06)));
    257 }
    258 
    259 TEST_F(ColorManagementTest, D2700ToSRGB) {
    260   std::vector<uint8_t> icc_data =
    261       jxl::test::ReadTestData("jxl/color_management/sRGB-D2700.icc");
    262   IccBytes icc;
    263   Bytes(icc_data).AppendTo(icc);
    264   ColorEncoding sRGB_D2700;
    265   ASSERT_TRUE(sRGB_D2700.SetICC(std::move(icc), JxlGetDefaultCms()));
    266 
    267   ColorSpaceTransform transform(*JxlGetDefaultCms());
    268   ASSERT_TRUE(transform.Init(sRGB_D2700, ColorEncoding::SRGB(),
    269                              kDefaultIntensityTarget, 1, 1));
    270   const float sRGB_D2700_values[3] = {0.863, 0.737, 0.490};
    271   float sRGB_values[3];
    272   ASSERT_TRUE(transform.Run(0, sRGB_D2700_values, sRGB_values, 1));
    273   EXPECT_THAT(sRGB_values,
    274               ElementsAre(FloatNear(0.914, 1e-3), FloatNear(0.745, 1e-3),
    275                           FloatNear(0.601, 1e-3)));
    276 }
    277 
    278 TEST_F(ColorManagementTest, P3HlgTo2020Hlg) {
    279   ColorEncoding p3_hlg;
    280   p3_hlg.SetColorSpace(ColorSpace::kRGB);
    281   ASSERT_TRUE(p3_hlg.SetWhitePointType(WhitePoint::kD65));
    282   ASSERT_TRUE(p3_hlg.SetPrimariesType(Primaries::kP3));
    283   p3_hlg.Tf().SetTransferFunction(TransferFunction::kHLG);
    284   ASSERT_TRUE(p3_hlg.CreateICC());
    285 
    286   ColorEncoding rec2020_hlg = p3_hlg;
    287   ASSERT_TRUE(rec2020_hlg.SetPrimariesType(Primaries::k2100));
    288   ASSERT_TRUE(rec2020_hlg.CreateICC());
    289 
    290   ColorSpaceTransform transform(*JxlGetDefaultCms());
    291   ASSERT_TRUE(transform.Init(p3_hlg, rec2020_hlg, 1000, 1, 1));
    292   const float p3_hlg_values[3] = {0., 0.75, 0.};
    293   float rec2020_hlg_values[3];
    294   ASSERT_TRUE(transform.Run(0, p3_hlg_values, rec2020_hlg_values, 1));
    295   EXPECT_THAT(rec2020_hlg_values,
    296               ElementsAre(FloatNear(0.3973, 1e-4), FloatNear(0.7382, 1e-4),
    297                           FloatNear(0.1183, 1e-4)));
    298 }
    299 
    300 TEST_F(ColorManagementTest, HlgOotf) {
    301   ColorEncoding p3_hlg;
    302   p3_hlg.SetColorSpace(ColorSpace::kRGB);
    303   ASSERT_TRUE(p3_hlg.SetWhitePointType(WhitePoint::kD65));
    304   ASSERT_TRUE(p3_hlg.SetPrimariesType(Primaries::kP3));
    305   p3_hlg.Tf().SetTransferFunction(TransferFunction::kHLG);
    306   ASSERT_TRUE(p3_hlg.CreateICC());
    307 
    308   ColorSpaceTransform transform_to_1000(*JxlGetDefaultCms());
    309   ASSERT_TRUE(
    310       transform_to_1000.Init(p3_hlg, ColorEncoding::LinearSRGB(), 1000, 1, 1));
    311   // HDR reference white: https://www.itu.int/pub/R-REP-BT.2408-4-2021
    312   float p3_hlg_values[3] = {0.75, 0.75, 0.75};
    313   float linear_srgb_values[3];
    314   ASSERT_TRUE(transform_to_1000.Run(0, p3_hlg_values, linear_srgb_values, 1));
    315   // On a 1000-nit display, HDR reference white should be 203 cd/m² which is
    316   // 0.203 times the maximum.
    317   EXPECT_THAT(linear_srgb_values,
    318               ElementsAre(FloatNear(0.203, 1e-3), FloatNear(0.203, 1e-3),
    319                           FloatNear(0.203, 1e-3)));
    320 
    321   ColorSpaceTransform transform_to_400(*JxlGetDefaultCms());
    322   ASSERT_TRUE(
    323       transform_to_400.Init(p3_hlg, ColorEncoding::LinearSRGB(), 400, 1, 1));
    324   ASSERT_TRUE(transform_to_400.Run(0, p3_hlg_values, linear_srgb_values, 1));
    325   // On a 400-nit display, it should be 100 cd/m².
    326   EXPECT_THAT(linear_srgb_values,
    327               ElementsAre(FloatNear(0.250, 1e-3), FloatNear(0.250, 1e-3),
    328                           FloatNear(0.250, 1e-3)));
    329 
    330   p3_hlg_values[2] = 0.50;
    331   ASSERT_TRUE(transform_to_1000.Run(0, p3_hlg_values, linear_srgb_values, 1));
    332   EXPECT_THAT(linear_srgb_values,
    333               ElementsAre(FloatNear(0.201, 1e-3), FloatNear(0.201, 1e-3),
    334                           FloatNear(0.050, 1e-3)));
    335 
    336   ColorSpaceTransform transform_from_400(*JxlGetDefaultCms());
    337   ASSERT_TRUE(
    338       transform_from_400.Init(ColorEncoding::LinearSRGB(), p3_hlg, 400, 1, 1));
    339   linear_srgb_values[0] = linear_srgb_values[1] = linear_srgb_values[2] = 0.250;
    340   ASSERT_TRUE(transform_from_400.Run(0, linear_srgb_values, p3_hlg_values, 1));
    341   EXPECT_THAT(p3_hlg_values,
    342               ElementsAre(FloatNear(0.75, 1e-3), FloatNear(0.75, 1e-3),
    343                           FloatNear(0.75, 1e-3)));
    344 
    345   ColorEncoding grayscale_hlg;
    346   grayscale_hlg.SetColorSpace(ColorSpace::kGray);
    347   ASSERT_TRUE(grayscale_hlg.SetWhitePointType(WhitePoint::kD65));
    348   grayscale_hlg.Tf().SetTransferFunction(TransferFunction::kHLG);
    349   ASSERT_TRUE(grayscale_hlg.CreateICC());
    350 
    351   ColorSpaceTransform grayscale_transform(*JxlGetDefaultCms());
    352   ASSERT_TRUE(grayscale_transform.Init(
    353       grayscale_hlg, ColorEncoding::LinearSRGB(/*is_gray=*/true), 1000, 1, 1));
    354   const float grayscale_hlg_value = 0.75;
    355   float linear_grayscale_value;
    356   ASSERT_TRUE(grayscale_transform.Run(0, &grayscale_hlg_value,
    357                                       &linear_grayscale_value, 1));
    358   EXPECT_THAT(linear_grayscale_value, FloatNear(0.203, 1e-3));
    359 }
    360 
    361 TEST_F(ColorManagementTest, XYBProfile) {
    362   ColorEncoding c_xyb;
    363   c_xyb.SetColorSpace(ColorSpace::kXYB);
    364   c_xyb.SetRenderingIntent(RenderingIntent::kPerceptual);
    365   ASSERT_TRUE(c_xyb.CreateICC());
    366   ColorEncoding c_native = ColorEncoding::LinearSRGB(false);
    367 
    368   static const size_t kGridDim = 17;
    369   static const size_t kNumColors = kGridDim * kGridDim * kGridDim;
    370   const JxlCmsInterface& cms = *JxlGetDefaultCms();
    371   ColorSpaceTransform xform(cms);
    372   ASSERT_TRUE(
    373       xform.Init(c_xyb, c_native, kDefaultIntensityTarget, kNumColors, 1));
    374 
    375   ImageMetadata metadata;
    376   metadata.color_encoding = c_native;
    377   ImageBundle ib(&metadata);
    378   JXL_ASSIGN_OR_DIE(Image3F native, Image3F::Create(kNumColors, 1));
    379   float mul = 1.0f / (kGridDim - 1);
    380   for (size_t ir = 0, x = 0; ir < kGridDim; ++ir) {
    381     for (size_t ig = 0; ig < kGridDim; ++ig) {
    382       for (size_t ib = 0; ib < kGridDim; ++ib, ++x) {
    383         native.PlaneRow(0, 0)[x] = ir * mul;
    384         native.PlaneRow(1, 0)[x] = ig * mul;
    385         native.PlaneRow(2, 0)[x] = ib * mul;
    386       }
    387     }
    388   }
    389   ib.SetFromImage(std::move(native), c_native);
    390   const Image3F& in = *ib.color();
    391   JXL_ASSIGN_OR_DIE(Image3F opsin, Image3F::Create(kNumColors, 1));
    392   JXL_CHECK(ToXYB(ib, nullptr, &opsin, cms, nullptr));
    393 
    394   JXL_ASSIGN_OR_DIE(Image3F opsin2, Image3F::Create(kNumColors, 1));
    395   CopyImageTo(opsin, &opsin2);
    396   ScaleXYB(&opsin2);
    397 
    398   float* src = xform.BufSrc(0);
    399   for (size_t i = 0; i < kNumColors; ++i) {
    400     for (size_t c = 0; c < 3; ++c) {
    401       src[3 * i + c] = opsin2.PlaneRow(c, 0)[i];
    402     }
    403   }
    404 
    405   float* dst = xform.BufDst(0);
    406   ASSERT_TRUE(xform.Run(0, src, dst, kNumColors));
    407 
    408   JXL_ASSIGN_OR_DIE(Image3F out, Image3F::Create(kNumColors, 1));
    409   for (size_t i = 0; i < kNumColors; ++i) {
    410     for (size_t c = 0; c < 3; ++c) {
    411       out.PlaneRow(c, 0)[i] = dst[3 * i + c];
    412     }
    413   }
    414 
    415   auto debug_print_color = [&](size_t i) {
    416     printf(
    417         "(%f, %f, %f) -> (%9.6f, %f, %f) -> (%f, %f, %f) -> "
    418         "(%9.6f, %9.6f, %9.6f)",
    419         in.PlaneRow(0, 0)[i], in.PlaneRow(1, 0)[i], in.PlaneRow(2, 0)[i],
    420         opsin.PlaneRow(0, 0)[i], opsin.PlaneRow(1, 0)[i],
    421         opsin.PlaneRow(2, 0)[i], opsin2.PlaneRow(0, 0)[i],
    422         opsin2.PlaneRow(1, 0)[i], opsin2.PlaneRow(2, 0)[i],
    423         out.PlaneRow(0, 0)[i], out.PlaneRow(1, 0)[i], out.PlaneRow(2, 0)[i]);
    424   };
    425 
    426   float max_err[3] = {};
    427   size_t max_err_i[3] = {};
    428   for (size_t i = 0; i < kNumColors; ++i) {
    429     for (size_t c = 0; c < 3; ++c) {
    430       // debug_print_color(i); printf("\n");
    431       float err = std::abs(in.PlaneRow(c, 0)[i] - out.PlaneRow(c, 0)[i]);
    432       if (err > max_err[c]) {
    433         max_err[c] = err;
    434         max_err_i[c] = i;
    435       }
    436     }
    437   }
    438   static float kMaxError[3] = {9e-4, 4e-4, 5e-4};
    439   printf("Maximum errors:\n");
    440   for (size_t c = 0; c < 3; ++c) {
    441     debug_print_color(max_err_i[c]);
    442     printf("    %f\n", max_err[c]);
    443     EXPECT_LT(max_err[c], kMaxError[c]);
    444   }
    445 }
    446 
    447 TEST_F(ColorManagementTest, GoldenXYBCube) {
    448   std::vector<int32_t> actual;
    449   const jxl::cms::ColorCube3D& cube = jxl::cms::UnscaledA2BCube();
    450   for (size_t ix = 0; ix < 2; ++ix) {
    451     for (size_t iy = 0; iy < 2; ++iy) {
    452       for (size_t ib = 0; ib < 2; ++ib) {
    453         const jxl::cms::ColorCube0D& out_f = cube[ix][iy][ib];
    454         for (int i = 0; i < 3; ++i) {
    455           int32_t val = static_cast<int32_t>(0.5f + 65535 * out_f[i]);
    456           ASSERT_TRUE(val >= 0 && val <= 65535);
    457           actual.push_back(val);
    458         }
    459       }
    460     }
    461   }
    462 
    463   std::vector<int32_t> expected = {0,     3206,  0,     0,     3206,  28873,
    464                                    62329, 65535, 36662, 62329, 65535, 65535,
    465                                    3206,  0,     0,     3206,  0,     28873,
    466                                    65535, 62329, 36662, 65535, 62329, 65535};
    467   EXPECT_EQ(actual, expected);
    468 }
    469 
    470 }  // namespace
    471 }  // namespace jxl