transcode_api_test.cc (4564B)
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 <cstddef> 7 #include <cstdint> 8 #include <cstdlib> 9 #include <cstring> 10 #include <ostream> 11 #include <sstream> 12 #include <string> 13 #include <vector> 14 15 #include "lib/jpegli/decode.h" 16 #include "lib/jpegli/encode.h" 17 #include "lib/jpegli/libjpeg_test_util.h" 18 #include "lib/jpegli/test_params.h" 19 #include "lib/jpegli/test_utils.h" 20 #include "lib/jpegli/testing.h" 21 22 namespace jpegli { 23 namespace { 24 25 void TranscodeWithJpegli(const std::vector<uint8_t>& jpeg_input, 26 const CompressParams& jparams, 27 std::vector<uint8_t>* jpeg_output) { 28 jpeg_decompress_struct dinfo = {}; 29 jpeg_compress_struct cinfo = {}; 30 uint8_t* transcoded_data = nullptr; 31 unsigned long transcoded_size; // NOLINT 32 const auto try_catch_block = [&]() -> bool { 33 ERROR_HANDLER_SETUP(jpegli); 34 dinfo.err = cinfo.err; 35 dinfo.client_data = cinfo.client_data; 36 jpegli_create_decompress(&dinfo); 37 jpegli_mem_src(&dinfo, jpeg_input.data(), jpeg_input.size()); 38 EXPECT_EQ(JPEG_REACHED_SOS, 39 jpegli_read_header(&dinfo, /*require_image=*/TRUE)); 40 jvirt_barray_ptr* coef_arrays = jpegli_read_coefficients(&dinfo); 41 JPEGLI_TEST_ENSURE_TRUE(coef_arrays != nullptr); 42 jpegli_create_compress(&cinfo); 43 jpegli_mem_dest(&cinfo, &transcoded_data, &transcoded_size); 44 jpegli_copy_critical_parameters(&dinfo, &cinfo); 45 jpegli_set_progressive_level(&cinfo, jparams.progressive_mode); 46 cinfo.optimize_coding = jparams.optimize_coding; 47 jpegli_write_coefficients(&cinfo, coef_arrays); 48 jpegli_finish_compress(&cinfo); 49 jpegli_finish_decompress(&dinfo); 50 return true; 51 }; 52 ASSERT_TRUE(try_catch_block()); 53 jpegli_destroy_decompress(&dinfo); 54 jpegli_destroy_compress(&cinfo); 55 if (transcoded_data) { 56 jpeg_output->assign(transcoded_data, transcoded_data + transcoded_size); 57 free(transcoded_data); 58 } 59 } 60 61 struct TestConfig { 62 TestImage input; 63 CompressParams jparams; 64 }; 65 66 class TranscodeAPITestParam : public ::testing::TestWithParam<TestConfig> {}; 67 68 TEST_P(TranscodeAPITestParam, TestAPI) { 69 TestConfig config = GetParam(); 70 CompressParams& jparams = config.jparams; 71 GeneratePixels(&config.input); 72 73 // Start with sequential non-optimized jpeg. 74 jparams.progressive_mode = 0; 75 jparams.optimize_coding = 0; 76 std::vector<uint8_t> compressed; 77 ASSERT_TRUE(EncodeWithJpegli(config.input, jparams, &compressed)); 78 TestImage output0; 79 DecodeWithLibjpeg(jparams, DecompressParams(), compressed, &output0); 80 81 // Transcode first to a sequential optimized jpeg, and then further to 82 // a progressive jpeg. 83 for (int progr : {0, 2}) { 84 std::vector<uint8_t> transcoded; 85 jparams.progressive_mode = progr; 86 jparams.optimize_coding = 1; 87 TranscodeWithJpegli(compressed, jparams, &transcoded); 88 89 // We expect a size reduction of at least 2%. 90 EXPECT_LT(transcoded.size(), compressed.size() * 0.98f); 91 92 // Verify that transcoding is lossless. 93 TestImage output1; 94 DecodeWithLibjpeg(jparams, DecompressParams(), transcoded, &output1); 95 ASSERT_EQ(output0.pixels.size(), output1.pixels.size()); 96 EXPECT_EQ(0, memcmp(output0.pixels.data(), output1.pixels.data(), 97 output0.pixels.size())); 98 compressed = transcoded; 99 } 100 } 101 102 std::vector<TestConfig> GenerateTests() { 103 std::vector<TestConfig> all_tests; 104 const size_t xsize0 = 1024; 105 const size_t ysize0 = 768; 106 for (int dxsize : {0, 1, 8, 9}) { 107 for (int dysize : {0, 1, 8, 9}) { 108 for (int h_sampling : {1, 2}) { 109 for (int v_sampling : {1, 2}) { 110 TestConfig config; 111 config.input.xsize = xsize0 + dxsize; 112 config.input.ysize = ysize0 + dysize; 113 config.jparams.h_sampling = {h_sampling, 1, 1}; 114 config.jparams.v_sampling = {v_sampling, 1, 1}; 115 all_tests.push_back(config); 116 } 117 } 118 } 119 } 120 return all_tests; 121 } 122 123 std::ostream& operator<<(std::ostream& os, const TestConfig& c) { 124 os << c.input; 125 os << c.jparams; 126 return os; 127 } 128 129 std::string TestDescription( 130 const testing::TestParamInfo<TranscodeAPITestParam::ParamType>& info) { 131 std::stringstream name; 132 name << info.param; 133 return name.str(); 134 } 135 136 JPEGLI_INSTANTIATE_TEST_SUITE_P(TranscodeAPITest, TranscodeAPITestParam, 137 testing::ValuesIn(GenerateTests()), 138 TestDescription); 139 140 } // namespace 141 } // namespace jpegli