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