// 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.
// What type of codestream format in the boxes to use for testing enum CodeStreamBoxFormat { // Do not use box format at all, only pure codestream
kCSBF_None, // Have a single codestream box, with its actual size given in the box
kCSBF_Single, // Have a single codestream box, with box size 0 (final box running to end)
kCSBF_Single_Zero_Terminated, // Single codestream box, with another unknown box behind it
kCSBF_Single_Other, // Have multiple partial codestream boxes
kCSBF_Multi, // Have multiple partial codestream boxes, with final box size 0 (running // to end)
kCSBF_Multi_Zero_Terminated, // Have multiple partial codestream boxes, terminated by non-codestream box
kCSBF_Multi_Other_Terminated, // Have multiple partial codestream boxes, terminated by non-codestream box // that has its size set to 0 (running to end)
kCSBF_Multi_Other_Zero_Terminated, // Have multiple partial codestream boxes, and the first one has a content // of zero length
kCSBF_Multi_First_Empty, // Have multiple partial codestream boxes, and the last one has a content // of zero length and there is an unknown empty box at the end
kCSBF_Multi_Last_Empty_Other, // Have a compressed exif box before a regular codestream box
kCSBF_Brob_Exif, // Not a value but used for counting amount of enum entries
kCSBF_NUM_ENTRIES,
};
// After the full image was output, JxlDecoderProcessInput should return // success to indicate all is done, unless we requested boxes and the last // box was not a terminal unbounded box, in which case it should ask for // more input.
JxlDecoderStatus expected_status =
expect_success ? JXL_DEC_SUCCESS : JXL_DEC_NEED_MORE_INPUT;
EXPECT_EQ(expected_status, process_input(dec));
return pixels;
}
// Decodes one-shot with the API for non-streaming decoding tests.
std::vector<uint8_t> DecodeWithAPI(Span<const uint8_t> compressed, const JxlPixelFormat& format, bool use_callback, bool set_buffer_early, bool use_resizable_runner, bool require_boxes, bool expect_success) {
JxlDecoder* dec = JxlDecoderCreate(nullptr);
std::vector<uint8_t> pixels =
DecodeWithAPI(dec, compressed, format, use_callback, set_buffer_early,
use_resizable_runner, require_boxes, expect_success);
JxlDecoderDestroy(dec); return pixels;
}
// TODO(lode): add multi-threaded test when multithreaded pixel decoding from // API is implemented.
TEST(DecodeTest, DefaultParallelRunnerTest) {
JxlDecoder* dec = JxlDecoderCreate(nullptr);
EXPECT_NE(nullptr, dec);
EXPECT_EQ(JXL_DEC_SUCCESS,
JxlDecoderSetParallelRunner(dec, nullptr, nullptr));
JxlDecoderDestroy(dec);
}
// Creates the header of a JPEG XL file with various custom parameters for // testing. // xsize, ysize: image dimensions to store in the SizeHeader, max 512. // bits_per_sample, orientation: a selection of header parameters to test with. // orientation: image orientation to set in the metadata // alpha_bits: if non-0, alpha extra channel bits to set in the metadata. Also // gives the alpha channel the name "alpha_test" // have_container: add box container format around the codestream. // metadata_default: if true, ImageMetadata is set to default and // bits_per_sample, orientation and alpha_bits are ignored. // insert_box: insert an extra box before the codestream box, making the header // farther away from the front than is ideal. Only used if have_container.
std::vector<uint8_t> GetTestHeader(size_t xsize, size_t ysize,
size_t bits_per_sample, size_t orientation,
size_t alpha_bits, bool xyb_encoded, bool have_container, bool metadata_default, bool insert_extra_box, const jxl::IccBytes& icc_profile) {
JxlMemoryManager* memory_manager = jxl::test::MemoryManager();
jxl::BitWriter writer{memory_manager};
EXPECT_TRUE(writer.WithMaxBits(
65536, // Large enough
jxl::LayerType::Header, nullptr, [&] { if (have_container) { const std::vector<uint8_t> signature_box = {
0, 0, 0, 0xc, 'J', 'X', 'L', ' ', 0xd, 0xa, 0x87, 0xa}; const std::vector<uint8_t> filetype_box = {
0, 0, 0, 0x14, 'f', 't', 'y', 'p', 'j', 'x', 'l', ' ', 0, 0, 0, 0, 'j', 'x', 'l', ' '}; const std::vector<uint8_t> extra_box_header = {0, 0, 0, 0xff, 't', 'e', 's', 't'}; // Beginning of codestream box, with an arbitrary size certainly large // enough to contain the header const std::vector<uint8_t> codestream_box_header = {
0, 0, 0, 0xff, 'j', 'x', 'l', 'c'};
for (uint8_t c : signature_box) {
writer.Write(8, c);
} for (uint8_t c : filetype_box) {
writer.Write(8, c);
} if (insert_extra_box) { for (uint8_t c : extra_box_header) {
writer.Write(8, c);
} for (size_t i = 0; i < 255 - 8; i++) {
writer.Write(8, 0);
}
} for (uint8_t c : codestream_box_header) {
writer.Write(8, c);
}
}
std::vector<std::vector<uint8_t>> test_samples; // Test with direct codestream
test_samples.push_back(GetTestHeader(
xsize[0], ysize[0], bits_per_sample[0], orientation[0], alpha_bits[0],
xyb_encoded, have_container[0], /*metadata_default=*/false, /*insert_extra_box=*/false, {})); // Test with container and different parameters
test_samples.push_back(GetTestHeader(
xsize[1], ysize[1], bits_per_sample[1], orientation[1], alpha_bits[1],
xyb_encoded, have_container[1], /*metadata_default=*/false, /*insert_extra_box=*/false, {}));
for (size_t i = 0; i < test_samples.size(); ++i) { const std::vector<uint8_t>& data = test_samples[i]; // Test decoding too small header first, until we reach the final byte. for (size_t size = 0; size <= data.size(); ++size) { // Test with a new decoder for each tested byte size.
JxlDecoder* dec = JxlDecoderCreate(nullptr);
EXPECT_EQ(JXL_DEC_SUCCESS,
JxlDecoderSubscribeEvents(dec, JXL_DEC_BASIC_INFO)); const uint8_t* next_in = data.data();
size_t avail_in = size;
EXPECT_EQ(JXL_DEC_SUCCESS, JxlDecoderSetInput(dec, next_in, avail_in));
JxlDecoderStatus status = JxlDecoderProcessInput(dec);
if (size == data.size()) {
EXPECT_EQ(JXL_DEC_BASIC_INFO, status);
// All header bytes given so the decoder must have the basic info.
EXPECT_EQ(true, have_basic_info);
EXPECT_EQ(have_container[i], FROM_JXL_BOOL(info.have_container));
EXPECT_EQ(alpha_bits[i], info.alpha_bits); // Orientations 5..8 swap the dimensions if (orientation[i] >= 5) {
EXPECT_EQ(xsize[i], info.ysize);
EXPECT_EQ(ysize[i], info.xsize);
} else {
EXPECT_EQ(xsize[i], info.xsize);
EXPECT_EQ(ysize[i], info.ysize);
} // The API should set the orientation to identity by default since it // already applies the transformation internally by default.
EXPECT_EQ(1u, info.orientation);
EXPECT_EQ(3u, info.num_color_channels);
if (alpha_bits[i] != 0) { // Expect an extra channel
EXPECT_EQ(1u, info.num_extra_channels);
JxlExtraChannelInfo extra;
EXPECT_EQ(0, JxlDecoderGetExtraChannelInfo(dec, 0, &extra));
EXPECT_EQ(alpha_bits[i], extra.bits_per_sample);
EXPECT_EQ(JXL_CHANNEL_ALPHA, extra.type);
EXPECT_EQ(0, extra.alpha_premultiplied); // Verify the name "alpha_test" given to the alpha channel
EXPECT_EQ(10u, extra.name_length); char name[11];
EXPECT_EQ(0,
JxlDecoderGetExtraChannelName(dec, 0, name, sizeof(name)));
EXPECT_EQ(std::string("alpha_test"), std::string(name));
} else {
EXPECT_EQ(0u, info.num_extra_channels);
}
EXPECT_EQ(JXL_DEC_SUCCESS, JxlDecoderProcessInput(dec));
} else { // If we did not give the full header, the basic info should not be // available. Allow a few bytes of slack due to some bits for default // opsinmatrix/extension bits. if (size + 2 < data.size()) {
EXPECT_EQ(false, have_basic_info);
EXPECT_EQ(JXL_DEC_NEED_MORE_INPUT, status);
}
}
// Test that decoder doesn't allow setting a setting required at beginning // unless it's reset
EXPECT_EQ(JXL_DEC_ERROR,
JxlDecoderSubscribeEvents(dec, JXL_DEC_BASIC_INFO));
JxlDecoderReset(dec);
EXPECT_EQ(JXL_DEC_SUCCESS,
JxlDecoderSubscribeEvents(dec, JXL_DEC_BASIC_INFO));
TEST(DecodeTest, BasicInfoSizeHintTest) { // Test on a file where the size hint is too small initially due to inserting // a box before the codestream (something that is normally not recommended)
size_t xsize = 50;
size_t ysize = 50;
size_t bits_per_sample = 16;
size_t orientation = 1;
size_t alpha_bits = 0; bool xyb_encoded = false;
std::vector<uint8_t> data = GetTestHeader(
xsize, ysize, bits_per_sample, orientation, alpha_bits, xyb_encoded, /*have_container=*/true, /*metadata_default=*/false, /*insert_extra_box=*/true, {});
JxlDecoderStatus status;
JxlDecoder* dec = JxlDecoderCreate(nullptr);
EXPECT_EQ(JXL_DEC_SUCCESS,
JxlDecoderSubscribeEvents(dec, JXL_DEC_BASIC_INFO));
size_t hint0 = JxlDecoderSizeHintBasicInfo(dec); // Test that the test works as intended: we construct a file on purpose to // be larger than the first hint by having that extra box.
EXPECT_LT(hint0, data.size()); const uint8_t* next_in = data.data(); // Do as if we have only as many bytes as indicated by the hint available
size_t avail_in = std::min(hint0, data.size());
EXPECT_EQ(JXL_DEC_SUCCESS, JxlDecoderSetInput(dec, next_in, avail_in));
status = JxlDecoderProcessInput(dec);
EXPECT_EQ(JXL_DEC_NEED_MORE_INPUT, status); // Basic info cannot be available yet due to the extra inserted box.
EXPECT_EQ(false, !JxlDecoderGetBasicInfo(dec, nullptr));
size_t hint1 = JxlDecoderSizeHintBasicInfo(dec); // The hint must be larger than the previous hint (taking already processed // bytes into account, the hint is a hint for the next avail_in) since the // decoder now knows there is a box in between.
EXPECT_GT(hint1 + num_read, hint0);
avail_in = std::min<size_t>(hint1, data.size() - num_read);
next_in += num_read;
EXPECT_EQ(JXL_DEC_SUCCESS, JxlDecoderSetInput(dec, next_in, avail_in));
status = JxlDecoderProcessInput(dec);
EXPECT_EQ(JXL_DEC_BASIC_INFO, status);
JxlBasicInfo info; // We should have the basic info now, since we only added one box in-between, // and the decoder should have known its size, its implementation can return // a correct hint.
EXPECT_EQ(true, !JxlDecoderGetBasicInfo(dec, &info));
// Also test if the basic info is correct.
EXPECT_EQ(1, info.have_container);
EXPECT_EQ(xsize, info.xsize);
EXPECT_EQ(ysize, info.ysize);
EXPECT_EQ(orientation, info.orientation);
EXPECT_EQ(bits_per_sample, info.bits_per_sample);
// Tests the case where pixels and metadata ICC profile are the same
TEST(DecodeTest, IccProfileTestOriginal) {
jxl::IccBytes icc_profile = GetIccTestProfile(); bool xyb_encoded = false;
std::vector<uint8_t> data = GetIccTestHeader(icc_profile, xyb_encoded);
// Expect the opposite of xyb_encoded for uses_original_profile
JxlBasicInfo info;
EXPECT_EQ(JXL_DEC_SUCCESS, JxlDecoderGetBasicInfo(dec, &info));
EXPECT_EQ(JXL_TRUE, info.uses_original_profile);
// the encoded color profile expected to be not available, since the image // has an ICC profile instead
EXPECT_EQ(JXL_DEC_ERROR,
JxlDecoderGetColorAsEncodedProfile(
dec, JXL_COLOR_PROFILE_TARGET_ORIGINAL, nullptr));
// Check that can get return status with NULL size
EXPECT_EQ(JXL_DEC_SUCCESS,
JxlDecoderGetICCProfileSize(dec, JXL_COLOR_PROFILE_TARGET_ORIGINAL,
nullptr));
// The profiles must be equal. This requires they have equal size, and if // they do, we can get the profile and compare the contents.
EXPECT_EQ(icc_profile.size(), dec_profile_size); if (icc_profile.size() == dec_profile_size) {
jxl::IccBytes icc_profile2(icc_profile.size());
EXPECT_EQ(JXL_DEC_SUCCESS, JxlDecoderGetColorAsICCProfile(
dec, JXL_COLOR_PROFILE_TARGET_ORIGINAL,
icc_profile2.data(), icc_profile2.size()));
EXPECT_EQ(icc_profile, icc_profile2);
}
// the data is not xyb_encoded, so same result expected for the pixel data // color profile
EXPECT_EQ(JXL_DEC_ERROR, JxlDecoderGetColorAsEncodedProfile(
dec, JXL_COLOR_PROFILE_TARGET_DATA, nullptr));
// Tests the case where pixels and metadata ICC profile are different
TEST(DecodeTest, IccProfileTestXybEncoded) {
jxl::IccBytes icc_profile = GetIccTestProfile(); bool xyb_encoded = true;
std::vector<uint8_t> data = GetIccTestHeader(icc_profile, xyb_encoded);
JxlDecoder* dec = JxlDecoderCreate(nullptr);
EXPECT_EQ(JXL_DEC_SUCCESS,
JxlDecoderSubscribeEvents(
dec, JXL_DEC_BASIC_INFO | JXL_DEC_COLOR_ENCODING));
// Expect the opposite of xyb_encoded for uses_original_profile
JxlBasicInfo info;
EXPECT_EQ(JXL_DEC_SUCCESS, JxlDecoderGetBasicInfo(dec, &info));
EXPECT_EQ(JXL_FALSE, info.uses_original_profile);
// the encoded color profile expected to be not available, since the image // has an ICC profile instead
EXPECT_EQ(JXL_DEC_ERROR,
JxlDecoderGetColorAsEncodedProfile(
dec, JXL_COLOR_PROFILE_TARGET_ORIGINAL, nullptr));
// Check that can get return status with NULL size
EXPECT_EQ(JXL_DEC_SUCCESS,
JxlDecoderGetICCProfileSize(dec, JXL_COLOR_PROFILE_TARGET_ORIGINAL,
nullptr));
// The profiles must be equal. This requires they have equal size, and if // they do, we can get the profile and compare the contents.
EXPECT_EQ(icc_profile.size(), dec_profile_size); if (icc_profile.size() == dec_profile_size) {
jxl::IccBytes icc_profile2(icc_profile.size());
EXPECT_EQ(JXL_DEC_SUCCESS, JxlDecoderGetColorAsICCProfile(
dec, JXL_COLOR_PROFILE_TARGET_ORIGINAL,
icc_profile2.data(), icc_profile2.size()));
EXPECT_EQ(icc_profile, icc_profile2);
}
// Data is xyb_encoded, so the data profile is a different profile, encoded // as structured profile.
EXPECT_EQ(JXL_DEC_SUCCESS, JxlDecoderGetColorAsEncodedProfile(
dec, JXL_COLOR_PROFILE_TARGET_DATA, nullptr));
JxlColorEncoding pixel_encoding;
EXPECT_EQ(JXL_DEC_SUCCESS,
JxlDecoderGetColorAsEncodedProfile(
dec, JXL_COLOR_PROFILE_TARGET_DATA, &pixel_encoding));
EXPECT_EQ(JXL_PRIMARIES_SRGB, pixel_encoding.primaries); // The API returns LINEAR by default when the colorspace cannot be represented // by enum values.
EXPECT_EQ(JXL_TRANSFER_FUNCTION_LINEAR, pixel_encoding.transfer_function);
// Test the same but with integer format.
EXPECT_EQ(JXL_DEC_SUCCESS,
JxlDecoderGetColorAsEncodedProfile(
dec, JXL_COLOR_PROFILE_TARGET_DATA, &pixel_encoding));
EXPECT_EQ(JXL_PRIMARIES_SRGB, pixel_encoding.primaries);
EXPECT_EQ(JXL_TRANSFER_FUNCTION_LINEAR, pixel_encoding.transfer_function);
// Test after setting the preferred color profile to non-linear sRGB: // for XYB images with ICC profile, this setting is expected to take effect.
jxl::ColorEncoding temp_jxl_srgb = jxl::ColorEncoding::SRGB(false);
JxlColorEncoding pixel_encoding_srgb = temp_jxl_srgb.ToExternal();
EXPECT_EQ(JXL_DEC_SUCCESS,
JxlDecoderSetPreferredColorProfile(dec, &pixel_encoding_srgb));
EXPECT_EQ(JXL_DEC_SUCCESS,
JxlDecoderGetColorAsEncodedProfile(
dec, JXL_COLOR_PROFILE_TARGET_DATA, &pixel_encoding));
EXPECT_EQ(JXL_TRANSFER_FUNCTION_SRGB, pixel_encoding.transfer_function);
// The decoder can also output this as a generated ICC profile anyway, and // we're certain that it will differ from the above defined profile since // the sRGB data should not have swapped R/G/B primaries.
EXPECT_EQ(JXL_DEC_SUCCESS,
JxlDecoderGetICCProfileSize(dec, JXL_COLOR_PROFILE_TARGET_DATA,
&dec_profile_size)); // We don't need to dictate exactly what size the generated ICC profile // must be (since there are many ways to represent the same color space), // but it should not be zero.
EXPECT_NE(0u, dec_profile_size);
jxl::IccBytes icc_profile2(dec_profile_size); if (0 != dec_profile_size) {
EXPECT_EQ(JXL_DEC_SUCCESS, JxlDecoderGetColorAsICCProfile(
dec, JXL_COLOR_PROFILE_TARGET_DATA,
icc_profile2.data(), icc_profile2.size())); // expected not equal
EXPECT_NE(icc_profile, icc_profile2);
}
// Test setting another different preferred profile, to verify that the // returned JXL_COLOR_PROFILE_TARGET_DATA ICC profile is correctly // updated.
EXPECT_EQ(JXL_DEC_SUCCESS,
JxlDecoderSetPreferredColorProfile(dec, &pixel_encoding_linear));
EXPECT_EQ(JXL_DEC_SUCCESS,
JxlDecoderGetColorAsEncodedProfile(
dec, JXL_COLOR_PROFILE_TARGET_DATA, &pixel_encoding));
EXPECT_EQ(JXL_TRANSFER_FUNCTION_LINEAR, pixel_encoding.transfer_function);
EXPECT_EQ(JXL_DEC_SUCCESS,
JxlDecoderGetICCProfileSize(dec, JXL_COLOR_PROFILE_TARGET_DATA,
&dec_profile_size));
EXPECT_NE(0u, dec_profile_size);
jxl::IccBytes icc_profile3(dec_profile_size); if (0 != dec_profile_size) {
EXPECT_EQ(JXL_DEC_SUCCESS, JxlDecoderGetColorAsICCProfile(
dec, JXL_COLOR_PROFILE_TARGET_DATA,
icc_profile3.data(), icc_profile3.size())); // expected not equal to the previously set preferred profile.
EXPECT_NE(icc_profile2, icc_profile3);
}
JxlDecoderDestroy(dec);
}
// Test decoding ICC from partial files byte for byte. // This test must pass also if JXL_CRASH_ON_ERROR is enabled, that is, the // decoding of the ANS histogram and stream of the encoded ICC profile must also // handle the case of not enough input bytes with StatusCode::kNotEnoughBytes // rather than fatal error status codes.
TEST(DecodeTest, ICCPartialTest) {
jxl::IccBytes icc_profile = GetIccTestProfile();
std::vector<uint8_t> data = GetIccTestHeader(icc_profile, false);
for (;;) {
EXPECT_EQ(JXL_DEC_SUCCESS, JxlDecoderSetInput(dec, next_in, avail_in));
JxlDecoderStatus status = JxlDecoderProcessInput(dec);
size_t remaining = JxlDecoderReleaseInput(dec);
EXPECT_LE(remaining, avail_in);
next_in += avail_in - remaining;
avail_in = remaining; if (status == JXL_DEC_NEED_MORE_INPUT) { if (total_size >= data.size()) { // End of partial codestream with codestrema headers and ICC profile // reached, it should not require more input since full image is not // requested
FAIL(); break;
}
size_t increment = 1; if (total_size + increment > data.size()) {
increment = data.size() - total_size;
}
total_size += increment;
avail_in += increment;
} elseif (status == JXL_DEC_BASIC_INFO) {
EXPECT_FALSE(seen_basic_info);
seen_basic_info = true;
} elseif (status == JXL_DEC_COLOR_ENCODING) {
EXPECT_TRUE(seen_basic_info);
EXPECT_FALSE(seen_color_encoding);
seen_color_encoding = true;
// Sanity check that the ICC profile was decoded correctly
size_t dec_profile_size;
EXPECT_EQ(JXL_DEC_SUCCESS,
JxlDecoderGetICCProfileSize(
dec, JXL_COLOR_PROFILE_TARGET_ORIGINAL, &dec_profile_size));
EXPECT_EQ(icc_profile.size(), dec_profile_size);
} elseif (status == JXL_DEC_SUCCESS) {
EXPECT_TRUE(seen_color_encoding); break;
} else { // We do not expect any other events or errors
FAIL(); break;
}
}
// If an orientation transformation is expected, to compare the pixels, also // apply this transformation to the original pixels. ConvertToExternal is // used to achieve this, with a temporary conversion to CodecInOut and back. if (config.orientation > 1 && !config.keep_orientation) {
jxl::Span<const uint8_t> bytes(pixels.data(), pixels.size());
jxl::ColorEncoding color_encoding =
jxl::ColorEncoding::SRGB(config.grayscale);
jxl::CodecInOut io{jxl::test::MemoryManager()}; if (config.include_alpha) io.metadata.m.SetAlphaBits(16);
io.metadata.m.color_encoding = color_encoding;
ASSERT_TRUE(io.SetSize(config.xsize, config.ysize));
for (uint8_t& pixel : pixels) pixel = 0;
EXPECT_TRUE(ConvertToExternal(
io.Main(), 16, /*float_out=*/false, orig_channels, JXL_BIG_ENDIAN,
xsize * 2 * orig_channels, nullptr, pixels.data(), pixels.size(), /*out_callback=*/{}, static_cast<jxl::Orientation>(config.orientation)));
} if (config.upsampling == 1) {
EXPECT_EQ(0u, jxl::test::ComparePixels(pixels.data(), pixels2.data(), xsize,
ysize, format_orig, format));
} else { // resampling is of course not lossless, so as a rough check: // count pixels that are more than off-by-25 in the 8-bit value of one of // the channels
EXPECT_LE(
jxl::test::ComparePixels(
pixels.data(), pixels2.data(), xsize, ysize, format_orig, format,
50.0 * (config.data_type == JXL_TYPE_UINT8 ? 1.0 : 256.0)),
300u);
}
// Test using the resizable runner for (size_t i = 0; i < 4; i++) {
make_test(ch_info[0], 300 << i, 33 << i, jxl::kNoPreview, /*add_intrinsic_size=*/false, CodeStreamBoxFormat::kCSBF_None,
JXL_ORIENT_IDENTITY, /*keep_orientation=*/false, out_formats[0], /*use_callback=*/false, /*set_buffer_early=*/false, /*resizable_runner=*/true, 1);
}
// Test orientations. for (int orientation = 2; orientation <= 8; ++orientation) { for (bool keep_orientation : {false, true}) { for (bool use_callback : {false, true}) { for (ChannelInfo ch : ch_info) { for (OutputFormat fmt : out_formats) {
make_test(ch, 280, 12, jxl::kNoPreview, /*add_intrinsic_size=*/false,
CodeStreamBoxFormat::kCSBF_None, static_cast<JxlOrientation>(orientation), /*keep_orientation=*/keep_orientation, fmt, /*use_callback=*/use_callback, /*set_buffer_early=*/true, /*resizable_runner=*/false, 1);
}
}
}
}
}
return all_tests;
}
std::ostream& operator<<(std::ostream& os, const PixelTestConfig& c) {
os << c.xsize << "x" << c.ysize; constchar* colors[] = {"", "G", "GA", "RGB", "RGBA"};
os << colors[(c.grayscale ? 1 : 3) + (c.include_alpha ? 1 : 0)];
os << "to";
os << colors[c.output_channels]; switch (c.data_type) { case JXL_TYPE_UINT8:
os << "u8"; break; case JXL_TYPE_UINT16:
os << "u16"; break; case JXL_TYPE_FLOAT:
os << "f32"; break; case JXL_TYPE_FLOAT16:
os << "f16"; break; default:
ADD_FAILURE();
}; if (jxl::test::GetDataBits(c.data_type) > jxl::kBitsPerByte) { if (c.endianness == JXL_NATIVE_ENDIAN) { // add nothing
} elseif (c.endianness == JXL_BIG_ENDIAN) {
os << "BE";
} elseif (c.endianness == JXL_LITTLE_ENDIAN) {
os << "LE";
}
} if (c.add_container != CodeStreamBoxFormat::kCSBF_None) {
os << "Box";
os << static_cast<size_t>(c.add_container);
} if (c.preview_mode == jxl::kSmallPreview) os << "Preview"; if (c.preview_mode == jxl::kBigPreview) os << "BigPreview"; if (c.add_intrinsic_size) os << "IntrinicSize"; if (c.use_callback) os << "Callback"; if (c.set_buffer_early) os << "EarlyBuffer"; if (c.use_resizable_runner) os << "ResizableRunner"; if (c.orientation != 1) os << "O" << c.orientation; if (c.keep_orientation) os << "Keep"; if (c.upsampling > 1) os << "x" << c.upsampling; return os;
}
// Test with the container for one of the pixel formats.
std::vector<uint8_t> pixels2 = jxl::DecodeWithAPI(
dec, jxl::Bytes(compressed.data(), compressed.size()), format, /*use_callback=*/true, /*set_buffer_early=*/true, /*use_resizable_runner=*/false, /*require_boxes=*/false, /*expect_success=*/true);
JxlDecoderReset(dec);
EXPECT_EQ(num_pixels * channels * 2, pixels2.size());
EXPECT_EQ(0u,
jxl::test::ComparePixels(pixels.data(), pixels2.data(), xsize,
ysize, format_orig, format));
}
{
JxlPixelFormat format = {channels, JXL_TYPE_FLOAT, JXL_LITTLE_ENDIAN, 0};
// The input pixels use the profile matching GetIccTestProfile, since we set // add_icc_profile for CreateTestJXLCodestream to true.
jxl::ColorEncoding color_encoding0;
EXPECT_TRUE(color_encoding0.SetICC(GetIccTestProfile(), JxlGetDefaultCms()));
jxl::Span<const uint8_t> span0(pixels.data(), pixels.size());
jxl::CodecInOut io0{memory_manager};
ASSERT_TRUE(io0.SetSize(xsize, ysize));
EXPECT_TRUE(ConvertFromExternal(span0, xsize, ysize, color_encoding0, /*bits_per_sample=*/16, format_orig, /*pool=*/nullptr, &io0.Main()));
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.