test_utils.h (9421B)
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 #ifndef LIB_JXL_TEST_UTILS_H_ 7 #define LIB_JXL_TEST_UTILS_H_ 8 9 // TODO(eustas): reduce includes (move to .cc) 10 11 // Macros and functions useful for tests. 12 13 #include <jxl/codestream_header.h> 14 #include <jxl/memory_manager.h> 15 #include <jxl/thread_parallel_runner_cxx.h> 16 17 #include <cstddef> 18 #include <cstdint> 19 #include <ostream> 20 #include <vector> 21 22 #include "lib/extras/dec/jxl.h" 23 #include "lib/extras/enc/jxl.h" 24 #include "lib/extras/packed_image.h" 25 #include "lib/jxl/base/compiler_specific.h" 26 #include "lib/jxl/base/data_parallel.h" 27 #include "lib/jxl/base/span.h" 28 #include "lib/jxl/base/status.h" 29 #include "lib/jxl/butteraugli/butteraugli.h" 30 #include "lib/jxl/codec_in_out.h" 31 #include "lib/jxl/color_encoding_internal.h" 32 #include "lib/jxl/enc_params.h" 33 34 #define TEST_LIBJPEG_SUPPORT() \ 35 do { \ 36 if (!jxl::extras::CanDecode(jxl::extras::Codec::kJPG)) { \ 37 fprintf(stderr, "Skipping test because of missing libjpeg codec.\n"); \ 38 return; \ 39 } \ 40 } while (0) 41 42 namespace jxl { 43 44 struct AuxOut; 45 class CodecInOut; 46 class PaddedBytes; 47 struct PassesEncoderState; 48 class ThreadPool; 49 50 namespace test { 51 52 void Check(bool ok); 53 54 #define JXL_TEST_ASSIGN_OR_DIE(lhs, statusor) \ 55 PRIVATE_JXL_TEST_ASSIGN_OR_DIE_IMPL( \ 56 JXL_JOIN(assign_or_die_temporary_variable, __LINE__), lhs, statusor) 57 58 // NOLINTBEGIN(bugprone-macro-parentheses) 59 #define PRIVATE_JXL_TEST_ASSIGN_OR_DIE_IMPL(name, lhs, statusor) \ 60 auto name = statusor; \ 61 ::jxl::test::Check(name.ok()); \ 62 lhs = std::move(name).value_(); 63 // NOLINTEND(bugprone-macro-parentheses) 64 65 std::string GetTestDataPath(const std::string& filename); 66 67 // Returns an ICC profile output by the JPEG XL decoder for RGB_D65_SRG_Rel_Lin, 68 // but with, on purpose, rXYZ, bXYZ and gXYZ (the RGB primaries) switched to a 69 // different order to ensure the profile does not match any known profile, so 70 // the encoder cannot encode it in a compact struct instead. 71 jxl::IccBytes GetIccTestProfile(); 72 73 std::vector<uint8_t> GetCompressedIccTestProfile(); 74 75 std::vector<uint8_t> ReadTestData(const std::string& filename); 76 77 void JxlBasicInfoSetFromPixelFormat(JxlBasicInfo* basic_info, 78 const JxlPixelFormat* pixel_format); 79 80 void DefaultAcceptedFormats(extras::JXLDecompressParams& dparams); 81 82 template <typename Params> 83 void SetThreadParallelRunner(Params params, ThreadPool* pool) { 84 if (pool && !params.runner_opaque) { 85 params.runner = pool->runner(); 86 params.runner_opaque = pool->runner_opaque(); 87 } 88 } 89 90 Status DecodeFile(extras::JXLDecompressParams dparams, Span<const uint8_t> file, 91 CodecInOut* JXL_RESTRICT io, ThreadPool* pool = nullptr); 92 93 bool Roundtrip(CodecInOut* io, const CompressParams& cparams, 94 extras::JXLDecompressParams dparams, 95 CodecInOut* JXL_RESTRICT io2, std::stringstream& failures, 96 size_t* compressed_size = nullptr, ThreadPool* pool = nullptr); 97 98 // Returns compressed size [bytes]. 99 size_t Roundtrip(const extras::PackedPixelFile& ppf_in, 100 const extras::JXLCompressParams& cparams, 101 extras::JXLDecompressParams dparams, ThreadPool* pool, 102 extras::PackedPixelFile* ppf_out); 103 104 // A POD descriptor of a ColorEncoding. Only used in tests as the return value 105 // of AllEncodings(). 106 struct ColorEncodingDescriptor { 107 ColorSpace color_space; 108 WhitePoint white_point; 109 Primaries primaries; 110 TransferFunction tf; 111 RenderingIntent rendering_intent; 112 }; 113 114 ColorEncoding ColorEncodingFromDescriptor(const ColorEncodingDescriptor& desc); 115 116 // Define the operator<< for tests. 117 static inline ::std::ostream& operator<<(::std::ostream& os, 118 const ColorEncodingDescriptor& c) { 119 return os << "ColorEncoding/" << Description(ColorEncodingFromDescriptor(c)); 120 } 121 122 // Returns ColorEncodingDescriptors, which are only used in tests. To obtain a 123 // ColorEncoding object call ColorEncodingFromDescriptor and then call 124 // ColorEncoding::CreateProfile() on that object to generate a profile. 125 std::vector<ColorEncodingDescriptor> AllEncodings(); 126 127 // Returns a CodecInOut based on the buf, xsize, ysize, and the assumption 128 // that the buffer was created using `GetSomeTestImage`. 129 jxl::CodecInOut SomeTestImageToCodecInOut(const std::vector<uint8_t>& buf, 130 size_t num_channels, size_t xsize, 131 size_t ysize); 132 133 bool Near(double expected, double value, double max_dist); 134 135 float LoadLEFloat16(const uint8_t* p); 136 137 float LoadBEFloat16(const uint8_t* p); 138 139 size_t GetPrecision(JxlDataType data_type); 140 141 size_t GetDataBits(JxlDataType data_type); 142 143 // Procedure to convert pixels to double precision, not efficient, but 144 // well-controlled for testing. It uses double, to be able to represent all 145 // precisions needed for the maximum data types the API supports: uint32_t 146 // integers, and, single precision float. The values are in range 0-1 for SDR. 147 std::vector<double> ConvertToRGBA32(const uint8_t* pixels, size_t xsize, 148 size_t ysize, const JxlPixelFormat& format, 149 double factor = 0.0); 150 151 // Returns amount of pixels which differ between the two pictures. Image b is 152 // the image after roundtrip after roundtrip, image a before roundtrip. There 153 // are more strict requirements for the alpha channel and grayscale values of 154 // the output image. 155 size_t ComparePixels(const uint8_t* a, const uint8_t* b, size_t xsize, 156 size_t ysize, const JxlPixelFormat& format_a, 157 const JxlPixelFormat& format_b, 158 double threshold_multiplier = 1.0); 159 160 double DistanceRMS(const uint8_t* a, const uint8_t* b, size_t xsize, 161 size_t ysize, const JxlPixelFormat& format); 162 163 float ButteraugliDistance(const extras::PackedPixelFile& a, 164 const extras::PackedPixelFile& b, 165 ThreadPool* pool = nullptr); 166 167 float ButteraugliDistance(const ImageBundle& rgb0, const ImageBundle& rgb1, 168 const ButteraugliParams& params, 169 const JxlCmsInterface& cms, ImageF* distmap = nullptr, 170 ThreadPool* pool = nullptr, 171 bool ignore_alpha = false); 172 173 float ButteraugliDistance(const std::vector<ImageBundle>& frames0, 174 const std::vector<ImageBundle>& frames1, 175 const ButteraugliParams& params, 176 const JxlCmsInterface& cms, ImageF* distmap = nullptr, 177 ThreadPool* pool = nullptr); 178 179 float Butteraugli3Norm(const extras::PackedPixelFile& a, 180 const extras::PackedPixelFile& b, 181 ThreadPool* pool = nullptr); 182 183 float ComputeDistance2(const extras::PackedPixelFile& a, 184 const extras::PackedPixelFile& b); 185 186 float ComputePSNR(const extras::PackedPixelFile& a, 187 const extras::PackedPixelFile& b); 188 189 bool SameAlpha(const extras::PackedPixelFile& a, 190 const extras::PackedPixelFile& b); 191 192 bool SamePixels(const extras::PackedImage& a, const extras::PackedImage& b); 193 194 bool SamePixels(const extras::PackedPixelFile& a, 195 const extras::PackedPixelFile& b); 196 197 extras::JXLCompressParams CompressParamsForLossless(); 198 199 StatusOr<ImageF> GetImage(const extras::PackedPixelFile& ppf); 200 201 StatusOr<Image3F> GetColorImage(const extras::PackedPixelFile& ppf); 202 203 class ThreadPoolForTests { 204 public: 205 explicit ThreadPoolForTests(int num_threads) { 206 runner_ = 207 JxlThreadParallelRunnerMake(/* memory_manager */ nullptr, num_threads); 208 pool_ = 209 jxl::make_unique<ThreadPool>(JxlThreadParallelRunner, runner_.get()); 210 } 211 ThreadPoolForTests(const ThreadPoolForTests&) = delete; 212 ThreadPoolForTests& operator&(const ThreadPoolForTests&) = delete; 213 ThreadPool* get() { return pool_.get(); } 214 215 private: 216 JxlThreadParallelRunnerPtr runner_; 217 std::unique_ptr<ThreadPool> pool_; 218 }; 219 220 // `icc` may be empty afterwards - if so, call CreateProfile. Does not append, 221 // clears any original data that was in icc. 222 // If `output_limit` is not 0, then returns error if resulting profile would be 223 // longer than `output_limit` 224 Status ReadICC(BitReader* JXL_RESTRICT reader, 225 std::vector<uint8_t>* JXL_RESTRICT icc); 226 227 // Compresses pixels from `io` (given in any ColorEncoding). 228 // `io->metadata.m.original` must be set. 229 Status EncodeFile(const CompressParams& params, CodecInOut* io, 230 std::vector<uint8_t>* compressed, ThreadPool* pool = nullptr); 231 232 constexpr const char* BoolToCStr(bool b) { return b ? "true" : "false"; } 233 234 } // namespace test 235 236 bool operator==(const jxl::Bytes& a, const jxl::Bytes& b); 237 238 // Allow using EXPECT_EQ on jxl::Bytes 239 bool operator!=(const jxl::Bytes& a, const jxl::Bytes& b); 240 241 } // namespace jxl 242 243 #endif // LIB_JXL_TEST_UTILS_H_