tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

splines_test.cc (15784B)


      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 "lib/jxl/splines.h"
      7 
      8 #include <jxl/cms.h>
      9 #include <jxl/memory_manager.h>
     10 
     11 #include <cstddef>
     12 #include <cstdint>
     13 #include <cstdio>
     14 #include <ostream>
     15 #include <utility>
     16 #include <vector>
     17 
     18 #include "lib/extras/codec.h"
     19 #include "lib/jxl/base/common.h"
     20 #include "lib/jxl/base/compiler_specific.h"
     21 #include "lib/jxl/base/printf_macros.h"
     22 #include "lib/jxl/base/rect.h"
     23 #include "lib/jxl/base/span.h"
     24 #include "lib/jxl/base/status.h"
     25 #include "lib/jxl/chroma_from_luma.h"
     26 #include "lib/jxl/common.h"
     27 #include "lib/jxl/enc_aux_out.h"
     28 #include "lib/jxl/enc_bit_writer.h"
     29 #include "lib/jxl/enc_splines.h"
     30 #include "lib/jxl/image.h"
     31 #include "lib/jxl/image_ops.h"
     32 #include "lib/jxl/image_test_utils.h"
     33 #include "lib/jxl/test_memory_manager.h"
     34 #include "lib/jxl/test_utils.h"
     35 #include "lib/jxl/testing.h"
     36 
     37 namespace jxl {
     38 
     39 std::ostream& operator<<(std::ostream& os, const Spline::Point& p) {
     40  return os << "(" << p.x << ", " << p.y << ")";
     41 }
     42 
     43 std::ostream& operator<<(std::ostream& os, const Spline& spline) {
     44  return os << "(spline with " << spline.control_points.size()
     45            << " control points)";
     46 }
     47 
     48 namespace {
     49 
     50 using ::jxl::test::ReadTestData;
     51 
     52 constexpr int kQuantizationAdjustment = 0;
     53 const ColorCorrelation color_correlation{};
     54 const float kYToX = color_correlation.YtoXRatio(0);
     55 const float kYToB = color_correlation.YtoBRatio(0);
     56 
     57 constexpr float kTolerance = 0.003125;
     58 
     59 Status DequantizeSplines(const Splines& splines,
     60                         std::vector<Spline>& dequantized) {
     61  const auto& quantized_splines = splines.QuantizedSplines();
     62  const auto& starting_points = splines.StartingPoints();
     63  JXL_ENSURE(quantized_splines.size() == starting_points.size());
     64 
     65  uint64_t total = 0;
     66  for (size_t i = 0; i < quantized_splines.size(); ++i) {
     67    dequantized.emplace_back();
     68    JXL_RETURN_IF_ERROR(quantized_splines[i].Dequantize(
     69        starting_points[i], kQuantizationAdjustment, kYToX, kYToB, 2u << 30u,
     70        &total, dequantized.back()));
     71  }
     72  return true;
     73 }
     74 
     75 }  // namespace
     76 
     77 TEST(SplinesTest, Serialization) {
     78  JxlMemoryManager* memory_manager = jxl::test::MemoryManager();
     79  Spline spline1{
     80      /*control_points=*/{
     81          {109, 54}, {218, 159}, {80, 3}, {110, 274}, {94, 185}, {17, 277}},
     82      /*color_dct=*/
     83      {Dct32{36.3, 39.7, 23.2, 67.5, 4.4,  71.5, 62.3, 32.3, 92.2, 10.1, 10.8,
     84             9.2,  6.1,  10.5, 79.1, 7,    24.6, 90.8, 5.5,  84,   43.8, 49,
     85             33.5, 78.9, 54.5, 77.9, 62.1, 51.4, 36.4, 14.3, 83.7, 35.4},
     86       Dct32{9.4,  53.4, 9.5,  74.9, 72.7, 26.7, 7.9,  0.9, 84.9, 23.2, 26.5,
     87             31.1, 91,   11.7, 74.1, 39.3, 23.7, 82.5, 4.8, 2.7,  61.2, 96.4,
     88             13.7, 66.7, 62.9, 82.4, 5.9,  98.7, 21.5, 7.9, 51.7, 63.1},
     89       Dct32{48,   39.3, 6.9,  26.3, 33.3, 6.2,  1.7,  98.9, 59.9, 59.6, 95,
     90             61.3, 82.7, 53,   6.1,  30.4, 34.7, 96.9, 93.4, 17,   38.8, 80.8,
     91             63,   18.6, 43.6, 32.3, 61,   20.2, 24.3, 28.3, 69.1, 62.4}},
     92      /*sigma_dct=*/{32.7, 21.5, 44.4, 1.8,  45.8, 90.6, 29.3, 59.2,
     93                     23.7, 85.2, 84.8, 27.2, 42.1, 84.1, 50.6, 17.6,
     94                     93.7, 4.9,  2.6,  69.8, 94.9, 52,   24.3, 18.8,
     95                     12.1, 95.7, 28.5, 81.4, 89.9, 31.4, 74.8, 52}};
     96  Spline spline2{
     97      /*control_points=*/{{172, 309},
     98                          {196, 277},
     99                          {42, 238},
    100                          {114, 350},
    101                          {307, 290},
    102                          {316, 269},
    103                          {124, 66},
    104                          {233, 267}},
    105      /*color_dct=*/
    106      {Dct32{15,   28.9, 22, 6.6,  41.8, 83,   8.6,  56.8, 68.9, 9.7,  5.4,
    107             19.8, 70.8, 90, 52.5, 65.2, 7.8,  23.5, 26.4, 72.2, 64.7, 87.1,
    108             1.3,  67.5, 46, 68.4, 65.4, 35.5, 29.1, 13,   41.6, 23.9},
    109       Dct32{47.7, 79.4, 62.7, 29.1, 96.8, 18.5, 17.6, 15.2, 80.5, 56,  96.2,
    110             59.9, 26.7, 96.1, 92.3, 42.1, 35.8, 54,   23.2, 55,   76,  35.8,
    111             58.4, 88.7, 2.4,  78.1, 95.6, 27.5, 6.6,  78.5, 24.1, 69.8},
    112       Dct32{43.8, 96.5, 0.9,  95.1, 49.1, 71.2, 25.1, 33.6, 75.2, 95,  82.1,
    113             19.7, 10.5, 44.9, 50,   93.3, 83.5, 99.5, 64.6, 54,   3.5, 99.7,
    114             45.3, 82.1, 22.4, 37.9, 60,   32.2, 12.6, 4.6,  65.5, 96.4}},
    115      /*sigma_dct=*/{72.5, 2.6,  41.7, 2.2,  39.7, 79.1, 69.6, 19.9,
    116                     92.3, 71.5, 41.9, 62.1, 30,   49.4, 70.3, 45.3,
    117                     62.5, 47.2, 46.7, 41.2, 90.8, 46.8, 91.2, 55,
    118                     8.1,  69.6, 25.4, 84.7, 61.7, 27.6, 3.7,  46.9}};
    119  Spline spline3{
    120      /*control_points=*/{{100, 186},
    121                          {257, 97},
    122                          {170, 49},
    123                          {25, 169},
    124                          {309, 104},
    125                          {232, 237},
    126                          {385, 101},
    127                          {122, 168},
    128                          {26, 300},
    129                          {390, 88}},
    130      /*color_dct=*/
    131      {Dct32{16.9, 64.8, 4.2,  10.6, 23.5, 17,   79.3, 5.7,  60.4, 16.6, 94.9,
    132             63.7, 87.6, 10.5, 3.8,  61.1, 22.9, 81.9, 80.4, 40.5, 45.9, 25.4,
    133             39.8, 30,   50.2, 90.4, 27.9, 93.7, 65.1, 48.2, 22.3, 43.9},
    134       Dct32{24.9, 66,   3.5,  90.2, 97.1, 15.8, 35.6, 0.6,  68,   39.6, 24.4,
    135             85.9, 57.7, 77.6, 47.5, 67.9, 4.3,  5.4,  91.2, 58.5, 0.1,  52.2,
    136             3.5,  47.8, 63.2, 43.5, 85.8, 35.8, 50.2, 35.9, 19.2, 48.2},
    137       Dct32{82.8, 44.9, 76.4, 39.5, 94.1, 14.3, 89.8, 10,   10.5, 74.5, 56.3,
    138             65.8, 7.8,  23.3, 52.8, 99.3, 56.8, 46,   76.7, 13.5, 67,   22.4,
    139             29.9, 43.3, 70.3, 26,   74.3, 53.9, 62,   19.1, 49.3, 46.7}},
    140      /*sigma_dct=*/{83.5, 1.7,  25.1, 18.7, 46.5, 75.3, 28,   62.3,
    141                     50.3, 23.3, 85.6, 96,   45.8, 33.1, 33.4, 52.9,
    142                     26.3, 58.5, 19.6, 70,   92.6, 22.5, 57,   21.6,
    143                     76.8, 87.5, 22.9, 66.3, 35.7, 35.6, 56.8, 67.2}};
    144  std::vector<Spline> spline_data{spline1, spline2, spline3};
    145 
    146  std::vector<QuantizedSpline> quantized_splines;
    147  std::vector<Spline::Point> starting_points;
    148  for (const Spline& spline : spline_data) {
    149    JXL_ASSIGN_OR_QUIT(
    150        QuantizedSpline qspline,
    151        QuantizedSpline::Create(spline, kQuantizationAdjustment, kYToX, kYToB),
    152        "Failed to create QuantizedSpline.");
    153    quantized_splines.emplace_back(std::move(qspline));
    154    starting_points.push_back(spline.control_points.front());
    155  }
    156 
    157  Splines splines(kQuantizationAdjustment, std::move(quantized_splines),
    158                  std::move(starting_points));
    159  std::vector<Spline> quantized_spline_data;
    160  ASSERT_TRUE(DequantizeSplines(splines, quantized_spline_data));
    161  EXPECT_EQ(quantized_spline_data.size(), spline_data.size());
    162  for (size_t i = 0; i < quantized_spline_data.size(); ++i) {
    163    const Spline& actual = quantized_spline_data[i];
    164    const Spline& expected = spline_data[i];
    165    const auto& actual_points = actual.control_points;
    166    const auto& expected_points = expected.control_points;
    167    EXPECT_EQ(actual_points.size(), expected_points.size());
    168    for (size_t j = 0; j < actual_points.size(); ++j) {
    169      EXPECT_NEAR(actual_points[j].x, expected_points[j].x, kTolerance)
    170          << "spline " << i << " point " << j;
    171      EXPECT_NEAR(actual_points[j].y, expected_points[j].y, kTolerance)
    172          << "spline " << i << " point " << j;
    173    }
    174  }
    175 
    176  BitWriter writer{memory_manager};
    177  ASSERT_TRUE(EncodeSplines(splines, &writer, LayerType::Splines,
    178                            HistogramParams(), nullptr));
    179  writer.ZeroPadToByte();
    180  const size_t bits_written = writer.BitsWritten();
    181 
    182  printf("Wrote %" PRIuS " bits of splines.\n", bits_written);
    183 
    184  BitReader reader(writer.GetSpan());
    185  Splines decoded_splines;
    186  ASSERT_TRUE(
    187      decoded_splines.Decode(memory_manager, &reader, /*num_pixels=*/1000));
    188  ASSERT_TRUE(reader.JumpToByteBoundary());
    189  EXPECT_EQ(reader.TotalBitsConsumed(), bits_written);
    190  ASSERT_TRUE(reader.Close());
    191 
    192  std::vector<Spline> decoded_spline_data;
    193  ASSERT_TRUE(DequantizeSplines(decoded_splines, decoded_spline_data));
    194 
    195  EXPECT_EQ(decoded_spline_data.size(), quantized_spline_data.size());
    196  for (size_t i = 0; i < decoded_spline_data.size(); ++i) {
    197    const Spline& actual = decoded_spline_data[i];
    198    const Spline& expected = quantized_spline_data[i];
    199    const auto& actual_points = actual.control_points;
    200    const auto& expected_points = expected.control_points;
    201    EXPECT_EQ(actual_points.size(), expected_points.size());
    202    for (size_t j = 0; j < actual_points.size(); ++j) {
    203      EXPECT_NEAR(actual_points[j].x, expected_points[j].x, kTolerance)
    204          << "spline " << i << " point " << j;
    205      EXPECT_NEAR(actual_points[j].y, expected_points[j].y, kTolerance)
    206          << "spline " << i << " point " << j;
    207    }
    208 
    209    const auto& actual_color_dct = actual.color_dct;
    210    const auto& expected_color_dct = expected.color_dct;
    211    for (size_t j = 0; j < actual_color_dct.size(); ++j) {
    212      EXPECT_ARRAY_NEAR(actual_color_dct[j], expected_color_dct[j], kTolerance);
    213    }
    214    EXPECT_ARRAY_NEAR(actual.sigma_dct, expected.sigma_dct, kTolerance);
    215  }
    216 }
    217 
    218 TEST(SplinesTest, TooManySplinesTest) {
    219  if (JXL_CRASH_ON_ERROR) {
    220    GTEST_SKIP() << "Skipping due to JXL_CRASH_ON_ERROR";
    221  }
    222  JxlMemoryManager* memory_manager = jxl::test::MemoryManager();
    223  // This is more than the limit for 1000 pixels.
    224  const size_t kNumSplines = 300;
    225 
    226  std::vector<QuantizedSpline> quantized_splines;
    227  std::vector<Spline::Point> starting_points;
    228  for (size_t i = 0; i < kNumSplines; i++) {
    229    Spline spline{
    230        /*control_points=*/{{1.f + i, 2}, {10.f + i, 25}, {30.f + i, 300}},
    231        /*color_dct=*/
    232        {Dct32{1.f, 0.2f, 0.1f}, Dct32{35.7f, 10.3f}, Dct32{35.7f, 7.8f}},
    233        /*sigma_dct=*/{10.f, 0.f, 0.f, 2.f}};
    234    JXL_ASSIGN_OR_QUIT(
    235        QuantizedSpline qspline,
    236        QuantizedSpline::Create(spline, kQuantizationAdjustment, kYToX, kYToB),
    237        "Failed to create QuantizedSpline.");
    238    quantized_splines.emplace_back(std::move(qspline));
    239    starting_points.push_back(spline.control_points.front());
    240  }
    241 
    242  Splines splines(kQuantizationAdjustment, std::move(quantized_splines),
    243                  std::move(starting_points));
    244  BitWriter writer{memory_manager};
    245  ASSERT_TRUE(EncodeSplines(splines, &writer, LayerType::Splines,
    246                            HistogramParams(SpeedTier::kFalcon, 1), nullptr));
    247  writer.ZeroPadToByte();
    248  // Re-read splines.
    249  BitReader reader(writer.GetSpan());
    250  Splines decoded_splines;
    251  EXPECT_FALSE(
    252      decoded_splines.Decode(memory_manager, &reader, /*num_pixels=*/1000));
    253  EXPECT_TRUE(reader.Close());
    254 }
    255 
    256 TEST(SplinesTest, DuplicatePoints) {
    257  if (JXL_CRASH_ON_ERROR) {
    258    GTEST_SKIP() << "Skipping due to JXL_CRASH_ON_ERROR";
    259  }
    260  JxlMemoryManager* memory_manager = jxl::test::MemoryManager();
    261  std::vector<Spline::Point> control_points{
    262      {9, 54}, {118, 159}, {97, 3},  // Repeated.
    263      {97, 3}, {10, 40},   {150, 25}, {120, 300}};
    264  Spline spline{
    265      control_points,
    266      /*color_dct=*/
    267      {Dct32{1.f, 0.2f, 0.1f}, Dct32{35.7f, 10.3f}, Dct32{35.7f, 7.8f}},
    268      /*sigma_dct=*/{10.f, 0.f, 0.f, 2.f}};
    269  std::vector<Spline> spline_data{spline};
    270  std::vector<QuantizedSpline> quantized_splines;
    271  std::vector<Spline::Point> starting_points;
    272  for (const Spline& spline : spline_data) {
    273    JXL_ASSIGN_OR_QUIT(
    274        QuantizedSpline qspline,
    275        QuantizedSpline::Create(spline, kQuantizationAdjustment, kYToX, kYToB),
    276        "Failed to create QuantizedSpline.");
    277    quantized_splines.emplace_back(std::move(qspline));
    278    starting_points.push_back(spline.control_points.front());
    279  }
    280  Splines splines(kQuantizationAdjustment, std::move(quantized_splines),
    281                  std::move(starting_points));
    282 
    283  JXL_TEST_ASSIGN_OR_DIE(Image3F image,
    284                         Image3F::Create(memory_manager, 320, 320));
    285  ZeroFillImage(&image);
    286  EXPECT_FALSE(splines.InitializeDrawCache(image.xsize(), image.ysize(),
    287                                           color_correlation));
    288 }
    289 
    290 TEST(SplinesTest, Drawing) {
    291  JxlMemoryManager* memory_manager = jxl::test::MemoryManager();
    292  CodecInOut io_expected{memory_manager};
    293  const std::vector<uint8_t> orig = ReadTestData("jxl/splines.pfm");
    294  ASSERT_TRUE(SetFromBytes(Bytes(orig), &io_expected,
    295                           /*pool=*/nullptr));
    296 
    297  std::vector<Spline::Point> control_points{{9, 54},  {118, 159}, {97, 3},
    298                                            {10, 40}, {150, 25},  {120, 300}};
    299  // Use values that survive quant/decorellation roundtrip.
    300  const Spline spline{
    301      control_points,
    302      /*color_dct=*/
    303      {Dct32{0.4989345073699951171875000f, 0.4997999966144561767578125f},
    304       Dct32{0.4772970676422119140625000f, 0.f, 0.5250000357627868652343750f},
    305       Dct32{-0.0176776945590972900390625f, 0.4900000095367431640625000f,
    306             0.5250000357627868652343750f}},
    307      /*sigma_dct=*/
    308      {0.9427147507667541503906250f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
    309       0.6665999889373779296875000f}};
    310  std::vector<Spline> spline_data = {spline};
    311  std::vector<QuantizedSpline> quantized_splines;
    312  std::vector<Spline::Point> starting_points;
    313  for (const Spline& spline : spline_data) {
    314    JXL_ASSIGN_OR_QUIT(
    315        QuantizedSpline qspline,
    316        QuantizedSpline::Create(spline, kQuantizationAdjustment, kYToX, kYToB),
    317        "Failed to create QuantizedSpline.");
    318    quantized_splines.emplace_back(std::move(qspline));
    319    starting_points.push_back(spline.control_points.front());
    320  }
    321  Splines splines(kQuantizationAdjustment, std::move(quantized_splines),
    322                  std::move(starting_points));
    323 
    324  JXL_TEST_ASSIGN_OR_DIE(Image3F image,
    325                         Image3F::Create(memory_manager, 320, 320));
    326  ZeroFillImage(&image);
    327  ASSERT_TRUE(splines.InitializeDrawCache(image.xsize(), image.ysize(),
    328                                          color_correlation));
    329  splines.AddTo(&image, Rect(image));
    330 
    331  CodecInOut io_actual{memory_manager};
    332  JXL_TEST_ASSIGN_OR_DIE(Image3F image2,
    333                         Image3F::Create(memory_manager, 320, 320));
    334  ASSERT_TRUE(CopyImageTo(image, &image2));
    335  ASSERT_TRUE(io_actual.SetFromImage(std::move(image2), ColorEncoding::SRGB()));
    336  ASSERT_TRUE(io_actual.frames[0].TransformTo(io_expected.Main().c_current(),
    337                                              *JxlGetDefaultCms()));
    338 
    339  JXL_TEST_ASSERT_OK(VerifyRelativeError(
    340      *io_expected.Main().color(), *io_actual.Main().color(), 1e-2f, 1e-1f, _));
    341 }
    342 
    343 TEST(SplinesTest, ClearedEveryFrame) {
    344  JxlMemoryManager* memory_manager = jxl::test::MemoryManager();
    345  CodecInOut io_expected{memory_manager};
    346  const std::vector<uint8_t> bytes_expected =
    347      ReadTestData("jxl/spline_on_first_frame.png");
    348  ASSERT_TRUE(SetFromBytes(Bytes(bytes_expected), &io_expected,
    349                           /*pool=*/nullptr));
    350  CodecInOut io_actual{memory_manager};
    351  const std::vector<uint8_t> bytes_actual =
    352      ReadTestData("jxl/spline_on_first_frame.jxl");
    353  ASSERT_TRUE(test::DecodeFile({}, Bytes(bytes_actual), &io_actual));
    354 
    355  ASSERT_TRUE(io_actual.frames[0].TransformTo(ColorEncoding::SRGB(),
    356                                              *JxlGetDefaultCms()));
    357  for (size_t c = 0; c < 3; ++c) {
    358    for (size_t y = 0; y < io_actual.ysize(); ++y) {
    359      float* const JXL_RESTRICT row = io_actual.Main().color()->PlaneRow(c, y);
    360      for (size_t x = 0; x < io_actual.xsize(); ++x) {
    361        row[x] = Clamp1(row[x], 0.f, 1.f);
    362      }
    363    }
    364  }
    365  JXL_TEST_ASSERT_OK(VerifyRelativeError(
    366      *io_expected.Main().color(), *io_actual.Main().color(), 1e-2f, 1e-1f, _));
    367 }
    368 
    369 }  // namespace jxl