diff options
Diffstat (limited to 'third_party/jpeg-xl/lib/jpegli/test_utils.h')
-rw-r--r-- | third_party/jpeg-xl/lib/jpegli/test_utils.h | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/third_party/jpeg-xl/lib/jpegli/test_utils.h b/third_party/jpeg-xl/lib/jpegli/test_utils.h new file mode 100644 index 0000000000..f300b5de9e --- /dev/null +++ b/third_party/jpeg-xl/lib/jpegli/test_utils.h @@ -0,0 +1,318 @@ +// Copyright (c) the JPEG XL Project Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#ifndef LIB_JPEGLI_TEST_UTILS_H_ +#define LIB_JPEGLI_TEST_UTILS_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <algorithm> +#include <string> +#include <vector> + +/* clang-format off */ +#include <stdio.h> +#include <jpeglib.h> +#include <setjmp.h> +/* clang-format on */ + +#include "lib/jpegli/common.h" + +namespace jpegli { + +// We define this here as well to make sure that the *_api_test.cc tests only +// use the public API and therefore we don't include any *_internal.h headers. +template <typename T1, typename T2> +constexpr inline T1 DivCeil(T1 a, T2 b) { + return (a + b - 1) / b; +} + +#define ERROR_HANDLER_SETUP(flavor) \ + jpeg_error_mgr jerr; \ + jmp_buf env; \ + cinfo.err = flavor##_std_error(&jerr); \ + if (setjmp(env)) { \ + return false; \ + } \ + cinfo.client_data = reinterpret_cast<void*>(&env); \ + cinfo.err->error_exit = [](j_common_ptr cinfo) { \ + (*cinfo->err->output_message)(cinfo); \ + jmp_buf* env = reinterpret_cast<jmp_buf*>(cinfo->client_data); \ + flavor##_destroy(cinfo); \ + longjmp(*env, 1); \ + }; + +#define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0])) + +static constexpr int kSpecialMarker0 = 0xe5; +static constexpr int kSpecialMarker1 = 0xe9; +static constexpr uint8_t kMarkerData[] = {0, 1, 255, 0, 17}; +static constexpr uint8_t kMarkerSequence[] = {0xe6, 0xe8, 0xe7, + 0xe6, 0xe7, 0xe8}; +static constexpr size_t kMarkerSequenceLen = ARRAY_SIZE(kMarkerSequence); + +static constexpr jpeg_scan_info kScript1[] = { + {1, {0}, 0, 63, 0, 0}, + {1, {1}, 0, 63, 0, 0}, + {1, {2}, 0, 63, 0, 0}, +}; + +static constexpr jpeg_scan_info kScript2[] = { + {3, {0, 1, 2}, 0, 0, 0, 0}, + {1, {0}, 1, 63, 0, 0}, + {1, {1}, 1, 63, 0, 0}, + {1, {2}, 1, 63, 0, 0}, +}; +static constexpr jpeg_scan_info kScript3[] = { + {1, {0}, 0, 0, 0, 0}, {1, {1}, 0, 0, 0, 0}, {1, {2}, 0, 0, 0, 0}, + {1, {0}, 1, 63, 0, 0}, {1, {1}, 1, 63, 0, 0}, {1, {2}, 1, 63, 0, 0}, +}; +static constexpr jpeg_scan_info kScript4[] = { + {3, {0, 1, 2}, 0, 0, 0, 0}, {1, {0}, 1, 63, 0, 1}, {1, {1}, 1, 63, 0, 1}, + {1, {2}, 1, 63, 0, 1}, {1, {0}, 1, 63, 1, 0}, {1, {1}, 1, 63, 1, 0}, + {1, {2}, 1, 63, 1, 0}, +}; + +struct ScanScript { + int num_scans; + const jpeg_scan_info* scans; +}; + +static constexpr ScanScript kTestScript[] = { + {ARRAY_SIZE(kScript1), kScript1}, + {ARRAY_SIZE(kScript2), kScript2}, + {ARRAY_SIZE(kScript3), kScript3}, + {ARRAY_SIZE(kScript4), kScript4}, +}; +static constexpr int kNumTestScripts = ARRAY_SIZE(kTestScript); + +static constexpr int kLastScan = 0xffff; + +static uint32_t kTestColorMap[] = { + 0x000000, 0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0x00ffff, + 0xff00ff, 0xffffff, 0x6251fc, 0x45d9c7, 0xa7f059, 0xd9a945, + 0xfa4e44, 0xceaffc, 0xbad7db, 0xc1f0b1, 0xdbca9a, 0xfacac5, + 0xf201ff, 0x0063db, 0x00f01c, 0xdbb204, 0xf12f0c, 0x7ba1dc}; +static constexpr int kTestColorMapNumColors = ARRAY_SIZE(kTestColorMap); + +std::string IOMethodName(JpegliDataType data_type, JpegliEndianness endianness); + +std::string ColorSpaceName(J_COLOR_SPACE colorspace); + +enum JpegIOMode { + PIXELS, + RAW_DATA, + COEFFICIENTS, +}; + +struct CustomQuantTable { + int slot_idx = 0; + uint16_t table_type = 0; + int scale_factor = 100; + bool add_raw = false; + bool force_baseline = true; + std::vector<unsigned int> basic_table; + std::vector<unsigned int> quantval; + void Generate(); +}; + +struct TestImage { + size_t xsize = 2268; + size_t ysize = 1512; + J_COLOR_SPACE color_space = JCS_RGB; + size_t components = 3; + JpegliDataType data_type = JPEGLI_TYPE_UINT8; + JpegliEndianness endianness = JPEGLI_NATIVE_ENDIAN; + std::vector<uint8_t> pixels; + std::vector<std::vector<uint8_t>> raw_data; + std::vector<std::vector<JCOEF>> coeffs; + void AllocatePixels() { + pixels.resize(ysize * xsize * components * + jpegli_bytes_per_sample(data_type)); + } + void Clear() { + pixels.clear(); + raw_data.clear(); + coeffs.clear(); + } +}; + +std::ostream& operator<<(std::ostream& os, const TestImage& input); + +struct CompressParams { + int quality = 90; + bool set_jpeg_colorspace = false; + J_COLOR_SPACE jpeg_color_space = JCS_UNKNOWN; + std::vector<int> quant_indexes; + std::vector<CustomQuantTable> quant_tables; + std::vector<int> h_sampling; + std::vector<int> v_sampling; + std::vector<int> comp_ids; + int override_JFIF = -1; + int override_Adobe = -1; + bool add_marker = false; + bool simple_progression = false; + // -1 is library default + // 0, 1, 2 is set through jpegli_set_progressive_level() + // 2 + N is kScriptN + int progressive_mode = -1; + unsigned int restart_interval = 0; + int restart_in_rows = 0; + int smoothing_factor = 0; + int optimize_coding = -1; + bool use_flat_dc_luma_code = false; + bool omit_standard_tables = false; + bool xyb_mode = false; + bool libjpeg_mode = false; + bool use_adaptive_quantization = true; + std::vector<uint8_t> icc; + + int h_samp(int c) const { return h_sampling.empty() ? 1 : h_sampling[c]; } + int v_samp(int c) const { return v_sampling.empty() ? 1 : v_sampling[c]; } + int max_h_sample() const { + auto it = std::max_element(h_sampling.begin(), h_sampling.end()); + return it == h_sampling.end() ? 1 : *it; + } + int max_v_sample() const { + auto it = std::max_element(v_sampling.begin(), v_sampling.end()); + return it == v_sampling.end() ? 1 : *it; + } + int comp_width(const TestImage& input, int c) const { + return DivCeil(input.xsize * h_samp(c), max_h_sample() * DCTSIZE) * DCTSIZE; + } + int comp_height(const TestImage& input, int c) const { + return DivCeil(input.ysize * v_samp(c), max_v_sample() * DCTSIZE) * DCTSIZE; + } +}; + +std::ostream& operator<<(std::ostream& os, const CompressParams& jparams); + +void VerifyHeader(const CompressParams& jparams, j_decompress_ptr cinfo); +void VerifyScanHeader(const CompressParams& jparams, j_decompress_ptr cinfo); + +enum ColorQuantMode { + CQUANT_1PASS, + CQUANT_2PASS, + CQUANT_EXTERNAL, + CQUANT_REUSE, +}; + +struct ScanDecompressParams { + int max_scan_number; + J_DITHER_MODE dither_mode; + ColorQuantMode color_quant_mode; +}; + +struct DecompressParams { + float size_factor = 1.0f; + size_t chunk_size = 65536; + size_t max_output_lines = 16; + JpegIOMode output_mode = PIXELS; + JpegliDataType data_type = JPEGLI_TYPE_UINT8; + JpegliEndianness endianness = JPEGLI_NATIVE_ENDIAN; + bool set_out_color_space = false; + J_COLOR_SPACE out_color_space = JCS_UNKNOWN; + bool crop_output = false; + bool do_block_smoothing = false; + bool do_fancy_upsampling = true; + bool skip_scans = false; + int scale_num = 1; + int scale_denom = 1; + bool quantize_colors = false; + int desired_number_of_colors = 256; + std::vector<ScanDecompressParams> scan_params; +}; + +void SetDecompressParams(const DecompressParams& dparams, + j_decompress_ptr cinfo, bool is_jpegli); + +void SetScanDecompressParams(const DecompressParams& dparams, + j_decompress_ptr cinfo, int scan_number, + bool is_jpegli); + +void CopyCoefficients(j_decompress_ptr cinfo, jvirt_barray_ptr* coef_arrays, + TestImage* output); + +void UnmapColors(uint8_t* row, size_t xsize, int components, + JSAMPARRAY colormap, size_t num_colors); + +std::string GetTestDataPath(const std::string& filename); +std::vector<uint8_t> ReadTestData(const std::string& filename); + +class PNMParser { + public: + explicit PNMParser(const uint8_t* data, const size_t len) + : pos_(data), end_(data + len) {} + + // Sets "pos" to the first non-header byte/pixel on success. + bool ParseHeader(const uint8_t** pos, size_t* xsize, size_t* ysize, + size_t* num_channels, size_t* bitdepth); + + private: + static bool IsLineBreak(const uint8_t c) { return c == '\r' || c == '\n'; } + static bool IsWhitespace(const uint8_t c) { + return IsLineBreak(c) || c == '\t' || c == ' '; + } + + bool ParseUnsigned(size_t* number); + + bool SkipWhitespace(); + + const uint8_t* pos_; + const uint8_t* const end_; +}; + +bool ReadPNM(const std::vector<uint8_t>& data, size_t* xsize, size_t* ysize, + size_t* num_channels, size_t* bitdepth, + std::vector<uint8_t>* pixels); + +void SetNumChannels(J_COLOR_SPACE colorspace, size_t* channels); + +void ConvertToGrayscale(TestImage* img); + +void GeneratePixels(TestImage* img); + +void GenerateRawData(const CompressParams& jparams, TestImage* img); + +void GenerateCoeffs(const CompressParams& jparams, TestImage* img); + +void EncodeWithJpegli(const TestImage& input, const CompressParams& jparams, + j_compress_ptr cinfo); + +bool EncodeWithJpegli(const TestImage& input, const CompressParams& jparams, + std::vector<uint8_t>* compressed); + +// Verifies that an image encoded with libjpegli can be decoded with libjpeg, +// and checks that the jpeg coding metadata matches jparams. +void DecodeAllScansWithLibjpeg(const CompressParams& jparams, + const DecompressParams& dparams, + const std::vector<uint8_t>& compressed, + std::vector<TestImage>* output_progression); +void DecodeWithLibjpeg(const CompressParams& jparams, + const DecompressParams& dparams, j_decompress_ptr cinfo, + TestImage* output); +void DecodeWithLibjpeg(const CompressParams& jparams, + const DecompressParams& dparams, + const std::vector<uint8_t>& compressed, + TestImage* output); + +double DistanceRms(const TestImage& input, const TestImage& output, + size_t start_line, size_t num_lines, + double* max_diff = nullptr); + +double DistanceRms(const TestImage& input, const TestImage& output, + double* max_diff = nullptr); + +void VerifyOutputImage(const TestImage& input, const TestImage& output, + size_t start_line, size_t num_lines, double max_rms, + double max_diff = 255.0); + +void VerifyOutputImage(const TestImage& input, const TestImage& output, + double max_rms, double max_diff = 255.0); + +} // namespace jpegli + +#endif // LIB_JPEGLI_TEST_UTILS_H_ |