mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
Bug 1845026 - Update libjxl to 69d06e17771830beae7fb62b76de5978b52546fc r=saschanaz
Differential Revision: https://phabricator.services.mozilla.com/D184331
This commit is contained in:
parent
67fc396208
commit
8340c57e0c
@ -43,6 +43,7 @@ SOURCES += [
|
||||
"/third_party/jpeg-xl/lib/jxl/dec_patch_dictionary.cc",
|
||||
"/third_party/jpeg-xl/lib/jxl/dec_xyb.cc",
|
||||
"/third_party/jpeg-xl/lib/jxl/decode.cc",
|
||||
"/third_party/jpeg-xl/lib/jxl/enc_debug_image.cc",
|
||||
"/third_party/jpeg-xl/lib/jxl/entropy_coder.cc",
|
||||
"/third_party/jpeg-xl/lib/jxl/epf.cc",
|
||||
"/third_party/jpeg-xl/lib/jxl/fast_dct.cc",
|
||||
|
@ -10,9 +10,9 @@ origin:
|
||||
|
||||
url: https://github.com/libjxl/libjxl
|
||||
|
||||
release: 190d44fbe463c5c3081081c80633639f69478d97 (2023-06-30T21:25:24Z).
|
||||
release: 69d06e17771830beae7fb62b76de5978b52546fc (2023-07-21T14:55:24Z).
|
||||
|
||||
revision: 190d44fbe463c5c3081081c80633639f69478d97
|
||||
revision: 69d06e17771830beae7fb62b76de5978b52546fc
|
||||
|
||||
license: Apache-2.0
|
||||
|
||||
|
8
third_party/jpeg-xl/CHANGELOG.md
vendored
8
third_party/jpeg-xl/CHANGELOG.md
vendored
@ -10,7 +10,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Added
|
||||
- encoder API: add `JxlEncoderSetExtraChannelDistance` to adjust the quality
|
||||
of extra channels (like alpha) separately.
|
||||
|
||||
- encoder API: new api functions for streaming encoding:
|
||||
- `JxlEncoderSetOutputCallback`,
|
||||
- `JxlEncoderChunkedImageFrameStart`,
|
||||
- `JxlEncoderChunkedImageFrameAddPart` and new
|
||||
- `JXL_ENC_FRAME_SETTING_BUFFERING` enum value.
|
||||
### Removed
|
||||
- API: the Butteraugli API (`jxl/butteraugli.h`) was removed.
|
||||
- encoder and decoder API: all deprecated functions were removed:
|
||||
@ -23,7 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
`JxlDecoderGetICCProfileSize`, and `JxlDecoderGetColorAsICCProfile`
|
||||
changed: a deprecated unused argument was removed.
|
||||
|
||||
### Changed
|
||||
### Changed
|
||||
- changed the name of the cjxl flag `photon_noise` to `photon_noise_iso`
|
||||
|
||||
## [0.8.0] - 2023-01-18
|
||||
|
26
third_party/jpeg-xl/CMakeLists.txt
vendored
26
third_party/jpeg-xl/CMakeLists.txt
vendored
@ -171,6 +171,10 @@ set(JPEGXL_FORCE_NEON false CACHE BOOL
|
||||
"Set flags to enable NEON in arm if not enabled by your toolchain.")
|
||||
set(JPEGXL_TEST_TOOLS false CACHE BOOL
|
||||
"Run scripts that test the encoding / decoding tools.")
|
||||
set(JPEGXL_ENABLE_AVX512 false CACHE BOOL
|
||||
"Build with AVX512 support (faster on CPUs that support it, but larger binary size).")
|
||||
set(JPEGXL_ENABLE_AVX512_ZEN4 false CACHE BOOL
|
||||
"Build with Zen4-optimized AVX512 support (faster on CPUs that support it, but larger binary size).")
|
||||
|
||||
# Force system dependencies.
|
||||
set(JPEGXL_FORCE_SYSTEM_BROTLI false CACHE BOOL
|
||||
@ -206,6 +210,20 @@ endif()
|
||||
message(STATUS
|
||||
"Compiled IDs C:${CMAKE_C_COMPILER_ID}, C++:${CMAKE_CXX_COMPILER_ID}")
|
||||
|
||||
# Always disable SSSE3 since it is rare to have SSSE3 but not SSE4
|
||||
set(HWY_DISABLED_TARGETS "HWY_SSSE3")
|
||||
if (NOT JPEGXL_ENABLE_AVX512)
|
||||
message(STATUS "Disabled AVX512 (set JPEGXL_ENABLE_AVX512 to enable it)")
|
||||
set(HWY_DISABLED_TARGETS "${HWY_DISABLED_TARGETS}|HWY_AVX3")
|
||||
add_definitions(-DFJXL_ENABLE_AVX512=0)
|
||||
endif()
|
||||
if (NOT JPEGXL_ENABLE_AVX512_ZEN4)
|
||||
message(STATUS "Disabled AVX512_ZEN4 (set JPEGXL_ENABLE_AVX512_ZEN4 to enable it)")
|
||||
set(HWY_DISABLED_TARGETS "${HWY_DISABLED_TARGETS}|HWY_AVX3_ZEN4")
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
# CMAKE_EXPORT_COMPILE_COMMANDS is used to generate the compilation database
|
||||
# used by clang-tidy.
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
@ -300,9 +318,11 @@ else ()
|
||||
)
|
||||
|
||||
# TODO(eustas): JXL currently compiles, but does not pass tests...
|
||||
if (NOT JXL_HWY_DISABLED_TARGETS_FORCED AND NOT JPEGXL_ENABLE_SIZELESS_VECTORS)
|
||||
add_definitions(-DHWY_DISABLED_TARGETS=\(HWY_SVE|HWY_SVE2|HWY_SVE_256|HWY_SVE2_128|HWY_RVV\))
|
||||
message("Warning: HWY_SVE, HWY_SVE2, HWY_SVE_256, HWY_SVE2_128 and HWY_RVV CPU targets are disabled")
|
||||
if (NOT JXL_HWY_DISABLED_TARGETS_FORCED)
|
||||
if (NOT JPEGXL_ENABLE_SIZELESS_VECTORS)
|
||||
set(HWY_DISABLED_TARGETS "${HWY_DISABLED_TARGETS}|HWY_SVE|HWY_SVE2|HWY_SVE_256|HWY_SVE2_128|HWY_RVV")
|
||||
endif()
|
||||
add_definitions(-DHWY_DISABLED_TARGETS=\(${HWY_DISABLED_TARGETS}\))
|
||||
endif()
|
||||
|
||||
# In CMake before 3.12 it is problematic to pass repeated flags like -Xclang.
|
||||
|
7
third_party/jpeg-xl/WORKSPACE
vendored
7
third_party/jpeg-xl/WORKSPACE
vendored
@ -150,7 +150,7 @@ SUBSTITUTIONS = {
|
||||
}
|
||||
YES_DEFINES = [
|
||||
"C_ARITH_CODING_SUPPORTED", "D_ARITH_CODING_SUPPORTED",
|
||||
"HAVE_BUILTIN_CTZL"
|
||||
"HAVE_BUILTIN_CTZL", "MEM_SRCDST_SUPPORTED"
|
||||
]
|
||||
NO_DEFINES = [
|
||||
"WITH_SIMD", "RIGHT_SHIFT_IS_UNSIGNED", "HAVE_INTRIN_H"
|
||||
@ -167,6 +167,7 @@ SUBSTITUTIONS.update({
|
||||
template = src + ".in",
|
||||
out = src,
|
||||
substitutions = SUBSTITUTIONS,
|
||||
visibility = ["//visibility:public"],
|
||||
) for src in ["jconfig.h", "jconfigint.h", "jversion.h"]
|
||||
]
|
||||
JPEG16_SOURCES = [
|
||||
@ -285,6 +286,10 @@ cc_library(
|
||||
includes = ["."],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
exports_files([
|
||||
"jmorecfg.h",
|
||||
"jpeglib.h",
|
||||
])
|
||||
""",
|
||||
remote = "https://github.com/libjpeg-turbo/libjpeg-turbo.git",
|
||||
tag = "2.1.91",
|
||||
|
13
third_party/jpeg-xl/bash_test.sh
vendored
13
third_party/jpeg-xl/bash_test.sh
vendored
@ -18,14 +18,11 @@ test_includes() {
|
||||
if [ ! -e "$f" ]; then
|
||||
continue
|
||||
fi
|
||||
# Check that the public files (in lib/include/ directory) don't use the full
|
||||
# path to the public header since users of the library will include the
|
||||
# library as: #include "jxl/foobar.h".
|
||||
if [[ "${f#lib/include/}" != "${f}" ]]; then
|
||||
if grep -i -H -n -E '#include\s*[<"]lib/include/jxl' "$f" >&2; then
|
||||
echo "Don't add \"include/\" to the include path of public headers." >&2
|
||||
ret=1
|
||||
fi
|
||||
# Check that the full paths to the public headers are not used, since users
|
||||
# of the library will include the library as: #include "jxl/foobar.h".
|
||||
if grep -i -H -n -E '#include\s*[<"]lib/include/jxl' "$f" >&2; then
|
||||
echo "Don't add \"include/\" to the include path of public headers." >&2
|
||||
ret=1
|
||||
fi
|
||||
|
||||
if [[ "${f#third_party/}" == "$f" ]]; then
|
||||
|
5
third_party/jpeg-xl/debian/copyright
vendored
5
third_party/jpeg-xl/debian/copyright
vendored
@ -5,6 +5,11 @@ Files: *
|
||||
Copyright: 2020 the JPEG XL Project
|
||||
License: BSD-3-clause
|
||||
|
||||
Files: third_party/libjpeg-turbo/*
|
||||
Copyright (C)2009-2023 D. R. Commander. All Rights Reserved.
|
||||
Copyright (C)2015 Viktor Szathmáry. All Rights Reserved.
|
||||
License: BSD-3-clause
|
||||
|
||||
Files: third_party/sjpeg/*
|
||||
Copyright: 2017 Google, Inc
|
||||
License: Apache-2.0
|
||||
|
4
third_party/jpeg-xl/deps.sh
vendored
4
third_party/jpeg-xl/deps.sh
vendored
@ -19,6 +19,7 @@ THIRD_PARTY_SKCMS="b25b07b4b07990811de121c0356155b2ba0f4318"
|
||||
THIRD_PARTY_SJPEG="e5ab13008bb214deb66d5f3e17ca2f8dbff150bf"
|
||||
THIRD_PARTY_ZLIB="cacf7f1d4e3d44d871b605da3b647f07d718623f"
|
||||
THIRD_PARTY_LIBPNG="a40189cf881e9f0db80511c382292a5604c3c3d1"
|
||||
THIRD_PARTY_LIBJPEG_TURBO="8ecba3647edb6dd940463fedf38ca33a8e2a73d1" # 2.1.5.1
|
||||
|
||||
# Download the target revision from GitHub.
|
||||
download_github() {
|
||||
@ -26,7 +27,7 @@ download_github() {
|
||||
local project="$2"
|
||||
|
||||
local varname=`echo "$path" | tr '[:lower:]' '[:upper:]'`
|
||||
varname="${varname/\//_}"
|
||||
varname="${varname/[\/-]/_}"
|
||||
local sha
|
||||
eval "sha=\${${varname}}"
|
||||
|
||||
@ -85,6 +86,7 @@ EOF
|
||||
"https://skia.googlesource.com/skcms/+archive/"
|
||||
download_github third_party/zlib madler/zlib
|
||||
download_github third_party/libpng glennrp/libpng
|
||||
download_github third_party/libjpeg-turbo libjpeg-turbo/libjpeg-turbo
|
||||
echo "Done."
|
||||
}
|
||||
|
||||
|
@ -154,11 +154,9 @@ bool DecodeJpegXlProgressive(const uint8_t* jxl, size_t size,
|
||||
return false;
|
||||
}
|
||||
pixels.resize(xsize * ysize * 4);
|
||||
void* pixels_buffer = (void*)pixels.data();
|
||||
size_t pixels_buffer_size = pixels.size() * sizeof(float);
|
||||
if (JXL_DEC_SUCCESS != JxlDecoderSetImageOutBuffer(dec.get(), &format,
|
||||
pixels_buffer,
|
||||
pixels_buffer_size)) {
|
||||
pixels.data(),
|
||||
pixels.size())) {
|
||||
fprintf(stderr, "JxlDecoderSetImageOutBuffer failed\n");
|
||||
return false;
|
||||
}
|
||||
|
46
third_party/jpeg-xl/lib/BUILD
vendored
46
third_party/jpeg-xl/lib/BUILD
vendored
@ -23,6 +23,8 @@ load(
|
||||
"libjxl_extras_for_tools_sources",
|
||||
"libjxl_extras_sources",
|
||||
#'libjxl_gbench_sources',
|
||||
"libjxl_jpegli_lib_version",
|
||||
"libjxl_jpegli_libjpeg_helper_files",
|
||||
"libjxl_jpegli_sources",
|
||||
"libjxl_jpegli_testlib_files",
|
||||
"libjxl_jpegli_tests",
|
||||
@ -55,6 +57,7 @@ load(
|
||||
"libjxl_test_timeouts",
|
||||
)
|
||||
load("@bazel_skylib//rules:expand_template.bzl", "expand_template")
|
||||
load("@bazel_skylib//rules:copy_file.bzl", "copy_file")
|
||||
|
||||
DEFAULT_VISIBILITY = ["//:__subpackages__"]
|
||||
|
||||
@ -123,6 +126,33 @@ cc_library(
|
||||
strip_include_prefix = INCLUDES_DIR,
|
||||
)
|
||||
|
||||
JPEGLI_JCONFIG_H = INCLUDES_DIR + "/jpegli/jconfig.h"
|
||||
|
||||
JPEGLI_JMORECFG_H = INCLUDES_DIR + "/jpegli/jmorecfg.h"
|
||||
|
||||
JPEGLI_JPEGLIB_H = INCLUDES_DIR + "/jpegli/jpeglib.h"
|
||||
|
||||
copy_file(
|
||||
name = "expand_jconfig",
|
||||
src = "@libjpeg_turbo//:jconfig.h",
|
||||
out = JPEGLI_JCONFIG_H,
|
||||
compatible_with = DEFAULT_COMPATIBILITY,
|
||||
)
|
||||
|
||||
copy_file(
|
||||
name = "copy_jmorecfg",
|
||||
src = "@libjpeg_turbo//:jmorecfg.h",
|
||||
out = JPEGLI_JMORECFG_H,
|
||||
compatible_with = DEFAULT_COMPATIBILITY,
|
||||
)
|
||||
|
||||
copy_file(
|
||||
name = "copy_jpeglib",
|
||||
src = "@libjpeg_turbo//:jpeglib.h",
|
||||
out = JPEGLI_JPEGLIB_H,
|
||||
compatible_with = DEFAULT_COMPATIBILITY,
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "includes",
|
||||
hdrs = libjxl_public_headers + [JXL_EXPORT_H],
|
||||
@ -131,6 +161,17 @@ cc_library(
|
||||
deps = [":jxl_version"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "libjpeg_includes",
|
||||
hdrs = [
|
||||
JPEGLI_JCONFIG_H,
|
||||
JPEGLI_JMORECFG_H,
|
||||
JPEGLI_JPEGLIB_H,
|
||||
],
|
||||
compatible_with = DEFAULT_COMPATIBILITY,
|
||||
strip_include_prefix = INCLUDES_DIR + "/jpegli",
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "base",
|
||||
srcs = [path for path in libjxl_base_sources if path.endswith(".cc")],
|
||||
@ -190,7 +231,8 @@ cc_library(
|
||||
compatible_with = DEFAULT_COMPATIBILITY,
|
||||
deps = [
|
||||
":jpegxl_private",
|
||||
] + libjxl_deps_hwy + libjxl_deps_jpeg,
|
||||
":libjpeg_includes",
|
||||
] + libjxl_deps_hwy,
|
||||
)
|
||||
|
||||
# TODO(eustas): build codecs separately?
|
||||
@ -214,7 +256,7 @@ cc_library(
|
||||
] + libjxl_deps_exr + libjxl_deps_gif + libjxl_deps_jpeg + libjxl_deps_png,
|
||||
)
|
||||
|
||||
TESTLIB_FILES = libjxl_testlib_files + libjxl_jpegli_testlib_files
|
||||
TESTLIB_FILES = libjxl_testlib_files + libjxl_jpegli_testlib_files + libjxl_jpegli_libjpeg_helper_files
|
||||
|
||||
cc_library(
|
||||
name = "test_utils",
|
||||
|
3
third_party/jpeg-xl/lib/CMakeLists.txt
vendored
3
third_party/jpeg-xl/lib/CMakeLists.txt
vendored
@ -141,8 +141,7 @@ if(JPEGXL_ENABLE_TOOLS)
|
||||
include(jxl_extras.cmake)
|
||||
endif()
|
||||
include(jxl_threads.cmake)
|
||||
find_package(JPEG)
|
||||
if (JPEG_FOUND AND JPEGXL_ENABLE_JPEGLI)
|
||||
if (JPEGXL_ENABLE_JPEGLI)
|
||||
include(jpegli.cmake)
|
||||
endif()
|
||||
|
||||
|
54
third_party/jpeg-xl/lib/extras/codec.cc
vendored
54
third_party/jpeg-xl/lib/extras/codec.cc
vendored
@ -8,24 +8,16 @@
|
||||
#include <jxl/decode.h>
|
||||
#include <jxl/types.h>
|
||||
|
||||
#include "lib/extras/packed_image.h"
|
||||
#include "lib/jxl/base/padded_bytes.h"
|
||||
#include "lib/jxl/base/status.h"
|
||||
|
||||
#if JPEGXL_ENABLE_APNG
|
||||
#include "lib/extras/enc/apng.h"
|
||||
#endif
|
||||
#if JPEGXL_ENABLE_JPEG
|
||||
#include "lib/extras/enc/jpg.h"
|
||||
#endif
|
||||
#if JPEGXL_ENABLE_EXR
|
||||
#include "lib/extras/enc/exr.h"
|
||||
#endif
|
||||
|
||||
#include "lib/extras/dec/decode.h"
|
||||
#include "lib/extras/enc/apng.h"
|
||||
#include "lib/extras/enc/exr.h"
|
||||
#include "lib/extras/enc/jpg.h"
|
||||
#include "lib/extras/enc/pgx.h"
|
||||
#include "lib/extras/enc/pnm.h"
|
||||
#include "lib/extras/packed_image.h"
|
||||
#include "lib/extras/packed_image_convert.h"
|
||||
#include "lib/jxl/base/padded_bytes.h"
|
||||
#include "lib/jxl/base/status.h"
|
||||
#include "lib/jxl/image_bundle.h"
|
||||
|
||||
namespace jxl {
|
||||
@ -68,22 +60,22 @@ Status Encode(const CodecInOut& io, const extras::Codec codec,
|
||||
std::ostringstream os;
|
||||
switch (codec) {
|
||||
case extras::Codec::kPNG:
|
||||
#if JPEGXL_ENABLE_APNG
|
||||
encoder = extras::GetAPNGEncoder();
|
||||
break;
|
||||
#else
|
||||
return JXL_FAILURE("JPEG XL was built without (A)PNG support");
|
||||
#endif
|
||||
if (encoder) {
|
||||
break;
|
||||
} else {
|
||||
return JXL_FAILURE("JPEG XL was built without (A)PNG support");
|
||||
}
|
||||
case extras::Codec::kJPG:
|
||||
#if JPEGXL_ENABLE_JPEG
|
||||
format.data_type = JXL_TYPE_UINT8;
|
||||
encoder = extras::GetJPEGEncoder();
|
||||
os << io.jpeg_quality;
|
||||
encoder->SetOption("q", os.str());
|
||||
break;
|
||||
#else
|
||||
return JXL_FAILURE("JPEG XL was built without JPEG support");
|
||||
#endif
|
||||
if (encoder) {
|
||||
os << io.jpeg_quality;
|
||||
encoder->SetOption("q", os.str());
|
||||
break;
|
||||
} else {
|
||||
return JXL_FAILURE("JPEG XL was built without JPEG support");
|
||||
}
|
||||
case extras::Codec::kPNM:
|
||||
if (io.Main().HasAlpha()) {
|
||||
encoder = extras::GetPAMEncoder();
|
||||
@ -103,13 +95,13 @@ Status Encode(const CodecInOut& io, const extras::Codec codec,
|
||||
case extras::Codec::kGIF:
|
||||
return JXL_FAILURE("Encoding to GIF is not implemented");
|
||||
case extras::Codec::kEXR:
|
||||
#if JPEGXL_ENABLE_EXR
|
||||
format.data_type = JXL_TYPE_FLOAT;
|
||||
encoder = extras::GetEXREncoder();
|
||||
break;
|
||||
#else
|
||||
return JXL_FAILURE("JPEG XL was built without OpenEXR support");
|
||||
#endif
|
||||
if (encoder) {
|
||||
break;
|
||||
} else {
|
||||
return JXL_FAILURE("JPEG XL was built without OpenEXR support");
|
||||
}
|
||||
case extras::Codec::kJXL:
|
||||
return JXL_FAILURE("TODO: encode using Codec::kJXL");
|
||||
|
||||
|
219
third_party/jpeg-xl/lib/extras/codec_test.cc
vendored
219
third_party/jpeg-xl/lib/extras/codec_test.cc
vendored
@ -15,17 +15,9 @@
|
||||
#include <vector>
|
||||
|
||||
#include "lib/extras/dec/decode.h"
|
||||
#include "lib/extras/dec/pgx.h"
|
||||
#include "lib/extras/dec/pnm.h"
|
||||
#include "lib/extras/enc/encode.h"
|
||||
#include "lib/extras/packed_image_convert.h"
|
||||
#include "lib/jxl/base/random.h"
|
||||
#include "lib/jxl/color_management.h"
|
||||
#include "lib/jxl/enc_butteraugli_comparator.h"
|
||||
#include "lib/jxl/enc_color_management.h"
|
||||
#include "lib/jxl/image.h"
|
||||
#include "lib/jxl/image_bundle.h"
|
||||
#include "lib/jxl/image_test_utils.h"
|
||||
#include "lib/jxl/test_utils.h"
|
||||
#include "lib/jxl/testing.h"
|
||||
|
||||
@ -40,7 +32,6 @@ using ::testing::AllOf;
|
||||
using ::testing::Contains;
|
||||
using ::testing::Field;
|
||||
using ::testing::IsEmpty;
|
||||
using ::testing::NotNull;
|
||||
using ::testing::SizeIs;
|
||||
|
||||
std::string ExtensionFromCodec(Codec codec, const bool is_gray,
|
||||
@ -57,17 +48,11 @@ std::string ExtensionFromCodec(Codec codec, const bool is_gray,
|
||||
if (bits_per_sample == 32) return ".pfm";
|
||||
if (has_alpha) return ".pam";
|
||||
return is_gray ? ".pgm" : ".ppm";
|
||||
case Codec::kGIF:
|
||||
return ".gif";
|
||||
case Codec::kEXR:
|
||||
return ".exr";
|
||||
case Codec::kJXL:
|
||||
return ".jxl";
|
||||
case Codec::kUnknown:
|
||||
default:
|
||||
return std::string();
|
||||
}
|
||||
JXL_UNREACHABLE;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
void VerifySameImage(const PackedImage& im0, size_t bits_per_sample0,
|
||||
@ -268,7 +253,10 @@ void TestRoundTrip(const TestImageParams& params, ThreadPool* pool) {
|
||||
|
||||
EncodedImage encoded;
|
||||
auto encoder = Encoder::FromExtension(extension);
|
||||
ASSERT_TRUE(encoder.get());
|
||||
if (!encoder) {
|
||||
fprintf(stderr, "Skipping test because of missing codec support.\n");
|
||||
return;
|
||||
}
|
||||
ASSERT_TRUE(encoder->Encode(ppf_in, &encoded, pool));
|
||||
ASSERT_EQ(encoded.bitstreams.size(), 1);
|
||||
|
||||
@ -325,7 +313,8 @@ TEST(CodecTest, TestRoundTrip) {
|
||||
params.xsize = 7;
|
||||
params.ysize = 4;
|
||||
|
||||
for (Codec codec : AvailableCodecs()) {
|
||||
for (Codec codec :
|
||||
{Codec::kPNG, Codec::kPNM, Codec::kPGX, Codec::kEXR, Codec::kJPG}) {
|
||||
for (int bits_per_sample : {4, 8, 10, 12, 16, 32}) {
|
||||
for (bool is_gray : {false, true}) {
|
||||
for (bool add_alpha : {false, true}) {
|
||||
@ -381,195 +370,6 @@ TEST(CodecTest, LosslessPNMRoundtrip) {
|
||||
}
|
||||
}
|
||||
|
||||
void DecodeRoundtrip(const std::string& pathname, ThreadPool* pool,
|
||||
CodecInOut& io,
|
||||
const ColorHints& color_hints = ColorHints()) {
|
||||
const PaddedBytes orig = jxl::test::ReadTestData(pathname);
|
||||
JXL_CHECK(SetFromBytes(Span<const uint8_t>(orig), color_hints, &io, pool));
|
||||
const ImageBundle& ib1 = io.Main();
|
||||
|
||||
// Encode/Decode again to make sure Encode carries through all metadata.
|
||||
std::vector<uint8_t> encoded;
|
||||
JXL_CHECK(Encode(io, Codec::kPNG, io.metadata.m.color_encoding,
|
||||
io.metadata.m.bit_depth.bits_per_sample, &encoded, pool));
|
||||
|
||||
CodecInOut io2;
|
||||
JXL_CHECK(
|
||||
SetFromBytes(Span<const uint8_t>(encoded), color_hints, &io2, pool));
|
||||
const ImageBundle& ib2 = io2.Main();
|
||||
EXPECT_EQ(Description(ib1.metadata()->color_encoding),
|
||||
Description(ib2.metadata()->color_encoding));
|
||||
EXPECT_EQ(Description(ib1.c_current()), Description(ib2.c_current()));
|
||||
|
||||
size_t bits_per_sample = io2.metadata.m.bit_depth.bits_per_sample;
|
||||
|
||||
// "Same" pixels?
|
||||
double max_l1 = bits_per_sample <= 12 ? 1.3 : 2E-3;
|
||||
double max_rel = bits_per_sample <= 12 ? 6E-3 : 1E-4;
|
||||
if (ib1.metadata()->color_encoding.IsGray()) {
|
||||
max_rel *= 2.0;
|
||||
} else if (ib1.metadata()->color_encoding.primaries != Primaries::kSRGB) {
|
||||
// Need more tolerance for large gamuts (anything but sRGB)
|
||||
max_l1 *= 1.5;
|
||||
max_rel *= 3.0;
|
||||
}
|
||||
JXL_ASSERT_OK(
|
||||
VerifyRelativeError(ib1.color(), ib2.color(), max_l1, max_rel, _));
|
||||
|
||||
// Simulate the encoder removing profile and decoder restoring it.
|
||||
if (!ib2.metadata()->color_encoding.WantICC()) {
|
||||
io2.metadata.m.color_encoding.InternalRemoveICC();
|
||||
EXPECT_TRUE(io2.metadata.m.color_encoding.CreateICC());
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
TEST(CodecTest, TestMetadataSRGB) {
|
||||
ThreadPoolForTests pool(12);
|
||||
|
||||
const char* paths[] = {"external/raw.pixls/DJI-FC6310-16bit_srgb8_v4_krita.png",
|
||||
"external/raw.pixls/Google-Pixel2XL-16bit_srgb8_v4_krita.png",
|
||||
"external/raw.pixls/HUAWEI-EVA-L09-16bit_srgb8_dt.png",
|
||||
"external/raw.pixls/Nikon-D300-12bit_srgb8_dt.png",
|
||||
"external/raw.pixls/Sony-DSC-RX1RM2-14bit_srgb8_v4_krita.png"};
|
||||
for (const char* relative_pathname : paths) {
|
||||
CodecInOut io;
|
||||
DecodeRoundtrip(relative_pathname, Codec::kPNG, &pool, io);
|
||||
EXPECT_EQ(8, io.metadata.m.bit_depth.bits_per_sample);
|
||||
EXPECT_FALSE(io.metadata.m.bit_depth.floating_point_sample);
|
||||
EXPECT_EQ(0, io.metadata.m.bit_depth.exponent_bits_per_sample);
|
||||
|
||||
EXPECT_EQ(64, io.xsize());
|
||||
EXPECT_EQ(64, io.ysize());
|
||||
EXPECT_FALSE(io.metadata.m.HasAlpha());
|
||||
|
||||
const ColorEncoding& c_original = io.metadata.m.color_encoding;
|
||||
EXPECT_FALSE(c_original.ICC().empty());
|
||||
EXPECT_EQ(ColorSpace::kRGB, c_original.GetColorSpace());
|
||||
EXPECT_EQ(WhitePoint::kD65, c_original.white_point);
|
||||
EXPECT_EQ(Primaries::kSRGB, c_original.primaries);
|
||||
EXPECT_TRUE(c_original.tf.IsSRGB());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CodecTest, TestMetadataLinear) {
|
||||
ThreadPoolForTests pool(12);
|
||||
|
||||
const char* paths[3] = {
|
||||
"external/raw.pixls/Google-Pixel2XL-16bit_acescg_g1_v4_krita.png",
|
||||
"external/raw.pixls/HUAWEI-EVA-L09-16bit_709_g1_dt.png",
|
||||
"external/raw.pixls/Nikon-D300-12bit_2020_g1_dt.png",
|
||||
};
|
||||
const WhitePoint white_points[3] = {WhitePoint::kCustom, WhitePoint::kD65,
|
||||
WhitePoint::kD65};
|
||||
const Primaries primaries[3] = {Primaries::kCustom, Primaries::kSRGB,
|
||||
Primaries::k2100};
|
||||
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
CodecInOut io;
|
||||
DecodeRoundtrip(paths[i], Codec::kPNG, &pool, io);
|
||||
EXPECT_EQ(16, io.metadata.m.bit_depth.bits_per_sample);
|
||||
EXPECT_FALSE(io.metadata.m.bit_depth.floating_point_sample);
|
||||
EXPECT_EQ(0, io.metadata.m.bit_depth.exponent_bits_per_sample);
|
||||
|
||||
EXPECT_EQ(64, io.xsize());
|
||||
EXPECT_EQ(64, io.ysize());
|
||||
EXPECT_FALSE(io.metadata.m.HasAlpha());
|
||||
|
||||
const ColorEncoding& c_original = io.metadata.m.color_encoding;
|
||||
EXPECT_FALSE(c_original.ICC().empty());
|
||||
EXPECT_EQ(ColorSpace::kRGB, c_original.GetColorSpace());
|
||||
EXPECT_EQ(white_points[i], c_original.white_point);
|
||||
EXPECT_EQ(primaries[i], c_original.primaries);
|
||||
EXPECT_TRUE(c_original.tf.IsLinear());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CodecTest, TestMetadataICC) {
|
||||
ThreadPoolForTests pool(12);
|
||||
|
||||
const char* paths[] = {
|
||||
"external/raw.pixls/DJI-FC6310-16bit_709_v4_krita.png",
|
||||
"external/raw.pixls/Sony-DSC-RX1RM2-14bit_709_v4_krita.png",
|
||||
};
|
||||
for (const char* relative_pathname : paths) {
|
||||
CodecInOut io;
|
||||
DecodeRoundtrip(relative_pathname, Codec::kPNG, &pool, io);
|
||||
EXPECT_GE(16, io.metadata.m.bit_depth.bits_per_sample);
|
||||
EXPECT_LE(14, io.metadata.m.bit_depth.bits_per_sample);
|
||||
|
||||
EXPECT_EQ(64, io.xsize());
|
||||
EXPECT_EQ(64, io.ysize());
|
||||
EXPECT_FALSE(io.metadata.m.HasAlpha());
|
||||
|
||||
const ColorEncoding& c_original = io.metadata.m.color_encoding;
|
||||
EXPECT_FALSE(c_original.ICC().empty());
|
||||
EXPECT_EQ(RenderingIntent::kPerceptual, c_original.rendering_intent);
|
||||
EXPECT_EQ(ColorSpace::kRGB, c_original.GetColorSpace());
|
||||
EXPECT_EQ(WhitePoint::kD65, c_original.white_point);
|
||||
EXPECT_EQ(Primaries::kSRGB, c_original.primaries);
|
||||
EXPECT_EQ(TransferFunction::k709, c_original.tf.GetTransferFunction());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CodecTest, Testexternal/pngsuite) {
|
||||
ThreadPoolForTests pool(12);
|
||||
|
||||
// Ensure we can load PNG with text, japanese UTF-8, compressed text.
|
||||
CodecInOut tmp1;
|
||||
DecodeRoundtrip("external/pngsuite/ct1n0g04.png", Codec::kPNG, &pool, tmp1);
|
||||
CodecInOut tmp2;
|
||||
DecodeRoundtrip("external/pngsuite/ctjn0g04.png", Codec::kPNG, &pool, tmp2);
|
||||
CodecInOut tmp3;
|
||||
DecodeRoundtrip("external/pngsuite/ctzn0g04.png", Codec::kPNG, &pool, tmp3);
|
||||
|
||||
// Extract gAMA
|
||||
CodecInOut b1;
|
||||
DecodeRoundtrip("external/pngsuite/g10n3p04.png", Codec::kPNG, &pool, b1);
|
||||
EXPECT_TRUE(b1.metadata.color_encoding.tf.IsLinear());
|
||||
|
||||
// Extract cHRM
|
||||
CodecInOut b_p;
|
||||
DecodeRoundtrip("external/pngsuite/ccwn2c08.png", Codec::kPNG, &pool, b_p);
|
||||
EXPECT_EQ(Primaries::kSRGB, b_p.metadata.color_encoding.primaries);
|
||||
EXPECT_EQ(WhitePoint::kD65, b_p.metadata.color_encoding.white_point);
|
||||
|
||||
// Extract EXIF from (new-style) dedicated chunk
|
||||
CodecInOut b_exif;
|
||||
DecodeRoundtrip("external/pngsuite/exif2c08.png", Codec::kPNG, &pool, b_exif);
|
||||
EXPECT_EQ(978, b_exif.blobs.exif.size());
|
||||
}
|
||||
#endif
|
||||
|
||||
void VerifyWideGamutMetadata(const std::string& relative_pathname,
|
||||
const Primaries primaries, ThreadPool* pool) {
|
||||
CodecInOut io;
|
||||
DecodeRoundtrip(relative_pathname, pool, io);
|
||||
|
||||
EXPECT_EQ(8u, io.metadata.m.bit_depth.bits_per_sample);
|
||||
EXPECT_FALSE(io.metadata.m.bit_depth.floating_point_sample);
|
||||
EXPECT_EQ(0u, io.metadata.m.bit_depth.exponent_bits_per_sample);
|
||||
|
||||
const ColorEncoding& c_original = io.metadata.m.color_encoding;
|
||||
EXPECT_FALSE(c_original.ICC().empty());
|
||||
EXPECT_EQ(RenderingIntent::kAbsolute, c_original.rendering_intent);
|
||||
EXPECT_EQ(ColorSpace::kRGB, c_original.GetColorSpace());
|
||||
EXPECT_EQ(WhitePoint::kD65, c_original.white_point);
|
||||
EXPECT_EQ(primaries, c_original.primaries);
|
||||
}
|
||||
|
||||
TEST(CodecTest, TestWideGamut) {
|
||||
ThreadPoolForTests pool(12);
|
||||
// VerifyWideGamutMetadata("external/wide-gamut-tests/P3-sRGB-color-bars.png",
|
||||
// Primaries::kP3, &pool);
|
||||
VerifyWideGamutMetadata("external/wide-gamut-tests/P3-sRGB-color-ring.png",
|
||||
Primaries::kP3, &pool);
|
||||
// VerifyWideGamutMetadata("external/wide-gamut-tests/R2020-sRGB-color-bars.png",
|
||||
// Primaries::k2100, &pool);
|
||||
// VerifyWideGamutMetadata("external/wide-gamut-tests/R2020-sRGB-color-ring.png",
|
||||
// Primaries::k2100, &pool);
|
||||
}
|
||||
|
||||
TEST(CodecTest, TestPNM) { TestCodecPNM(); }
|
||||
|
||||
TEST(CodecTest, FormatNegotiation) {
|
||||
@ -611,7 +411,10 @@ TEST(CodecTest, EncodeToPNG) {
|
||||
ThreadPool* const pool = nullptr;
|
||||
|
||||
std::unique_ptr<Encoder> png_encoder = Encoder::FromExtension(".png");
|
||||
ASSERT_THAT(png_encoder, NotNull());
|
||||
if (!png_encoder) {
|
||||
fprintf(stderr, "Skipping test because of missing codec support.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
const PaddedBytes original_png = jxl::test::ReadTestData(
|
||||
"external/wesaturate/500px/tmshre_riaphotographs_srgb8.png");
|
||||
|
16
third_party/jpeg-xl/lib/extras/dec/apng.cc
vendored
16
third_party/jpeg-xl/lib/extras/dec/apng.cc
vendored
@ -52,11 +52,14 @@
|
||||
#include "lib/jxl/base/scope_guard.h"
|
||||
#include "lib/jxl/common.h"
|
||||
#include "lib/jxl/sanitizers.h"
|
||||
#if JPEGXL_ENABLE_APNG
|
||||
#include "png.h" /* original (unpatched) libpng is ok */
|
||||
#endif
|
||||
|
||||
namespace jxl {
|
||||
namespace extras {
|
||||
|
||||
#if JPEGXL_ENABLE_APNG
|
||||
namespace {
|
||||
|
||||
constexpr unsigned char kExifSignature[6] = {0x45, 0x78, 0x69,
|
||||
@ -558,10 +561,20 @@ int processing_finish(png_structp png_ptr, png_infop info_ptr,
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
bool CanDecodeAPNG() {
|
||||
#if JPEGXL_ENABLE_APNG
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
Status DecodeImageAPNG(const Span<const uint8_t> bytes,
|
||||
const ColorHints& color_hints, PackedPixelFile* ppf,
|
||||
const SizeConstraints* constraints) {
|
||||
#if JPEGXL_ENABLE_APNG
|
||||
Reader r;
|
||||
unsigned int id, j, w, h, w0, h0, x0, y0;
|
||||
unsigned int delay_num, delay_den, dop, bop, rowbytes, imagesize;
|
||||
@ -956,6 +969,9 @@ Status DecodeImageAPNG(const Span<const uint8_t> bytes,
|
||||
ppf->frames.back().frame_info.is_last = true;
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace extras
|
||||
|
2
third_party/jpeg-xl/lib/extras/dec/apng.h
vendored
2
third_party/jpeg-xl/lib/extras/dec/apng.h
vendored
@ -23,6 +23,8 @@ struct SizeConstraints;
|
||||
|
||||
namespace extras {
|
||||
|
||||
bool CanDecodeAPNG();
|
||||
|
||||
// Decodes `bytes` into `ppf`.
|
||||
Status DecodeImageAPNG(Span<const uint8_t> bytes, const ColorHints& color_hints,
|
||||
PackedPixelFile* ppf,
|
||||
|
54
third_party/jpeg-xl/lib/extras/dec/decode.cc
vendored
54
third_party/jpeg-xl/lib/extras/dec/decode.cc
vendored
@ -7,18 +7,10 @@
|
||||
|
||||
#include <locale>
|
||||
|
||||
#if JPEGXL_ENABLE_APNG
|
||||
#include "lib/extras/dec/apng.h"
|
||||
#endif
|
||||
#if JPEGXL_ENABLE_EXR
|
||||
#include "lib/extras/dec/exr.h"
|
||||
#endif
|
||||
#if JPEGXL_ENABLE_GIF
|
||||
#include "lib/extras/dec/gif.h"
|
||||
#endif
|
||||
#if JPEGXL_ENABLE_JPEG
|
||||
#include "lib/extras/dec/jpg.h"
|
||||
#endif
|
||||
#include "lib/extras/dec/jxl.h"
|
||||
#include "lib/extras/dec/pgx.h"
|
||||
#include "lib/extras/dec/pnm.h"
|
||||
@ -53,25 +45,6 @@ void BasenameAndExtension(std::string path, std::string* basename,
|
||||
|
||||
} // namespace
|
||||
|
||||
std::vector<Codec> AvailableCodecs() {
|
||||
std::vector<Codec> out;
|
||||
#if JPEGXL_ENABLE_APNG
|
||||
out.push_back(Codec::kPNG);
|
||||
#endif
|
||||
#if JPEGXL_ENABLE_EXR
|
||||
out.push_back(Codec::kEXR);
|
||||
#endif
|
||||
#if JPEGXL_ENABLE_GIF
|
||||
out.push_back(Codec::kGIF);
|
||||
#endif
|
||||
#if JPEGXL_ENABLE_JPEG
|
||||
out.push_back(Codec::kJPG);
|
||||
#endif
|
||||
out.push_back(Codec::kPGX);
|
||||
out.push_back(Codec::kPNM);
|
||||
return out;
|
||||
}
|
||||
|
||||
Codec CodecFromPath(std::string path, size_t* JXL_RESTRICT bits_per_sample,
|
||||
std::string* basename, std::string* extension) {
|
||||
std::string base;
|
||||
@ -106,6 +79,25 @@ Codec CodecFromPath(std::string path, size_t* JXL_RESTRICT bits_per_sample,
|
||||
return Codec::kUnknown;
|
||||
}
|
||||
|
||||
bool CanDecode(Codec codec) {
|
||||
switch (codec) {
|
||||
case Codec::kEXR:
|
||||
return CanDecodeEXR();
|
||||
case Codec::kGIF:
|
||||
return CanDecodeGIF();
|
||||
case Codec::kJPG:
|
||||
return CanDecodeJPG();
|
||||
case Codec::kPNG:
|
||||
return CanDecodeAPNG();
|
||||
case Codec::kPNM:
|
||||
case Codec::kPGX:
|
||||
case Codec::kJXL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Status DecodeBytes(const Span<const uint8_t> bytes,
|
||||
const ColorHints& color_hints, extras::PackedPixelFile* ppf,
|
||||
const SizeConstraints* constraints, Codec* orig_codec) {
|
||||
@ -118,11 +110,9 @@ Status DecodeBytes(const Span<const uint8_t> bytes,
|
||||
ppf->info.orientation = JXL_ORIENT_IDENTITY;
|
||||
|
||||
const auto choose_codec = [&]() -> Codec {
|
||||
#if JPEGXL_ENABLE_APNG
|
||||
if (DecodeImageAPNG(bytes, color_hints, ppf, constraints)) {
|
||||
return Codec::kPNG;
|
||||
}
|
||||
#endif
|
||||
if (DecodeImagePGX(bytes, color_hints, ppf, constraints)) {
|
||||
return Codec::kPGX;
|
||||
}
|
||||
@ -135,21 +125,15 @@ Status DecodeBytes(const Span<const uint8_t> bytes,
|
||||
ppf)) {
|
||||
return Codec::kJXL;
|
||||
}
|
||||
#if JPEGXL_ENABLE_GIF
|
||||
if (DecodeImageGIF(bytes, color_hints, ppf, constraints)) {
|
||||
return Codec::kGIF;
|
||||
}
|
||||
#endif
|
||||
#if JPEGXL_ENABLE_JPEG
|
||||
if (DecodeImageJPG(bytes, color_hints, ppf, constraints)) {
|
||||
return Codec::kJPG;
|
||||
}
|
||||
#endif
|
||||
#if JPEGXL_ENABLE_EXR
|
||||
if (DecodeImageEXR(bytes, color_hints, ppf, constraints)) {
|
||||
return Codec::kEXR;
|
||||
}
|
||||
#endif
|
||||
return Codec::kUnknown;
|
||||
};
|
||||
|
||||
|
4
third_party/jpeg-xl/lib/extras/dec/decode.h
vendored
4
third_party/jpeg-xl/lib/extras/dec/decode.h
vendored
@ -24,7 +24,7 @@ struct SizeConstraints;
|
||||
|
||||
namespace extras {
|
||||
|
||||
// Codecs supported by CodecInOut::Encode.
|
||||
// Codecs supported by DecodeBytes.
|
||||
enum class Codec : uint32_t {
|
||||
kUnknown, // for CodecFromPath
|
||||
kPNG,
|
||||
@ -36,7 +36,7 @@ enum class Codec : uint32_t {
|
||||
kJXL
|
||||
};
|
||||
|
||||
std::vector<Codec> AvailableCodecs();
|
||||
bool CanDecode(Codec codec);
|
||||
|
||||
// If and only if extension is ".pfm", *bits_per_sample is updated to 32 so
|
||||
// that Encode() would encode to PFM instead of PPM.
|
||||
|
18
third_party/jpeg-xl/lib/extras/dec/exr.cc
vendored
18
third_party/jpeg-xl/lib/extras/dec/exr.cc
vendored
@ -5,20 +5,22 @@
|
||||
|
||||
#include "lib/extras/dec/exr.h"
|
||||
|
||||
#if JPEGXL_ENABLE_EXR
|
||||
#include <ImfChromaticitiesAttribute.h>
|
||||
#include <ImfIO.h>
|
||||
#include <ImfRgbaFile.h>
|
||||
#include <ImfStandardAttributes.h>
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace jxl {
|
||||
namespace extras {
|
||||
|
||||
#if JPEGXL_ENABLE_EXR
|
||||
namespace {
|
||||
|
||||
namespace OpenEXR = OPENEXR_IMF_NAMESPACE;
|
||||
namespace Imath = IMATH_NAMESPACE;
|
||||
|
||||
// OpenEXR::Int64 is deprecated in favor of using uint64_t directly, but using
|
||||
// uint64_t as recommended causes build failures with previous OpenEXR versions
|
||||
@ -60,10 +62,20 @@ class InMemoryIStream : public OpenEXR::IStream {
|
||||
};
|
||||
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
bool CanDecodeEXR() {
|
||||
#if JPEGXL_ENABLE_EXR
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
Status DecodeImageEXR(Span<const uint8_t> bytes, const ColorHints& color_hints,
|
||||
PackedPixelFile* ppf,
|
||||
const SizeConstraints* constraints) {
|
||||
#if JPEGXL_ENABLE_EXR
|
||||
InMemoryIStream is(bytes);
|
||||
|
||||
#ifdef __EXCEPTIONS
|
||||
@ -145,6 +157,7 @@ Status DecodeImageEXR(Span<const uint8_t> bytes, const ColorHints& color_hints,
|
||||
std::min(input.dataWindow().max.x, input.displayWindow().max.x);
|
||||
++exr_x) {
|
||||
const int image_x = exr_x - input.displayWindow().min.x;
|
||||
// TODO(eustas): UB: OpenEXR::Rgba is not TriviallyCopyable
|
||||
memcpy(row + image_x * pixel_size,
|
||||
input_row + (exr_x - input.dataWindow().min.x), pixel_size);
|
||||
}
|
||||
@ -179,6 +192,9 @@ Status DecodeImageEXR(Span<const uint8_t> bytes, const ColorHints& color_hints,
|
||||
}
|
||||
ppf->info.intensity_target = intensity_target;
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace extras
|
||||
|
2
third_party/jpeg-xl/lib/extras/dec/exr.h
vendored
2
third_party/jpeg-xl/lib/extras/dec/exr.h
vendored
@ -21,6 +21,8 @@ struct SizeConstraints;
|
||||
|
||||
namespace extras {
|
||||
|
||||
bool CanDecodeEXR();
|
||||
|
||||
// Decodes `bytes` into `ppf`. color_hints are ignored.
|
||||
Status DecodeImageEXR(Span<const uint8_t> bytes, const ColorHints& color_hints,
|
||||
PackedPixelFile* ppf,
|
||||
|
17
third_party/jpeg-xl/lib/extras/dec/gif.cc
vendored
17
third_party/jpeg-xl/lib/extras/dec/gif.cc
vendored
@ -5,7 +5,9 @@
|
||||
|
||||
#include "lib/extras/dec/gif.h"
|
||||
|
||||
#if JPEGXL_ENABLE_GIF
|
||||
#include <gif_lib.h>
|
||||
#endif
|
||||
#include <jxl/codestream_header.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -20,6 +22,7 @@
|
||||
namespace jxl {
|
||||
namespace extras {
|
||||
|
||||
#if JPEGXL_ENABLE_GIF
|
||||
namespace {
|
||||
|
||||
struct ReadState {
|
||||
@ -53,12 +56,21 @@ void ensure_have_alpha(PackedFrame* frame) {
|
||||
std::fill_n(static_cast<uint8_t*>(frame->extra_channels[0].pixels()),
|
||||
frame->color.xsize * frame->color.ysize, 255u);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
bool CanDecodeGIF() {
|
||||
#if JPEGXL_ENABLE_GIF
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
Status DecodeImageGIF(Span<const uint8_t> bytes, const ColorHints& color_hints,
|
||||
PackedPixelFile* ppf,
|
||||
const SizeConstraints* constraints) {
|
||||
#if JPEGXL_ENABLE_GIF
|
||||
int error = GIF_OK;
|
||||
ReadState state = {bytes};
|
||||
const auto ReadFromSpan = [](GifFileType* const gif, GifByteType* const bytes,
|
||||
@ -394,6 +406,9 @@ Status DecodeImageGIF(Span<const uint8_t> bytes, const ColorHints& color_hints,
|
||||
}
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace extras
|
||||
|
2
third_party/jpeg-xl/lib/extras/dec/gif.h
vendored
2
third_party/jpeg-xl/lib/extras/dec/gif.h
vendored
@ -22,6 +22,8 @@ struct SizeConstraints;
|
||||
|
||||
namespace extras {
|
||||
|
||||
bool CanDecodeGIF();
|
||||
|
||||
// Decodes `bytes` into `ppf`. color_hints are ignored.
|
||||
Status DecodeImageGIF(Span<const uint8_t> bytes, const ColorHints& color_hints,
|
||||
PackedPixelFile* ppf,
|
||||
|
16
third_party/jpeg-xl/lib/extras/dec/jpg.cc
vendored
16
third_party/jpeg-xl/lib/extras/dec/jpg.cc
vendored
@ -5,8 +5,10 @@
|
||||
|
||||
#include "lib/extras/dec/jpg.h"
|
||||
|
||||
#if JPEGXL_ENABLE_JPEG
|
||||
#include <jpeglib.h>
|
||||
#include <setjmp.h>
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
|
||||
#include <algorithm>
|
||||
@ -21,6 +23,7 @@
|
||||
namespace jxl {
|
||||
namespace extras {
|
||||
|
||||
#if JPEGXL_ENABLE_JPEG
|
||||
namespace {
|
||||
|
||||
constexpr unsigned char kICCSignature[12] = {
|
||||
@ -175,11 +178,21 @@ void UnmapColors(uint8_t* row, size_t xsize, int components,
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
bool CanDecodeJPG() {
|
||||
#if JPEGXL_ENABLE_JPEG
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
Status DecodeImageJPG(const Span<const uint8_t> bytes,
|
||||
const ColorHints& color_hints, PackedPixelFile* ppf,
|
||||
const SizeConstraints* constraints,
|
||||
const JPGDecompressParams* dparams) {
|
||||
#if JPEGXL_ENABLE_JPEG
|
||||
// Don't do anything for non-JPEG files (no need to report an error)
|
||||
if (!IsJPG(bytes)) return false;
|
||||
|
||||
@ -316,6 +329,9 @@ Status DecodeImageJPG(const Span<const uint8_t> bytes,
|
||||
};
|
||||
|
||||
return try_catch_block();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace extras
|
||||
|
2
third_party/jpeg-xl/lib/extras/dec/jpg.h
vendored
2
third_party/jpeg-xl/lib/extras/dec/jpg.h
vendored
@ -23,6 +23,8 @@ struct SizeConstraints;
|
||||
|
||||
namespace extras {
|
||||
|
||||
bool CanDecodeJPG();
|
||||
|
||||
struct JPGDecompressParams {
|
||||
int num_colors = 0;
|
||||
bool two_pass_quant = false;
|
||||
|
30
third_party/jpeg-xl/lib/extras/dec/jxl.cc
vendored
30
third_party/jpeg-xl/lib/extras/dec/jxl.cc
vendored
@ -347,21 +347,23 @@ bool DecodeImageJXL(const uint8_t* bytes, size_t bytes_size,
|
||||
}
|
||||
size_t icc_size = 0;
|
||||
JxlColorProfileTarget target = JXL_COLOR_PROFILE_TARGET_DATA;
|
||||
if (JXL_DEC_SUCCESS !=
|
||||
JxlDecoderGetICCProfileSize(dec, target, &icc_size)) {
|
||||
fprintf(stderr, "JxlDecoderGetICCProfileSize failed\n");
|
||||
}
|
||||
if (icc_size != 0) {
|
||||
ppf->icc.resize(icc_size);
|
||||
if (JXL_DEC_SUCCESS != JxlDecoderGetColorAsICCProfile(
|
||||
dec, target, ppf->icc.data(), icc_size)) {
|
||||
fprintf(stderr, "JxlDecoderGetColorAsICCProfile failed\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
ppf->color_encoding.color_space = JXL_COLOR_SPACE_UNKNOWN;
|
||||
if (JXL_DEC_SUCCESS != JxlDecoderGetColorAsEncodedProfile(
|
||||
dec, target, &ppf->color_encoding)) {
|
||||
ppf->color_encoding.color_space = JXL_COLOR_SPACE_UNKNOWN;
|
||||
dec, target, &ppf->color_encoding) ||
|
||||
dparams.need_icc) {
|
||||
// only get ICC if it is not an Enum color encoding
|
||||
if (JXL_DEC_SUCCESS !=
|
||||
JxlDecoderGetICCProfileSize(dec, target, &icc_size)) {
|
||||
fprintf(stderr, "JxlDecoderGetICCProfileSize failed\n");
|
||||
}
|
||||
if (icc_size != 0) {
|
||||
ppf->icc.resize(icc_size);
|
||||
if (JXL_DEC_SUCCESS != JxlDecoderGetColorAsICCProfile(
|
||||
dec, target, ppf->icc.data(), icc_size)) {
|
||||
fprintf(stderr, "JxlDecoderGetColorAsICCProfile failed\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
icc_size = 0;
|
||||
target = JXL_COLOR_PROFILE_TARGET_ORIGINAL;
|
||||
|
4
third_party/jpeg-xl/lib/extras/dec/jxl.h
vendored
4
third_party/jpeg-xl/lib/extras/dec/jxl.h
vendored
@ -41,6 +41,10 @@ struct JXLDecompressParams {
|
||||
// Whether truncated input should be treated as an error.
|
||||
bool allow_partial_input = false;
|
||||
|
||||
// Set to true if an ICC profile has to be synthesized for Enum color
|
||||
// encodings
|
||||
bool need_icc = false;
|
||||
|
||||
// How many passes to decode at most. By default, decode everything.
|
||||
uint32_t max_passes = std::numeric_limits<uint32_t>::max();
|
||||
|
||||
|
69
third_party/jpeg-xl/lib/extras/enc/apng.cc
vendored
69
third_party/jpeg-xl/lib/extras/enc/apng.cc
vendored
@ -45,11 +45,14 @@
|
||||
#include "lib/extras/exif.h"
|
||||
#include "lib/jxl/base/byte_order.h"
|
||||
#include "lib/jxl/base/printf_macros.h"
|
||||
#if JPEGXL_ENABLE_APNG
|
||||
#include "png.h" /* original (unpatched) libpng is ok */
|
||||
#endif
|
||||
|
||||
namespace jxl {
|
||||
namespace extras {
|
||||
|
||||
#if JPEGXL_ENABLE_APNG
|
||||
namespace {
|
||||
|
||||
constexpr unsigned char kExifSignature[6] = {0x45, 0x78, 0x69,
|
||||
@ -158,7 +161,7 @@ class BlobsWriterPNG {
|
||||
}
|
||||
};
|
||||
|
||||
void MaybeAddCICP(JxlColorEncoding c_enc, png_structp png_ptr,
|
||||
void MaybeAddCICP(const JxlColorEncoding& c_enc, png_structp png_ptr,
|
||||
png_infop info_ptr) {
|
||||
png_byte cicp_data[4] = {};
|
||||
png_unknown_chunk cicp_chunk;
|
||||
@ -195,6 +198,51 @@ void MaybeAddCICP(JxlColorEncoding c_enc, png_structp png_ptr,
|
||||
png_set_unknown_chunks(png_ptr, info_ptr, &cicp_chunk, 1);
|
||||
}
|
||||
|
||||
bool MaybeAddSRGB(const JxlColorEncoding& c_enc, png_structp png_ptr,
|
||||
png_infop info_ptr) {
|
||||
if (c_enc.transfer_function == JXL_TRANSFER_FUNCTION_SRGB &&
|
||||
(c_enc.color_space == JXL_COLOR_SPACE_GRAY ||
|
||||
(c_enc.color_space == JXL_COLOR_SPACE_RGB &&
|
||||
c_enc.primaries == JXL_PRIMARIES_SRGB &&
|
||||
c_enc.white_point == JXL_WHITE_POINT_D65))) {
|
||||
png_set_sRGB(png_ptr, info_ptr, c_enc.rendering_intent);
|
||||
png_set_cHRM_fixed(png_ptr, info_ptr, 31270, 32900, 64000, 33000, 30000,
|
||||
60000, 15000, 6000);
|
||||
png_set_gAMA_fixed(png_ptr, info_ptr, 45455);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MaybeAddCHRM(const JxlColorEncoding& c_enc, png_structp png_ptr,
|
||||
png_infop info_ptr) {
|
||||
if (c_enc.color_space != JXL_COLOR_SPACE_RGB) return;
|
||||
if (c_enc.primaries == 0) return;
|
||||
png_set_cHRM(png_ptr, info_ptr, c_enc.white_point_xy[0],
|
||||
c_enc.white_point_xy[1], c_enc.primaries_red_xy[0],
|
||||
c_enc.primaries_red_xy[1], c_enc.primaries_green_xy[0],
|
||||
c_enc.primaries_green_xy[1], c_enc.primaries_blue_xy[0],
|
||||
c_enc.primaries_blue_xy[1]);
|
||||
}
|
||||
|
||||
void MaybeAddGAMA(const JxlColorEncoding& c_enc, png_structp png_ptr,
|
||||
png_infop info_ptr) {
|
||||
switch (c_enc.transfer_function) {
|
||||
case JXL_TRANSFER_FUNCTION_LINEAR:
|
||||
png_set_gAMA_fixed(png_ptr, info_ptr, PNG_FP_1);
|
||||
break;
|
||||
case JXL_TRANSFER_FUNCTION_SRGB:
|
||||
png_set_gAMA_fixed(png_ptr, info_ptr, 45455);
|
||||
break;
|
||||
case JXL_TRANSFER_FUNCTION_GAMMA:
|
||||
png_set_gAMA(png_ptr, info_ptr, c_enc.gamma);
|
||||
break;
|
||||
|
||||
default:;
|
||||
// No gAMA chunk.
|
||||
}
|
||||
}
|
||||
|
||||
Status APNGEncoder::EncodePackedPixelFileToAPNG(
|
||||
const PackedPixelFile& ppf, ThreadPool* pool,
|
||||
std::vector<uint8_t>* bytes) const {
|
||||
@ -274,11 +322,17 @@ Status APNGEncoder::EncodePackedPixelFileToAPNG(
|
||||
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
|
||||
PNG_FILTER_TYPE_BASE);
|
||||
if (count == 0) {
|
||||
MaybeAddCICP(ppf.color_encoding, png_ptr, info_ptr);
|
||||
if (!ppf.icc.empty()) {
|
||||
png_set_benign_errors(png_ptr, 1);
|
||||
png_set_iCCP(png_ptr, info_ptr, "1", 0, ppf.icc.data(), ppf.icc.size());
|
||||
if (!MaybeAddSRGB(ppf.color_encoding, png_ptr, info_ptr)) {
|
||||
MaybeAddCICP(ppf.color_encoding, png_ptr, info_ptr);
|
||||
if (!ppf.icc.empty()) {
|
||||
png_set_benign_errors(png_ptr, 1);
|
||||
png_set_iCCP(png_ptr, info_ptr, "1", 0, ppf.icc.data(),
|
||||
ppf.icc.size());
|
||||
}
|
||||
MaybeAddCHRM(ppf.color_encoding, png_ptr, info_ptr);
|
||||
MaybeAddGAMA(ppf.color_encoding, png_ptr, info_ptr);
|
||||
}
|
||||
|
||||
std::vector<std::string> textstrings;
|
||||
JXL_RETURN_IF_ERROR(BlobsWriterPNG::Encode(ppf.metadata, &textstrings));
|
||||
for (size_t kk = 0; kk + 1 < textstrings.size(); kk += 2) {
|
||||
@ -362,9 +416,14 @@ Status APNGEncoder::EncodePackedPixelFileToAPNG(
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
std::unique_ptr<Encoder> GetAPNGEncoder() {
|
||||
#if JPEGXL_ENABLE_APNG
|
||||
return jxl::make_unique<APNGEncoder>();
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace extras
|
||||
|
18
third_party/jpeg-xl/lib/extras/enc/encode.cc
vendored
18
third_party/jpeg-xl/lib/extras/enc/encode.cc
vendored
@ -7,15 +7,9 @@
|
||||
|
||||
#include <locale>
|
||||
|
||||
#if JPEGXL_ENABLE_APNG
|
||||
#include "lib/extras/enc/apng.h"
|
||||
#endif
|
||||
#if JPEGXL_ENABLE_EXR
|
||||
#include "lib/extras/enc/exr.h"
|
||||
#endif
|
||||
#if JPEGXL_ENABLE_JPEG
|
||||
#include "lib/extras/enc/jpg.h"
|
||||
#endif
|
||||
#include "lib/extras/enc/npy.h"
|
||||
#include "lib/extras/enc/pgx.h"
|
||||
#include "lib/extras/enc/pnm.h"
|
||||
@ -139,28 +133,16 @@ std::unique_ptr<Encoder> Encoder::FromExtension(std::string extension) {
|
||||
std::transform(
|
||||
extension.begin(), extension.end(), extension.begin(),
|
||||
[](char c) { return std::tolower(c, std::locale::classic()); });
|
||||
#if JPEGXL_ENABLE_APNG
|
||||
if (extension == ".png" || extension == ".apng") return GetAPNGEncoder();
|
||||
#endif
|
||||
|
||||
#if JPEGXL_ENABLE_JPEG
|
||||
if (extension == ".jpg") return GetJPEGEncoder();
|
||||
if (extension == ".jpeg") return GetJPEGEncoder();
|
||||
#endif
|
||||
|
||||
if (extension == ".npy") return GetNumPyEncoder();
|
||||
|
||||
if (extension == ".pgx") return GetPGXEncoder();
|
||||
|
||||
if (extension == ".pam") return GetPAMEncoder();
|
||||
if (extension == ".pgm") return GetPGMEncoder();
|
||||
if (extension == ".ppm") return GetPPMEncoder();
|
||||
if (extension == ".pfm") return GetPFMEncoder();
|
||||
|
||||
#if JPEGXL_ENABLE_EXR
|
||||
if (extension == ".exr") return GetEXREncoder();
|
||||
#endif
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
8
third_party/jpeg-xl/lib/extras/enc/exr.cc
vendored
8
third_party/jpeg-xl/lib/extras/enc/exr.cc
vendored
@ -5,10 +5,12 @@
|
||||
|
||||
#include "lib/extras/enc/exr.h"
|
||||
|
||||
#if JPEGXL_ENABLE_EXR
|
||||
#include <ImfChromaticitiesAttribute.h>
|
||||
#include <ImfIO.h>
|
||||
#include <ImfRgbaFile.h>
|
||||
#include <ImfStandardAttributes.h>
|
||||
#endif
|
||||
#include <jxl/codestream_header.h>
|
||||
|
||||
#include <vector>
|
||||
@ -19,6 +21,7 @@
|
||||
namespace jxl {
|
||||
namespace extras {
|
||||
|
||||
#if JPEGXL_ENABLE_EXR
|
||||
namespace {
|
||||
|
||||
namespace OpenEXR = OPENEXR_IMF_NAMESPACE;
|
||||
@ -191,9 +194,14 @@ class EXREncoder : public Encoder {
|
||||
};
|
||||
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
std::unique_ptr<Encoder> GetEXREncoder() {
|
||||
#if JPEGXL_ENABLE_EXR
|
||||
return jxl::make_unique<EXREncoder>();
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace extras
|
||||
|
38
third_party/jpeg-xl/lib/extras/enc/jpegli.cc
vendored
38
third_party/jpeg-xl/lib/extras/enc/jpegli.cc
vendored
@ -29,9 +29,6 @@ void MyErrorExit(j_common_ptr cinfo) {
|
||||
Status VerifyInput(const PackedPixelFile& ppf) {
|
||||
const JxlBasicInfo& info = ppf.info;
|
||||
JXL_RETURN_IF_ERROR(Encoder::VerifyBasicInfo(info));
|
||||
if (info.alpha_bits > 0) {
|
||||
return JXL_FAILURE("Alpha is not supported for JPEG output.");
|
||||
}
|
||||
if (ppf.frames.size() != 1) {
|
||||
return JXL_FAILURE("JPEG input must have exactly one frame.");
|
||||
}
|
||||
@ -51,12 +48,12 @@ Status VerifyInput(const PackedPixelFile& ppf) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Status GetColorEncoding(const PackedPixelFile& ppf,
|
||||
Status GetColorEncoding(const PackedPixelFile& ppf, const JxlCmsInterface* cms,
|
||||
ColorEncoding* color_encoding) {
|
||||
if (!ppf.icc.empty()) {
|
||||
PaddedBytes icc;
|
||||
icc.assign(ppf.icc.data(), ppf.icc.data() + ppf.icc.size());
|
||||
JXL_RETURN_IF_ERROR(color_encoding->SetICC(std::move(icc)));
|
||||
JXL_RETURN_IF_ERROR(color_encoding->SetICC(std::move(icc), cms));
|
||||
} else {
|
||||
JXL_RETURN_IF_ERROR(ConvertExternalToInternalColorEncoding(
|
||||
ppf.color_encoding, color_encoding));
|
||||
@ -329,10 +326,12 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings,
|
||||
}
|
||||
JXL_RETURN_IF_ERROR(VerifyInput(ppf));
|
||||
|
||||
ColorEncoding color_encoding;
|
||||
JXL_RETURN_IF_ERROR(GetColorEncoding(ppf, &color_encoding));
|
||||
const JxlCmsInterface& cms = GetJxlCms();
|
||||
|
||||
ColorSpaceTransform c_transform(GetJxlCms());
|
||||
ColorEncoding color_encoding;
|
||||
JXL_RETURN_IF_ERROR(GetColorEncoding(ppf, &cms, &color_encoding));
|
||||
|
||||
ColorSpaceTransform c_transform(cms);
|
||||
ColorEncoding xyb_encoding;
|
||||
if (jpeg_settings.xyb) {
|
||||
if (ppf.info.num_color_channels != 3) {
|
||||
@ -491,10 +490,25 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings,
|
||||
}
|
||||
} else {
|
||||
row_bytes.resize(image.stride);
|
||||
for (size_t y = 0; y < info.ysize; ++y) {
|
||||
memcpy(&row_bytes[0], pixels + y * image.stride, image.stride);
|
||||
JSAMPROW row[] = {row_bytes.data()};
|
||||
jpegli_write_scanlines(&cinfo, row, 1);
|
||||
if (cinfo.num_components == (int)image.format.num_channels) {
|
||||
for (size_t y = 0; y < info.ysize; ++y) {
|
||||
memcpy(&row_bytes[0], pixels + y * image.stride, image.stride);
|
||||
JSAMPROW row[] = {row_bytes.data()};
|
||||
jpegli_write_scanlines(&cinfo, row, 1);
|
||||
}
|
||||
} else {
|
||||
for (size_t y = 0; y < info.ysize; ++y) {
|
||||
int bytes_per_channel =
|
||||
PackedImage::BitsPerChannel(image.format.data_type) / 8;
|
||||
int bytes_per_pixel = cinfo.num_components * bytes_per_channel;
|
||||
for (size_t x = 0; x < info.xsize; ++x) {
|
||||
memcpy(&row_bytes[x * bytes_per_pixel],
|
||||
&pixels[y * image.stride + x * image.pixel_stride()],
|
||||
bytes_per_pixel);
|
||||
}
|
||||
JSAMPROW row[] = {row_bytes.data()};
|
||||
jpegli_write_scanlines(&cinfo, row, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
jpegli_finish_compress(&cinfo);
|
||||
|
66
third_party/jpeg-xl/lib/extras/enc/jpg.cc
vendored
66
third_party/jpeg-xl/lib/extras/enc/jpg.cc
vendored
@ -5,8 +5,10 @@
|
||||
|
||||
#include "lib/extras/enc/jpg.h"
|
||||
|
||||
#if JPEGXL_ENABLE_JPEG
|
||||
#include <jpeglib.h>
|
||||
#include <setjmp.h>
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
|
||||
#include <algorithm>
|
||||
@ -31,6 +33,7 @@
|
||||
namespace jxl {
|
||||
namespace extras {
|
||||
|
||||
#if JPEGXL_ENABLE_JPEG
|
||||
namespace {
|
||||
|
||||
constexpr unsigned char kICCSignature[12] = {
|
||||
@ -313,13 +316,39 @@ Status EncodeWithLibJpeg(const PackedImage& image, const JxlBasicInfo& info,
|
||||
if (cinfo.input_components > 3 || cinfo.input_components < 0)
|
||||
return JXL_FAILURE("invalid numbers of components");
|
||||
|
||||
std::vector<uint8_t> raw_bytes(image.pixels_size);
|
||||
memcpy(&raw_bytes[0], reinterpret_cast<const uint8_t*>(image.pixels()),
|
||||
image.pixels_size);
|
||||
for (size_t y = 0; y < info.ysize; ++y) {
|
||||
JSAMPROW row[] = {raw_bytes.data() + y * image.stride};
|
||||
|
||||
jpeg_write_scanlines(&cinfo, row, 1);
|
||||
std::vector<uint8_t> row_bytes(image.stride);
|
||||
const uint8_t* pixels = reinterpret_cast<const uint8_t*>(image.pixels());
|
||||
if (cinfo.num_components == (int)image.format.num_channels &&
|
||||
image.format.data_type == JXL_TYPE_UINT8) {
|
||||
for (size_t y = 0; y < info.ysize; ++y) {
|
||||
memcpy(&row_bytes[0], pixels + y * image.stride, image.stride);
|
||||
JSAMPROW row[] = {row_bytes.data()};
|
||||
jpeg_write_scanlines(&cinfo, row, 1);
|
||||
}
|
||||
} else if (image.format.data_type == JXL_TYPE_UINT8) {
|
||||
for (size_t y = 0; y < info.ysize; ++y) {
|
||||
const uint8_t* image_row = pixels + y * image.stride;
|
||||
for (size_t x = 0; x < info.xsize; ++x) {
|
||||
const uint8_t* image_pixel = image_row + x * image.pixel_stride();
|
||||
memcpy(&row_bytes[x * cinfo.num_components], image_pixel,
|
||||
cinfo.num_components);
|
||||
}
|
||||
JSAMPROW row[] = {row_bytes.data()};
|
||||
jpeg_write_scanlines(&cinfo, row, 1);
|
||||
}
|
||||
} else {
|
||||
for (size_t y = 0; y < info.ysize; ++y) {
|
||||
const uint8_t* image_row = pixels + y * image.stride;
|
||||
for (size_t x = 0; x < info.xsize; ++x) {
|
||||
const uint8_t* image_pixel = image_row + x * image.pixel_stride();
|
||||
for (int c = 0; c < cinfo.num_components; ++c) {
|
||||
uint32_t val16 = (image_pixel[2 * c] << 8) + image_pixel[2 * c + 1];
|
||||
row_bytes[x * cinfo.num_components + c] = (val16 + 128) / 257;
|
||||
}
|
||||
}
|
||||
JSAMPROW row[] = {row_bytes.data()};
|
||||
jpeg_write_scanlines(&cinfo, row, 1);
|
||||
}
|
||||
}
|
||||
jpeg_finish_compress(&cinfo);
|
||||
jpeg_destroy_compress(&cinfo);
|
||||
@ -412,6 +441,12 @@ Status EncodeWithSJpeg(const PackedImage& image, const JxlBasicInfo& info,
|
||||
#if !JPEGXL_ENABLE_SJPEG
|
||||
return JXL_FAILURE("JPEG XL was built without sjpeg support");
|
||||
#else
|
||||
if (image.format.data_type != JXL_TYPE_UINT8) {
|
||||
return JXL_FAILURE("Unsupported pixel data type");
|
||||
}
|
||||
if (info.alpha_bits > 0) {
|
||||
return JXL_FAILURE("alpha is not supported");
|
||||
}
|
||||
sjpeg::EncoderParam param(params.quality);
|
||||
if (!icc.empty()) {
|
||||
param.iccp.assign(icc.begin(), icc.end());
|
||||
@ -474,12 +509,6 @@ Status EncodeImageJPG(const PackedImage& image, const JxlBasicInfo& info,
|
||||
std::vector<uint8_t> exif, JpegEncoder encoder,
|
||||
const JpegParams& params, ThreadPool* pool,
|
||||
std::vector<uint8_t>* bytes) {
|
||||
if (image.format.data_type != JXL_TYPE_UINT8) {
|
||||
return JXL_FAILURE("Unsupported pixel data type");
|
||||
}
|
||||
if (info.alpha_bits > 0) {
|
||||
return JXL_FAILURE("alpha is not supported");
|
||||
}
|
||||
if (params.quality > 100) {
|
||||
return JXL_FAILURE("please specify a 0-100 JPEG quality");
|
||||
}
|
||||
@ -503,13 +532,17 @@ Status EncodeImageJPG(const PackedImage& image, const JxlBasicInfo& info,
|
||||
class JPEGEncoder : public Encoder {
|
||||
std::vector<JxlPixelFormat> AcceptedFormats() const override {
|
||||
std::vector<JxlPixelFormat> formats;
|
||||
for (const uint32_t num_channels : {1, 3}) {
|
||||
for (const uint32_t num_channels : {1, 2, 3, 4}) {
|
||||
for (JxlEndianness endianness : {JXL_BIG_ENDIAN, JXL_LITTLE_ENDIAN}) {
|
||||
formats.push_back(JxlPixelFormat{/*num_channels=*/num_channels,
|
||||
/*data_type=*/JXL_TYPE_UINT8,
|
||||
/*endianness=*/endianness,
|
||||
/*align=*/0});
|
||||
}
|
||||
formats.push_back(JxlPixelFormat{/*num_channels=*/num_channels,
|
||||
/*data_type=*/JXL_TYPE_UINT16,
|
||||
/*endianness=*/JXL_BIG_ENDIAN,
|
||||
/*align=*/0});
|
||||
}
|
||||
return formats;
|
||||
}
|
||||
@ -583,9 +616,14 @@ class JPEGEncoder : public Encoder {
|
||||
};
|
||||
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
std::unique_ptr<Encoder> GetJPEGEncoder() {
|
||||
#if JPEGXL_ENABLE_JPEG
|
||||
return jxl::make_unique<JPEGEncoder>();
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace extras
|
||||
|
7
third_party/jpeg-xl/lib/extras/enc/jxl.cc
vendored
7
third_party/jpeg-xl/lib/extras/enc/jxl.cc
vendored
@ -62,6 +62,13 @@ bool EncodeImageJXL(const JXLCompressParams& params, const PackedPixelFile& ppf,
|
||||
fprintf(stderr, "Setting frame distance failed.\n");
|
||||
return false;
|
||||
}
|
||||
if (params.debug_image) {
|
||||
JxlEncoderSetDebugImageCallback(settings, params.debug_image,
|
||||
params.debug_image_opaque);
|
||||
}
|
||||
if (params.stats) {
|
||||
JxlEncoderCollectStats(settings, params.stats);
|
||||
}
|
||||
|
||||
bool use_boxes = !ppf.metadata.exif.empty() || !ppf.metadata.xmp.empty() ||
|
||||
!ppf.metadata.jumbf.empty() || !ppf.metadata.iptc.empty();
|
||||
|
4
third_party/jpeg-xl/lib/extras/enc/jxl.h
vendored
4
third_party/jpeg-xl/lib/extras/enc/jxl.h
vendored
@ -58,7 +58,9 @@ struct JXLCompressParams {
|
||||
// If runner_opaque is set, the decoder uses this parallel runner.
|
||||
JxlParallelRunner runner = JxlThreadParallelRunner;
|
||||
void* runner_opaque = nullptr;
|
||||
|
||||
JxlDebugImageCallback debug_image = nullptr;
|
||||
void* debug_image_opaque = nullptr;
|
||||
JxlEncoderStats* stats = nullptr;
|
||||
bool allow_expert_options = false;
|
||||
|
||||
void AddOption(JxlEncoderFrameSettingId id, int64_t val) {
|
||||
|
12
third_party/jpeg-xl/lib/extras/jpegli_test.cc
vendored
12
third_party/jpeg-xl/lib/extras/jpegli_test.cc
vendored
@ -3,7 +3,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#if JPEGXL_ENABLE_JPEG && JPEGXL_ENABLE_JPEGLI
|
||||
#if JPEGXL_ENABLE_JPEGLI
|
||||
|
||||
#include "lib/extras/dec/jpegli.h"
|
||||
|
||||
@ -95,6 +95,7 @@ float BitsPerPixel(const PackedPixelFile& ppf,
|
||||
}
|
||||
|
||||
TEST(JpegliTest, JpegliSRGBDecodeTest) {
|
||||
TEST_LIBJPEG_SUPPORT();
|
||||
std::string testimage = "jxl/flower/flower_small.rgb.depth8.ppm";
|
||||
PackedPixelFile ppf0;
|
||||
ASSERT_TRUE(ReadTestImage(testimage, &ppf0));
|
||||
@ -113,6 +114,7 @@ TEST(JpegliTest, JpegliSRGBDecodeTest) {
|
||||
}
|
||||
|
||||
TEST(JpegliTest, JpegliGrayscaleDecodeTest) {
|
||||
TEST_LIBJPEG_SUPPORT();
|
||||
std::string testimage = "jxl/flower/flower_small.g.depth8.pgm";
|
||||
PackedPixelFile ppf0;
|
||||
ASSERT_TRUE(ReadTestImage(testimage, &ppf0));
|
||||
@ -131,6 +133,7 @@ TEST(JpegliTest, JpegliGrayscaleDecodeTest) {
|
||||
}
|
||||
|
||||
TEST(JpegliTest, JpegliXYBEncodeTest) {
|
||||
TEST_LIBJPEG_SUPPORT();
|
||||
std::string testimage = "jxl/flower/flower_small.rgb.depth8.ppm";
|
||||
PackedPixelFile ppf_in;
|
||||
ASSERT_TRUE(ReadTestImage(testimage, &ppf_in));
|
||||
@ -149,6 +152,7 @@ TEST(JpegliTest, JpegliXYBEncodeTest) {
|
||||
}
|
||||
|
||||
TEST(JpegliTest, JpegliDecodeTestLargeSmoothArea) {
|
||||
TEST_LIBJPEG_SUPPORT();
|
||||
TestImage t;
|
||||
const size_t xsize = 2070;
|
||||
const size_t ysize = 1063;
|
||||
@ -178,6 +182,7 @@ TEST(JpegliTest, JpegliDecodeTestLargeSmoothArea) {
|
||||
}
|
||||
|
||||
TEST(JpegliTest, JpegliYUVEncodeTest) {
|
||||
TEST_LIBJPEG_SUPPORT();
|
||||
std::string testimage = "jxl/flower/flower_small.rgb.depth8.ppm";
|
||||
PackedPixelFile ppf_in;
|
||||
ASSERT_TRUE(ReadTestImage(testimage, &ppf_in));
|
||||
@ -196,6 +201,7 @@ TEST(JpegliTest, JpegliYUVEncodeTest) {
|
||||
}
|
||||
|
||||
TEST(JpegliTest, JpegliYUVChromaSubsamplingEncodeTest) {
|
||||
TEST_LIBJPEG_SUPPORT();
|
||||
std::string testimage = "jxl/flower/flower_small.rgb.depth8.ppm";
|
||||
PackedPixelFile ppf_in;
|
||||
ASSERT_TRUE(ReadTestImage(testimage, &ppf_in));
|
||||
@ -217,6 +223,7 @@ TEST(JpegliTest, JpegliYUVChromaSubsamplingEncodeTest) {
|
||||
}
|
||||
|
||||
TEST(JpegliTest, JpegliYUVEncodeTestNoAq) {
|
||||
TEST_LIBJPEG_SUPPORT();
|
||||
std::string testimage = "jxl/flower/flower_small.rgb.depth8.ppm";
|
||||
PackedPixelFile ppf_in;
|
||||
ASSERT_TRUE(ReadTestImage(testimage, &ppf_in));
|
||||
@ -320,6 +327,7 @@ class JpegliColorQuantTestParam : public ::testing::TestWithParam<TestConfig> {
|
||||
};
|
||||
|
||||
TEST_P(JpegliColorQuantTestParam, JpegliColorQuantizeTest) {
|
||||
TEST_LIBJPEG_SUPPORT();
|
||||
TestConfig config = GetParam();
|
||||
std::string testimage = "jxl/flower/flower_small.rgb.depth8.ppm";
|
||||
PackedPixelFile ppf0;
|
||||
@ -402,4 +410,4 @@ JXL_GTEST_INSTANTIATE_TEST_SUITE_P(JpegliColorQuantTest,
|
||||
} // namespace
|
||||
} // namespace extras
|
||||
} // namespace jxl
|
||||
#endif // JPEGXL_ENABLE_JPEG
|
||||
#endif // JPEGXL_ENABLE_JPEGLI
|
||||
|
@ -115,7 +115,8 @@ Status ConvertPackedPixelFileToCodecInOut(const PackedPixelFile& ppf,
|
||||
if (!ppf.icc.empty()) {
|
||||
PaddedBytes icc;
|
||||
icc.append(ppf.icc);
|
||||
if (!io->metadata.m.color_encoding.SetICC(std::move(icc))) {
|
||||
const JxlCmsInterface& cms = GetJxlCms();
|
||||
if (!io->metadata.m.color_encoding.SetICC(std::move(icc), &cms)) {
|
||||
fprintf(stderr, "Warning: error setting ICC profile, assuming SRGB\n");
|
||||
io->metadata.m.color_encoding = ColorEncoding::SRGB(is_gray);
|
||||
} else {
|
||||
|
@ -25,6 +25,21 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Parses an ICC profile and populates @p c and @p cmyk with the data.
|
||||
*
|
||||
* @param user_data JxlCmsInterface::set_fields_data passed as-is.
|
||||
* @param icc_data the ICC data to parse.
|
||||
* @param icc_size how many bytes of icc_data are valid.
|
||||
* @param c a JxlColorEncoding to populate if applicable.
|
||||
* @param cmyk a boolean to set to whether the colorspace is a CMYK colorspace.
|
||||
* @return Whether the relevant fields in @p c were successfully populated.
|
||||
*/
|
||||
typedef JXL_BOOL (*jpegxl_cms_set_fields_from_icc_func)(void* user_data,
|
||||
const uint8_t* icc_data,
|
||||
size_t icc_size,
|
||||
JxlColorEncoding* c,
|
||||
JXL_BOOL* cmyk);
|
||||
|
||||
/** Represents an input or output colorspace to a color transform, as a
|
||||
* serialized ICC profile. */
|
||||
typedef struct {
|
||||
@ -207,6 +222,11 @@ typedef void (*jpegxl_cms_destroy_func)(void*);
|
||||
* @enddot
|
||||
*/
|
||||
typedef struct {
|
||||
/** CMS-specific data that will be passed to @ref set_fields_from_icc. */
|
||||
void* set_fields_data;
|
||||
/** Populates a JxlColorEncoding from an ICC profile. */
|
||||
jpegxl_cms_set_fields_from_icc_func set_fields_from_icc;
|
||||
|
||||
/** CMS-specific data that will be passed to @ref init. */
|
||||
void* init_data;
|
||||
/** Prepares a colorspace transform as described in the documentation of @ref
|
||||
|
108
third_party/jpeg-xl/lib/include/jxl/encode.h
vendored
108
third_party/jpeg-xl/lib/include/jxl/encode.h
vendored
@ -18,6 +18,7 @@
|
||||
#include <jxl/jxl_export.h>
|
||||
#include <jxl/memory_manager.h>
|
||||
#include <jxl/parallel_runner.h>
|
||||
#include <jxl/stats.h>
|
||||
#include <jxl/version.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
@ -335,6 +336,19 @@ typedef enum {
|
||||
*/
|
||||
JXL_ENC_FRAME_SETTING_JPEG_COMPRESS_BOXES = 33,
|
||||
|
||||
/** Control what kind of buffering is used, when using chunked image frames.
|
||||
* 0 = buffers everything, basically the same as non-streamed code path
|
||||
(mainly for testing)
|
||||
* 1 = can buffer internal data (the tokens)
|
||||
* 2 = can buffer the output
|
||||
* 3 = minimize buffer usage: streamed input and chunked output, writing TOC
|
||||
last (will not work with progressive)
|
||||
|
||||
When the image dimensions is smaller than 2048 x 2048 all the options are the
|
||||
same. Using 1, 2 or 3 can result increasingly in less compression density.
|
||||
*/
|
||||
JXL_ENC_FRAME_SETTING_BUFFERING = 34,
|
||||
|
||||
/** Enum value not to be used as an option. This value is added to force the
|
||||
* C compiler to have the enum to take a known size.
|
||||
*/
|
||||
@ -630,6 +644,49 @@ JXL_EXPORT JxlEncoderStatus JxlEncoderAddImageFrame(
|
||||
const JxlEncoderFrameSettings* frame_settings,
|
||||
const JxlPixelFormat* pixel_format, const void* buffer, size_t size);
|
||||
|
||||
/**
|
||||
* TODO(firsching): add documentation
|
||||
*
|
||||
*/
|
||||
typedef void (*JxlEncoderOutputCallback)(void* run_opaque, size_t pos,
|
||||
size_t num_bytes);
|
||||
|
||||
/**
|
||||
* TODO(firsching): add documentation
|
||||
*
|
||||
*/
|
||||
JXL_EXPORT JxlEncoderStatus
|
||||
JxlEncoderSetOutputCallback(JxlEncoderOutputCallback callback);
|
||||
|
||||
/**
|
||||
* TODO(firsching): add documentation
|
||||
*
|
||||
* @param frame_settings
|
||||
* @return JXL_ENC_SUCCESS on success, JXL_ENC_ERROR on error
|
||||
*/
|
||||
JXL_EXPORT JxlEncoderStatus
|
||||
JxlEncoderChunkedImageFrameStart(const JxlEncoderFrameSettings* frame_settings);
|
||||
|
||||
/**
|
||||
* TODO(firsching): add documentation
|
||||
* We process exactly one 2048x2048 DC-group.
|
||||
*
|
||||
* @param frame_settings
|
||||
* @param x horizontal position of the top-left corner of the processed group.
|
||||
* Must be divisible by 2048.
|
||||
* @param y vertical position of the top-left corner of the processed group.
|
||||
* Must be divisible by 2048.
|
||||
* @param pixel_format for pixels. Object owned by the caller and its contents
|
||||
* are copied internally.
|
||||
* @param input_data the input buffer.
|
||||
* @param input_size size of the input data in bytes.
|
||||
* @return JXL_EXPORT
|
||||
*/
|
||||
JXL_EXPORT JxlEncoderStatus JxlEncoderChunkedImageFrameAddPart(
|
||||
const JxlEncoderFrameSettings* frame_settings, size_t x, size_t y,
|
||||
const JxlPixelFormat* pixel_format, const void* input_data,
|
||||
size_t input_size);
|
||||
|
||||
/**
|
||||
* Sets the buffer to read pixels from for an extra channel at a given index.
|
||||
* The index must be smaller than the num_extra_channels in the associated
|
||||
@ -1152,6 +1209,57 @@ JXL_EXPORT void JxlColorEncodingSetToLinearSRGB(
|
||||
*/
|
||||
JXL_EXPORT void JxlEncoderAllowExpertOptions(JxlEncoder* enc);
|
||||
|
||||
/**
|
||||
* Function type for @ref JxlEncoderSetDebugImageCallback.
|
||||
*
|
||||
* The callback may be called simultaneously by different threads when using a
|
||||
* threaded parallel runner, on different debug images.
|
||||
*
|
||||
* @param opaque optional user data, as given to @ref
|
||||
* JxlEncoderSetDebugImageCallback.
|
||||
* @param label label of debug image, can be used in filenames
|
||||
* @param xsize width of debug image
|
||||
* @param ysize height of debug image
|
||||
* @param color color encoding of debug image
|
||||
* @param pixels pixel data of debug image as big-endian 16-bit unsigned
|
||||
* samples. The memory is not owned by the user, and is only valid during the
|
||||
* time the callback is running.
|
||||
*/
|
||||
typedef void (*JxlDebugImageCallback)(void* opaque, const char* label,
|
||||
size_t xsize, size_t ysize,
|
||||
const JxlColorEncoding* color,
|
||||
const uint16_t* pixels);
|
||||
|
||||
/**
|
||||
* Sets the given debug image callback that will be used by the encoder to
|
||||
* output various debug images during encoding.
|
||||
*
|
||||
* This only has any effect if the encoder was compiled with the appropriate
|
||||
* debug build flags.
|
||||
*
|
||||
* @param frame_settings set of options and metadata for this frame. Also
|
||||
* includes reference to the encoder object.
|
||||
* @param callback used to return the debug image
|
||||
* @param opaque user supplied parameter to the image callback
|
||||
*/
|
||||
JXL_EXPORT void JxlEncoderSetDebugImageCallback(
|
||||
JxlEncoderFrameSettings* frame_settings, JxlDebugImageCallback callback,
|
||||
void* opaque);
|
||||
|
||||
/**
|
||||
* Sets the given stats object for gathering various statistics during encoding.
|
||||
*
|
||||
* This only has any effect if the encoder was compiled with the appropriate
|
||||
* debug build flags.
|
||||
*
|
||||
* @param frame_settings set of options and metadata for this frame. Also
|
||||
* includes reference to the encoder object.
|
||||
* @param stats object that can be used to query the gathered stats (created
|
||||
* by @ref JxlEncoderStatsCreate)
|
||||
*/
|
||||
JXL_EXPORT void JxlEncoderCollectStats(JxlEncoderFrameSettings* frame_settings,
|
||||
JxlEncoderStats* stats);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
}
|
||||
#endif
|
||||
|
103
third_party/jpeg-xl/lib/include/jxl/stats.h
vendored
Normal file
103
third_party/jpeg-xl/lib/include/jxl/stats.h
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
/** @addtogroup libjxl_encoder
|
||||
* @{
|
||||
* @file stats.h
|
||||
* @brief API to collect various statistics from JXL encoder.
|
||||
*/
|
||||
|
||||
#ifndef JXL_STATS_H_
|
||||
#define JXL_STATS_H_
|
||||
|
||||
#include <jxl/jxl_export.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Opaque structure that holds the encoder statistics.
|
||||
*
|
||||
* Allocated and initialized with JxlEncoderStatsCreate().
|
||||
* Cleaned up and deallocated with JxlEncoderStatsDestroy().
|
||||
*/
|
||||
typedef struct JxlEncoderStatsStruct JxlEncoderStats;
|
||||
|
||||
/**
|
||||
* Creates an instance of JxlEncoderStats and initializes it.
|
||||
*
|
||||
* @return pointer to initialized JxlEncoderStats instance
|
||||
*/
|
||||
JXL_EXPORT JxlEncoderStats* JxlEncoderStatsCreate();
|
||||
|
||||
/**
|
||||
* Deinitializes and frees JxlEncoderStats instance.
|
||||
*
|
||||
* @param stats instance to be cleaned up and deallocated. No-op if stats is
|
||||
* null pointer.
|
||||
*/
|
||||
JXL_EXPORT void JxlEncoderStatsDestroy(JxlEncoderStats* stats);
|
||||
|
||||
/** Data type for querying JxlEncoderStats object
|
||||
*/
|
||||
typedef enum {
|
||||
JXL_ENC_STAT_HEADER_BITS,
|
||||
JXL_ENC_STAT_TOC_BITS,
|
||||
JXL_ENC_STAT_DICTIONARY_BITS,
|
||||
JXL_ENC_STAT_SPLINES_BITS,
|
||||
JXL_ENC_STAT_NOISE_BITS,
|
||||
JXL_ENC_STAT_QUANT_BITS,
|
||||
JXL_ENC_STAT_MODULAR_TREE_BITS,
|
||||
JXL_ENC_STAT_MODULAR_GLOBAL_BITS,
|
||||
JXL_ENC_STAT_DC_BITS,
|
||||
JXL_ENC_STAT_MODULAR_DC_GROUP_BITS,
|
||||
JXL_ENC_STAT_CONTROL_FIELDS_BITS,
|
||||
JXL_ENC_STAT_COEF_ORDER_BITS,
|
||||
JXL_ENC_STAT_AC_HISTOGRAM_BITS,
|
||||
JXL_ENC_STAT_AC_BITS,
|
||||
JXL_ENC_STAT_MODULAR_AC_GROUP_BITS,
|
||||
JXL_ENC_STAT_NUM_SMALL_BLOCKS,
|
||||
JXL_ENC_STAT_NUM_DCT4X8_BLOCKS,
|
||||
JXL_ENC_STAT_NUM_AFV_BLOCKS,
|
||||
JXL_ENC_STAT_NUM_DCT8_BLOCKS,
|
||||
JXL_ENC_STAT_NUM_DCT8X32_BLOCKS,
|
||||
JXL_ENC_STAT_NUM_DCT16_BLOCKS,
|
||||
JXL_ENC_STAT_NUM_DCT16X32_BLOCKS,
|
||||
JXL_ENC_STAT_NUM_DCT32_BLOCKS,
|
||||
JXL_ENC_STAT_NUM_DCT32X64_BLOCKS,
|
||||
JXL_ENC_STAT_NUM_DCT64_BLOCKS,
|
||||
JXL_ENC_STAT_NUM_BUTTERAUGLI_ITERS,
|
||||
JXL_ENC_NUM_STATS,
|
||||
} JxlEncoderStatsKey;
|
||||
|
||||
/** Returns the value of the statistics corresponding the given key.
|
||||
*
|
||||
* @param stats object that was passed to the encoder with a
|
||||
* @ref JxlEncoderCollectStats function
|
||||
* @param key the particular statistics to query
|
||||
*
|
||||
* @return the value of the statistics
|
||||
*/
|
||||
JXL_EXPORT size_t JxlEncoderStatsGet(const JxlEncoderStats* stats,
|
||||
JxlEncoderStatsKey key);
|
||||
|
||||
/** Updates the values of the given stats object with that of an other.
|
||||
*
|
||||
* @param stats object whose values will be updated (usually added together)
|
||||
* @param other stats object whose values will be merged with stats
|
||||
*/
|
||||
JXL_EXPORT void JxlEncoderStatsMerge(JxlEncoderStats* stats,
|
||||
const JxlEncoderStats* other);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* JXL_STATS_H_ */
|
||||
|
||||
/** @}*/
|
58
third_party/jpeg-xl/lib/jpegli.cmake
vendored
58
third_party/jpeg-xl/lib/jpegli.cmake
vendored
@ -12,31 +12,67 @@ set(JPEGLI_INTERNAL_LIBS
|
||||
${ATOMICS_LIBRARIES}
|
||||
)
|
||||
|
||||
# JPEGLIB setup
|
||||
set(BITS_IN_JSAMPLE 8)
|
||||
set(MEM_SRCDST_SUPPORTED 1)
|
||||
|
||||
if(JPEGLI_LIBJPEG_LIBRARY_SOVERSION STREQUAL "62")
|
||||
set(JPEG_LIB_VERSION 62)
|
||||
elseif(JPEGLI_LIBJPEG_LIBRARY_SOVERSION STREQUAL "7")
|
||||
set(JPEG_LIB_VERSION 70)
|
||||
elseif(JPEGLI_LIBJPEG_LIBRARY_SOVERSION STREQUAL "8")
|
||||
set(JPEG_LIB_VERSION 80)
|
||||
endif()
|
||||
|
||||
configure_file(
|
||||
../third_party/libjpeg-turbo/jconfig.h.in include/jpegli/jconfig.h)
|
||||
configure_file(
|
||||
../third_party/libjpeg-turbo/jpeglib.h include/jpegli/jpeglib.h COPYONLY)
|
||||
configure_file(
|
||||
../third_party/libjpeg-turbo/jmorecfg.h include/jpegli/jmorecfg.h COPYONLY)
|
||||
|
||||
add_library(jpegli-static STATIC EXCLUDE_FROM_ALL "${JPEGXL_INTERNAL_JPEGLI_SOURCES}")
|
||||
target_compile_options(jpegli-static PRIVATE "${JPEGXL_INTERNAL_FLAGS}")
|
||||
target_compile_options(jpegli-static PUBLIC ${JPEGXL_COVERAGE_FLAGS})
|
||||
set_property(TARGET jpegli-static PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
target_include_directories(jpegli-static PUBLIC
|
||||
target_include_directories(jpegli-static PRIVATE
|
||||
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>"
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>"
|
||||
"${JXL_HWY_INCLUDE_DIRS}"
|
||||
)
|
||||
target_include_directories(jpegli-static PUBLIC "${JPEG_INCLUDE_DIRS}")
|
||||
target_include_directories(jpegli-static PUBLIC
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include/jpegli>"
|
||||
)
|
||||
target_link_libraries(jpegli-static PUBLIC ${JPEGLI_INTERNAL_LIBS})
|
||||
|
||||
#
|
||||
# Tests for jpegli-static
|
||||
#
|
||||
|
||||
if(BUILD_TESTING)
|
||||
find_package(JPEG)
|
||||
if(JPEG_FOUND AND BUILD_TESTING)
|
||||
# TODO(eustas): merge into jxl_tests.cmake?
|
||||
|
||||
add_library(jpegli_libjpeg_util-obj OBJECT
|
||||
${JPEGXL_INTERNAL_JPEGLI_LIBJPEG_HELPER_FILES}
|
||||
)
|
||||
target_include_directories(jpegli_libjpeg_util-obj PRIVATE
|
||||
"${PROJECT_SOURCE_DIR}"
|
||||
"${JPEG_INCLUDE_DIRS}"
|
||||
)
|
||||
target_compile_options(jpegli_libjpeg_util-obj PRIVATE
|
||||
"${JPEGXL_INTERNAL_FLAGS}" "${JPEGXL_COVERAGE_FLAGS}")
|
||||
|
||||
# Individual test binaries:
|
||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tests)
|
||||
foreach (TESTFILE IN LISTS JPEGXL_INTERNAL_JPEGLI_TESTS)
|
||||
# The TESTNAME is the name without the extension or directory.
|
||||
get_filename_component(TESTNAME ${TESTFILE} NAME_WE)
|
||||
add_executable(${TESTNAME} ${TESTFILE} ${JPEGXL_INTERNAL_JPEGLI_TESTLIB_FILES})
|
||||
add_executable(${TESTNAME} ${TESTFILE}
|
||||
$<TARGET_OBJECTS:jpegli_libjpeg_util-obj>
|
||||
${JPEGXL_INTERNAL_JPEGLI_TESTLIB_FILES}
|
||||
)
|
||||
target_compile_options(${TESTNAME} PRIVATE
|
||||
${JPEGXL_INTERNAL_FLAGS}
|
||||
# Add coverage flags to the test binary so code in the private headers of
|
||||
@ -45,7 +81,11 @@ foreach (TESTFILE IN LISTS JPEGXL_INTERNAL_JPEGLI_TESTS)
|
||||
)
|
||||
target_compile_definitions(${TESTNAME} PRIVATE
|
||||
-DTEST_DATA_PATH="${JPEGXL_TEST_DATA_PATH}")
|
||||
target_include_directories(${TESTNAME} PRIVATE "${PROJECT_SOURCE_DIR}")
|
||||
target_include_directories(${TESTNAME} PRIVATE
|
||||
"${PROJECT_SOURCE_DIR}"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/include"
|
||||
)
|
||||
target_link_libraries(${TESTNAME}
|
||||
hwy
|
||||
jpegli-static
|
||||
@ -73,7 +113,10 @@ add_library(jpegli-libjpeg-obj OBJECT "${JPEGXL_INTERNAL_JPEGLI_WRAPPER_SOURCES}
|
||||
target_compile_options(jpegli-libjpeg-obj PRIVATE ${JPEGXL_INTERNAL_FLAGS})
|
||||
target_compile_options(jpegli-libjpeg-obj PUBLIC ${JPEGXL_COVERAGE_FLAGS})
|
||||
set_property(TARGET jpegli-libjpeg-obj PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
target_include_directories(jpegli-libjpeg-obj PUBLIC "${PROJECT_SOURCE_DIR}")
|
||||
target_include_directories(jpegli-libjpeg-obj PRIVATE
|
||||
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>"
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include/jpegli>"
|
||||
)
|
||||
target_compile_definitions(jpegli-libjpeg-obj PUBLIC
|
||||
${JPEGLI_LIBJPEG_OBJ_COMPILE_DEFINITIONS}
|
||||
)
|
||||
@ -101,6 +144,9 @@ if (JPEGXL_INSTALL_JPEGLI_LIBJPEG)
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
install(
|
||||
DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include/jpegli/"
|
||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
endif()
|
||||
|
||||
# This hides the default visibility symbols from static libraries bundled into
|
||||
|
@ -6,11 +6,7 @@
|
||||
#ifndef LIB_JPEGLI_ADAPTIVE_QUANTIZATION_H_
|
||||
#define LIB_JPEGLI_ADAPTIVE_QUANTIZATION_H_
|
||||
|
||||
/* clang-format off */
|
||||
#include <stdio.h>
|
||||
#include <jpeglib.h>
|
||||
#include <stddef.h>
|
||||
/* clang-format on */
|
||||
#include "lib/jpegli/common.h"
|
||||
|
||||
namespace jpegli {
|
||||
|
||||
|
5
third_party/jpeg-xl/lib/jpegli/bit_writer.h
vendored
5
third_party/jpeg-xl/lib/jpegli/bit_writer.h
vendored
@ -6,13 +6,10 @@
|
||||
#ifndef LIB_JPEGLI_BIT_WRITER_H_
|
||||
#define LIB_JPEGLI_BIT_WRITER_H_
|
||||
|
||||
/* clang-format off */
|
||||
#include <stdio.h>
|
||||
#include <jpeglib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
/* clang-format on */
|
||||
|
||||
#include "lib/jpegli/common.h"
|
||||
#include "lib/jxl/base/byte_order.h"
|
||||
#include "lib/jxl/base/compiler_specific.h"
|
||||
|
||||
|
@ -6,10 +6,7 @@
|
||||
#ifndef LIB_JPEGLI_COLOR_QUANTIZE_H_
|
||||
#define LIB_JPEGLI_COLOR_QUANTIZE_H_
|
||||
|
||||
/* clang-format off */
|
||||
#include <stdio.h>
|
||||
#include <jpeglib.h>
|
||||
/* clang-format on */
|
||||
#include "lib/jpegli/common.h"
|
||||
|
||||
namespace jpegli {
|
||||
|
||||
|
@ -6,11 +6,7 @@
|
||||
#ifndef LIB_JPEGLI_COLOR_TRANSFORM_H_
|
||||
#define LIB_JPEGLI_COLOR_TRANSFORM_H_
|
||||
|
||||
/* clang-format off */
|
||||
#include <stdio.h>
|
||||
#include <jpeglib.h>
|
||||
/* clang-format on */
|
||||
|
||||
#include "lib/jpegli/common.h"
|
||||
#include "lib/jxl/base/compiler_specific.h"
|
||||
|
||||
namespace jpegli {
|
||||
|
23
third_party/jpeg-xl/lib/jpegli/common.h
vendored
23
third_party/jpeg-xl/lib/jpegli/common.h
vendored
@ -25,6 +25,8 @@
|
||||
#include <jpeglib.h>
|
||||
/* clang-format on */
|
||||
|
||||
#include "lib/jpegli/types.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -39,27 +41,6 @@ JQUANT_TBL* jpegli_alloc_quant_table(j_common_ptr cinfo);
|
||||
|
||||
JHUFF_TBL* jpegli_alloc_huff_table(j_common_ptr cinfo);
|
||||
|
||||
//
|
||||
// New API structs and functions that are not available in libjpeg
|
||||
//
|
||||
// NOTE: This part of the API is still experimental and will probably change in
|
||||
// the future.
|
||||
//
|
||||
|
||||
typedef enum {
|
||||
JPEGLI_TYPE_FLOAT = 0,
|
||||
JPEGLI_TYPE_UINT8 = 2,
|
||||
JPEGLI_TYPE_UINT16 = 3,
|
||||
} JpegliDataType;
|
||||
|
||||
typedef enum {
|
||||
JPEGLI_NATIVE_ENDIAN = 0,
|
||||
JPEGLI_LITTLE_ENDIAN = 1,
|
||||
JPEGLI_BIG_ENDIAN = 2,
|
||||
} JpegliEndianness;
|
||||
|
||||
int jpegli_bytes_per_sample(JpegliDataType data_type);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
5
third_party/jpeg-xl/lib/jpegli/decode.h
vendored
5
third_party/jpeg-xl/lib/jpegli/decode.h
vendored
@ -20,11 +20,6 @@
|
||||
#ifndef LIB_JPEGLI_DECODE_H_
|
||||
#define LIB_JPEGLI_DECODE_H_
|
||||
|
||||
/* clang-format off */
|
||||
#include <stdio.h>
|
||||
#include <jpeglib.h>
|
||||
/* clang-format on */
|
||||
|
||||
#include "lib/jpegli/common.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
|
@ -269,7 +269,8 @@ void TestAPINonBuffered(const CompressParams& jparams,
|
||||
cinfo->scale_denom = 2;
|
||||
}
|
||||
jpegli_calc_output_dimensions(cinfo);
|
||||
SetDecompressParams(dparams, cinfo, /*is_jpegli=*/true);
|
||||
SetDecompressParams(dparams, cinfo);
|
||||
jpegli_set_output_format(cinfo, dparams.data_type, dparams.endianness);
|
||||
VerifyHeader(jparams, cinfo);
|
||||
jpegli_calc_output_dimensions(cinfo);
|
||||
EXPECT_LE(expected_output.xsize, cinfo->output_width);
|
||||
@ -294,7 +295,8 @@ void TestAPIBuffered(const CompressParams& jparams,
|
||||
EXPECT_EQ(JPEG_REACHED_SOS,
|
||||
jpegli_read_header(cinfo, /*require_image=*/TRUE));
|
||||
cinfo->buffered_image = TRUE;
|
||||
SetDecompressParams(dparams, cinfo, /*is_jpegli=*/true);
|
||||
SetDecompressParams(dparams, cinfo);
|
||||
jpegli_set_output_format(cinfo, dparams.data_type, dparams.endianness);
|
||||
VerifyHeader(jparams, cinfo);
|
||||
EXPECT_TRUE(jpegli_start_decompress(cinfo));
|
||||
// start decompress should not read the whole input in buffered image mode
|
||||
@ -312,8 +314,7 @@ void TestAPIBuffered(const CompressParams& jparams,
|
||||
if (result == JPEG_REACHED_SOS) ++sos_marker_cnt;
|
||||
continue;
|
||||
}
|
||||
SetScanDecompressParams(dparams, cinfo, cinfo->input_scan_number,
|
||||
/*is_jpegli=*/true);
|
||||
SetScanDecompressParams(dparams, cinfo, cinfo->input_scan_number);
|
||||
EXPECT_TRUE(jpegli_start_output(cinfo, cinfo->input_scan_number));
|
||||
// start output sets output_scan_number, but does not change
|
||||
// input_scan_number
|
||||
@ -924,7 +925,7 @@ std::vector<TestConfig> GenerateTests(bool buffered) {
|
||||
}
|
||||
}
|
||||
// Tests for progressive levels.
|
||||
for (int p = 0; p < 3 + kNumTestScripts; ++p) {
|
||||
for (int p = 0; p < 3 + NumTestScanScripts(); ++p) {
|
||||
TestConfig config;
|
||||
config.jparams.progressive_mode = p;
|
||||
all_tests.push_back(config);
|
||||
@ -1245,7 +1246,7 @@ std::ostream& operator<<(std::ostream& os, const DecompressParams& dparams) {
|
||||
}
|
||||
os << IOMethodName(dparams.data_type, dparams.endianness);
|
||||
if (dparams.set_out_color_space) {
|
||||
os << "OutColor" << ColorSpaceName(dparams.out_color_space);
|
||||
os << "OutColor" << ColorSpaceName((J_COLOR_SPACE)dparams.out_color_space);
|
||||
}
|
||||
if (dparams.crop_output) {
|
||||
os << "Crop";
|
||||
@ -1265,7 +1266,7 @@ std::ostream& operator<<(std::ostream& os, const DecompressParams& dparams) {
|
||||
if (i > 0) os << "_";
|
||||
const auto& sparam = dparams.scan_params[i];
|
||||
os << QuantMode(sparam.color_quant_mode);
|
||||
os << DitherMode(sparam.dither_mode) << "Dither";
|
||||
os << DitherMode((J_DITHER_MODE)sparam.dither_mode) << "Dither";
|
||||
}
|
||||
}
|
||||
if (dparams.skip_scans) {
|
||||
|
@ -6,11 +6,9 @@
|
||||
#ifndef LIB_JPEGLI_DECODE_MARKER_H_
|
||||
#define LIB_JPEGLI_DECODE_MARKER_H_
|
||||
|
||||
/* clang-format off */
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <jpeglib.h>
|
||||
/* clang-format on */
|
||||
|
||||
#include "lib/jpegli/common.h"
|
||||
|
||||
namespace jpegli {
|
||||
|
||||
@ -22,7 +20,7 @@ namespace jpegli {
|
||||
// Return value is one of:
|
||||
// * JPEG_SUSPENDED, if the current input buffer ends before the next SOS or
|
||||
// EOI marker. Input buffer refill is handled by the caller;
|
||||
// * JPEG_REACHED_SOS, if the the next SOS marker is found;
|
||||
// * JPEG_REACHED_SOS, if the next SOS marker is found;
|
||||
// * JPEG_REACHED_EOR, if the end of the input is found.
|
||||
int ProcessMarkers(j_decompress_ptr cinfo, const uint8_t* const data,
|
||||
const size_t len, size_t* pos);
|
||||
|
6
third_party/jpeg-xl/lib/jpegli/decode_scan.h
vendored
6
third_party/jpeg-xl/lib/jpegli/decode_scan.h
vendored
@ -6,11 +6,9 @@
|
||||
#ifndef LIB_JPEGLI_DECODE_SCAN_H_
|
||||
#define LIB_JPEGLI_DECODE_SCAN_H_
|
||||
|
||||
/* clang-format off */
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <jpeglib.h>
|
||||
/* clang-format on */
|
||||
|
||||
#include "lib/jpegli/common.h"
|
||||
|
||||
namespace jpegli {
|
||||
|
||||
|
5
third_party/jpeg-xl/lib/jpegli/downsample.h
vendored
5
third_party/jpeg-xl/lib/jpegli/downsample.h
vendored
@ -6,10 +6,7 @@
|
||||
#ifndef LIB_JPEGLI_DOWNSAMPLE_H_
|
||||
#define LIB_JPEGLI_DOWNSAMPLE_H_
|
||||
|
||||
/* clang-format off */
|
||||
#include <stdio.h>
|
||||
#include <jpeglib.h>
|
||||
/* clang-format on */
|
||||
#include "lib/jpegli/common.h"
|
||||
|
||||
namespace jpegli {
|
||||
|
||||
|
5
third_party/jpeg-xl/lib/jpegli/encode.h
vendored
5
third_party/jpeg-xl/lib/jpegli/encode.h
vendored
@ -20,11 +20,6 @@
|
||||
#ifndef LIB_JPEGLI_ENCODE_H_
|
||||
#define LIB_JPEGLI_ENCODE_H_
|
||||
|
||||
/* clang-format off */
|
||||
#include <stdio.h>
|
||||
#include <jpeglib.h>
|
||||
/* clang-format on */
|
||||
|
||||
#include "lib/jpegli/common.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
|
100
third_party/jpeg-xl/lib/jpegli/encode_api_test.cc
vendored
100
third_party/jpeg-xl/lib/jpegli/encode_api_test.cc
vendored
@ -134,25 +134,13 @@ TEST(EncodeAPITest, ReuseCinfoSameMemOutput) {
|
||||
EXPECT_TRUE(try_catch_block());
|
||||
jpegli_destroy_compress(&cinfo);
|
||||
}
|
||||
std::vector<TestImage> all_outputs(all_configs.size());
|
||||
{
|
||||
jpeg_decompress_struct cinfo = {};
|
||||
const auto try_catch_block = [&]() -> bool {
|
||||
ERROR_HANDLER_SETUP(jpegli);
|
||||
jpeg_create_decompress(&cinfo);
|
||||
jpeg_mem_src(&cinfo, buffer, buffer_size);
|
||||
for (size_t i = 0; i < all_configs.size(); ++i) {
|
||||
DecodeWithLibjpeg(all_configs[i].jparams, DecompressParams(), &cinfo,
|
||||
&all_outputs[i]);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
EXPECT_TRUE(try_catch_block());
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
}
|
||||
size_t pos = 0;
|
||||
for (size_t i = 0; i < all_configs.size(); ++i) {
|
||||
VerifyOutputImage(all_configs[i].input, all_outputs[i],
|
||||
all_configs[i].max_dist);
|
||||
TestImage output;
|
||||
pos +=
|
||||
DecodeWithLibjpeg(all_configs[i].jparams, DecompressParams(), nullptr,
|
||||
0, buffer + pos, buffer_size - pos, &output);
|
||||
VerifyOutputImage(all_configs[i].input, output, all_configs[i].max_dist);
|
||||
}
|
||||
if (buffer) free(buffer);
|
||||
}
|
||||
@ -175,28 +163,19 @@ TEST(EncodeAPITest, ReuseCinfoSameStdOutput) {
|
||||
EXPECT_TRUE(try_catch_block());
|
||||
jpegli_destroy_compress(&cinfo);
|
||||
}
|
||||
size_t total_size = ftell(tmpf);
|
||||
rewind(tmpf);
|
||||
std::vector<TestImage> all_outputs(all_configs.size());
|
||||
{
|
||||
jpeg_decompress_struct cinfo = {};
|
||||
const auto try_catch_block = [&]() -> bool {
|
||||
ERROR_HANDLER_SETUP(jpegli);
|
||||
jpeg_create_decompress(&cinfo);
|
||||
jpeg_stdio_src(&cinfo, tmpf);
|
||||
for (size_t i = 0; i < all_configs.size(); ++i) {
|
||||
DecodeWithLibjpeg(all_configs[i].jparams, DecompressParams(), &cinfo,
|
||||
&all_outputs[i]);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
EXPECT_TRUE(try_catch_block());
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
}
|
||||
for (size_t i = 0; i < all_configs.size(); ++i) {
|
||||
VerifyOutputImage(all_configs[i].input, all_outputs[i],
|
||||
all_configs[i].max_dist);
|
||||
}
|
||||
std::vector<uint8_t> compressed(total_size);
|
||||
JXL_CHECK(total_size == fread(&compressed[0], 1, total_size, tmpf));
|
||||
fclose(tmpf);
|
||||
size_t pos = 0;
|
||||
for (size_t i = 0; i < all_configs.size(); ++i) {
|
||||
TestImage output;
|
||||
pos += DecodeWithLibjpeg(all_configs[i].jparams, DecompressParams(),
|
||||
nullptr, 0, &compressed[pos],
|
||||
compressed.size() - pos, &output);
|
||||
VerifyOutputImage(all_configs[i].input, output, all_configs[i].max_dist);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EncodeAPITest, ReuseCinfoChangeParams) {
|
||||
@ -298,32 +277,15 @@ TEST(EncodeAPITest, AbbreviatedStreams) {
|
||||
EXPECT_LT(data_stream_size, 50);
|
||||
jpegli_destroy_compress(&cinfo);
|
||||
}
|
||||
{
|
||||
jpeg_decompress_struct cinfo = {};
|
||||
const auto try_catch_block = [&]() -> bool {
|
||||
ERROR_HANDLER_SETUP(jpeg);
|
||||
jpeg_create_decompress(&cinfo);
|
||||
jpeg_mem_src(&cinfo, table_stream, table_stream_size);
|
||||
jpeg_read_header(&cinfo, FALSE);
|
||||
jpeg_mem_src(&cinfo, data_stream, data_stream_size);
|
||||
jpeg_read_header(&cinfo, TRUE);
|
||||
EXPECT_EQ(1, cinfo.image_width);
|
||||
EXPECT_EQ(1, cinfo.image_height);
|
||||
EXPECT_EQ(3, cinfo.num_components);
|
||||
jpeg_start_decompress(&cinfo);
|
||||
JSAMPLE image[3] = {0};
|
||||
JSAMPROW row[] = {image};
|
||||
jpeg_read_scanlines(&cinfo, row, 1);
|
||||
jxl::msan::UnpoisonMemory(image, 3);
|
||||
EXPECT_EQ(0, image[0]);
|
||||
EXPECT_EQ(0, image[1]);
|
||||
EXPECT_EQ(0, image[2]);
|
||||
jpeg_finish_decompress(&cinfo);
|
||||
return true;
|
||||
};
|
||||
EXPECT_TRUE(try_catch_block());
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
}
|
||||
TestImage output;
|
||||
DecodeWithLibjpeg(CompressParams(), DecompressParams(), table_stream,
|
||||
table_stream_size, data_stream, data_stream_size, &output);
|
||||
EXPECT_EQ(1, output.xsize);
|
||||
EXPECT_EQ(1, output.ysize);
|
||||
EXPECT_EQ(3, output.components);
|
||||
EXPECT_EQ(0, output.pixels[0]);
|
||||
EXPECT_EQ(0, output.pixels[1]);
|
||||
EXPECT_EQ(0, output.pixels[2]);
|
||||
if (table_stream) free(table_stream);
|
||||
if (data_stream) free(data_stream);
|
||||
}
|
||||
@ -398,8 +360,8 @@ std::vector<TestConfig> GenerateTests() {
|
||||
if (!progr) {
|
||||
config.jparams.optimize_coding = optimize;
|
||||
}
|
||||
const float kMaxBpp[4] = {1.55, 1.45, 1.45, 1.32};
|
||||
const float kMaxDist[4] = {1.95, 2.1, 2.1, 2.0};
|
||||
const float kMaxBpp[4] = {1.55, 1.4, 1.4, 1.32};
|
||||
const float kMaxDist[4] = {1.95, 2.2, 2.2, 2.0};
|
||||
const int idx = v_samp * 2 + h_samp - 3;
|
||||
config.max_bpp =
|
||||
kMaxBpp[idx] * (optimize ? 0.97 : 1.0) * (progr ? 0.97 : 1.0);
|
||||
@ -490,7 +452,7 @@ std::vector<TestConfig> GenerateTests() {
|
||||
all_tests.push_back(config);
|
||||
}
|
||||
}
|
||||
for (int p = 0; p < 3 + kNumTestScripts; ++p) {
|
||||
for (int p = 0; p < 3 + NumTestScanScripts(); ++p) {
|
||||
for (int samp : {1, 2}) {
|
||||
for (int quality : {100, 90, 1}) {
|
||||
for (int r : {0, 1024, 1}) {
|
||||
@ -508,11 +470,11 @@ std::vector<TestConfig> GenerateTests() {
|
||||
config.jparams.v_sampling = {samp, 1, 1};
|
||||
config.jparams.quality = quality;
|
||||
config.jparams.restart_interval = r;
|
||||
config.max_bpp = quality == 100 ? 8.0 : 2.0;
|
||||
config.max_bpp = quality == 100 ? 8.0 : 1.9;
|
||||
if (r == 1) {
|
||||
config.max_bpp += 10.0;
|
||||
}
|
||||
config.max_dist = quality == 1 ? 20.0 : 2.0;
|
||||
config.max_dist = quality == 1 ? 20.0 : 2.1;
|
||||
all_tests.push_back(config);
|
||||
}
|
||||
}
|
||||
|
@ -6,13 +6,10 @@
|
||||
#ifndef LIB_JPEGLI_ENCODE_INTERNAL_H_
|
||||
#define LIB_JPEGLI_ENCODE_INTERNAL_H_
|
||||
|
||||
/* clang-format off */
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <jpeglib.h>
|
||||
/* clang-format on */
|
||||
|
||||
#include "lib/jpegli/bit_writer.h"
|
||||
#include "lib/jpegli/common.h"
|
||||
#include "lib/jpegli/common_internal.h"
|
||||
#include "lib/jpegli/encode.h"
|
||||
|
||||
|
@ -30,6 +30,78 @@ static const int kStreamingModeCoefficients = 0;
|
||||
static const int kStreamingModeTokens = 1;
|
||||
static const int kStreamingModeBits = 2;
|
||||
|
||||
namespace {
|
||||
void ZigZagShuffle(int32_t* JXL_RESTRICT block) {
|
||||
// TODO(szabadka) SIMDify this.
|
||||
int32_t tmp[DCTSIZE2];
|
||||
tmp[0] = block[0];
|
||||
tmp[1] = block[1];
|
||||
tmp[2] = block[8];
|
||||
tmp[3] = block[16];
|
||||
tmp[4] = block[9];
|
||||
tmp[5] = block[2];
|
||||
tmp[6] = block[3];
|
||||
tmp[7] = block[10];
|
||||
tmp[8] = block[17];
|
||||
tmp[9] = block[24];
|
||||
tmp[10] = block[32];
|
||||
tmp[11] = block[25];
|
||||
tmp[12] = block[18];
|
||||
tmp[13] = block[11];
|
||||
tmp[14] = block[4];
|
||||
tmp[15] = block[5];
|
||||
tmp[16] = block[12];
|
||||
tmp[17] = block[19];
|
||||
tmp[18] = block[26];
|
||||
tmp[19] = block[33];
|
||||
tmp[20] = block[40];
|
||||
tmp[21] = block[48];
|
||||
tmp[22] = block[41];
|
||||
tmp[23] = block[34];
|
||||
tmp[24] = block[27];
|
||||
tmp[25] = block[20];
|
||||
tmp[26] = block[13];
|
||||
tmp[27] = block[6];
|
||||
tmp[28] = block[7];
|
||||
tmp[29] = block[14];
|
||||
tmp[30] = block[21];
|
||||
tmp[31] = block[28];
|
||||
tmp[32] = block[35];
|
||||
tmp[33] = block[42];
|
||||
tmp[34] = block[49];
|
||||
tmp[35] = block[56];
|
||||
tmp[36] = block[57];
|
||||
tmp[37] = block[50];
|
||||
tmp[38] = block[43];
|
||||
tmp[39] = block[36];
|
||||
tmp[40] = block[29];
|
||||
tmp[41] = block[22];
|
||||
tmp[42] = block[15];
|
||||
tmp[43] = block[23];
|
||||
tmp[44] = block[30];
|
||||
tmp[45] = block[37];
|
||||
tmp[46] = block[44];
|
||||
tmp[47] = block[51];
|
||||
tmp[48] = block[58];
|
||||
tmp[49] = block[59];
|
||||
tmp[50] = block[52];
|
||||
tmp[51] = block[45];
|
||||
tmp[52] = block[38];
|
||||
tmp[53] = block[31];
|
||||
tmp[54] = block[39];
|
||||
tmp[55] = block[46];
|
||||
tmp[56] = block[53];
|
||||
tmp[57] = block[60];
|
||||
tmp[58] = block[61];
|
||||
tmp[59] = block[54];
|
||||
tmp[60] = block[47];
|
||||
tmp[61] = block[55];
|
||||
tmp[62] = block[62];
|
||||
tmp[63] = block[63];
|
||||
memcpy(block, tmp, DCTSIZE2 * sizeof(tmp[0]));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
template <int kMode>
|
||||
void ProcessiMCURow(j_compress_ptr cinfo) {
|
||||
jpeg_comp_master* m = cinfo->master;
|
||||
|
@ -37,76 +37,6 @@ using hwy::HWY_NAMESPACE::Sub;
|
||||
using DI = HWY_FULL(int32_t);
|
||||
constexpr DI di;
|
||||
|
||||
void ZigZagShuffle(int32_t* JXL_RESTRICT block) {
|
||||
// TODO(szabadka) SIMDify this.
|
||||
int32_t tmp[DCTSIZE2];
|
||||
tmp[0] = block[0];
|
||||
tmp[1] = block[1];
|
||||
tmp[2] = block[8];
|
||||
tmp[3] = block[16];
|
||||
tmp[4] = block[9];
|
||||
tmp[5] = block[2];
|
||||
tmp[6] = block[3];
|
||||
tmp[7] = block[10];
|
||||
tmp[8] = block[17];
|
||||
tmp[9] = block[24];
|
||||
tmp[10] = block[32];
|
||||
tmp[11] = block[25];
|
||||
tmp[12] = block[18];
|
||||
tmp[13] = block[11];
|
||||
tmp[14] = block[4];
|
||||
tmp[15] = block[5];
|
||||
tmp[16] = block[12];
|
||||
tmp[17] = block[19];
|
||||
tmp[18] = block[26];
|
||||
tmp[19] = block[33];
|
||||
tmp[20] = block[40];
|
||||
tmp[21] = block[48];
|
||||
tmp[22] = block[41];
|
||||
tmp[23] = block[34];
|
||||
tmp[24] = block[27];
|
||||
tmp[25] = block[20];
|
||||
tmp[26] = block[13];
|
||||
tmp[27] = block[6];
|
||||
tmp[28] = block[7];
|
||||
tmp[29] = block[14];
|
||||
tmp[30] = block[21];
|
||||
tmp[31] = block[28];
|
||||
tmp[32] = block[35];
|
||||
tmp[33] = block[42];
|
||||
tmp[34] = block[49];
|
||||
tmp[35] = block[56];
|
||||
tmp[36] = block[57];
|
||||
tmp[37] = block[50];
|
||||
tmp[38] = block[43];
|
||||
tmp[39] = block[36];
|
||||
tmp[40] = block[29];
|
||||
tmp[41] = block[22];
|
||||
tmp[42] = block[15];
|
||||
tmp[43] = block[23];
|
||||
tmp[44] = block[30];
|
||||
tmp[45] = block[37];
|
||||
tmp[46] = block[44];
|
||||
tmp[47] = block[51];
|
||||
tmp[48] = block[58];
|
||||
tmp[49] = block[59];
|
||||
tmp[50] = block[52];
|
||||
tmp[51] = block[45];
|
||||
tmp[52] = block[38];
|
||||
tmp[53] = block[31];
|
||||
tmp[54] = block[39];
|
||||
tmp[55] = block[46];
|
||||
tmp[56] = block[53];
|
||||
tmp[57] = block[60];
|
||||
tmp[58] = block[61];
|
||||
tmp[59] = block[54];
|
||||
tmp[60] = block[47];
|
||||
tmp[61] = block[55];
|
||||
tmp[62] = block[62];
|
||||
tmp[63] = block[63];
|
||||
memcpy(block, tmp, DCTSIZE2 * sizeof(tmp[0]));
|
||||
}
|
||||
|
||||
template <typename DI, class V>
|
||||
JXL_INLINE V NumBits(DI di, const V x) {
|
||||
// TODO(szabadka) Add faster implementations for some specific architectures.
|
||||
|
@ -103,7 +103,10 @@ void TokenizeACProgressiveScan(j_compress_ptr cinfo, int scan_index,
|
||||
JBLOCKARRAY ba = (*cinfo->mem->access_virt_barray)(
|
||||
reinterpret_cast<j_common_ptr>(cinfo), m->coeff_buffers[comp_idx], by,
|
||||
1, false);
|
||||
int max_tokens_per_row = comp->width_in_blocks * (Se - Ss + 1);
|
||||
// Each coefficient can appear in at most one token, but we have to reserve
|
||||
// one extra EOBrun token that was rolled over from the previous block-row
|
||||
// and has to be flushed at the end.
|
||||
int max_tokens_per_row = 1 + comp->width_in_blocks * (Se - Ss + 1);
|
||||
if (ta->num_tokens + max_tokens_per_row > m->num_tokens) {
|
||||
if (ta->tokens) {
|
||||
m->total_num_tokens += ta->num_tokens;
|
||||
@ -638,7 +641,7 @@ void CopyHuffmanTable(j_compress_ptr cinfo, int index, bool is_dc,
|
||||
if (index < 0 || index >= NUM_HUFF_TBLS) {
|
||||
JPEGLI_ERROR("Invalid %s Huffman table index %d", type, index);
|
||||
}
|
||||
// Check if we have alreay copied this Huffman table.
|
||||
// Check if we have already copied this Huffman table.
|
||||
int slot_idx = index + (is_dc ? 0 : NUM_HUFF_TBLS);
|
||||
if (inv_slot_map[slot_idx] != -1) {
|
||||
return;
|
||||
|
@ -6,10 +6,7 @@
|
||||
#ifndef LIB_JPEGLI_ENTROPY_CODING_H_
|
||||
#define LIB_JPEGLI_ENTROPY_CODING_H_
|
||||
|
||||
/* clang-format off */
|
||||
#include <stdio.h>
|
||||
#include <jpeglib.h>
|
||||
/* clang-format on */
|
||||
#include "lib/jpegli/common.h"
|
||||
|
||||
namespace jpegli {
|
||||
|
||||
|
8
third_party/jpeg-xl/lib/jpegli/error.h
vendored
8
third_party/jpeg-xl/lib/jpegli/error.h
vendored
@ -6,12 +6,10 @@
|
||||
#ifndef LIB_JPEGLI_ERROR_H_
|
||||
#define LIB_JPEGLI_ERROR_H_
|
||||
|
||||
/* clang-format off */
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <jpeglib.h>
|
||||
#include <stdarg.h>
|
||||
/* clang-format on */
|
||||
#include <stdint.h>
|
||||
|
||||
#include "lib/jpegli/common.h"
|
||||
|
||||
namespace jpegli {
|
||||
|
||||
|
@ -36,27 +36,13 @@ TEST(EncoderErrorHandlingTest, MinimalSuccess) {
|
||||
EXPECT_TRUE(try_catch_block());
|
||||
jpegli_destroy_compress(&cinfo);
|
||||
}
|
||||
{
|
||||
jpeg_decompress_struct cinfo = {};
|
||||
const auto try_catch_block = [&]() -> bool {
|
||||
ERROR_HANDLER_SETUP(jpeg);
|
||||
jpeg_create_decompress(&cinfo);
|
||||
jpeg_mem_src(&cinfo, buffer, buffer_size);
|
||||
jpeg_read_header(&cinfo, TRUE);
|
||||
EXPECT_EQ(1, cinfo.image_width);
|
||||
EXPECT_EQ(1, cinfo.image_height);
|
||||
jpeg_start_decompress(&cinfo);
|
||||
JSAMPLE image[1];
|
||||
JSAMPROW row[] = {image};
|
||||
jpeg_read_scanlines(&cinfo, row, 1);
|
||||
jxl::msan::UnpoisonMemory(image, 1);
|
||||
EXPECT_EQ(0, image[0]);
|
||||
jpeg_finish_decompress(&cinfo);
|
||||
return true;
|
||||
};
|
||||
EXPECT_TRUE(try_catch_block());
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
}
|
||||
TestImage output;
|
||||
DecodeWithLibjpeg(CompressParams(), DecompressParams(), nullptr, 0, buffer,
|
||||
buffer_size, &output);
|
||||
EXPECT_EQ(1, output.xsize);
|
||||
EXPECT_EQ(1, output.ysize);
|
||||
EXPECT_EQ(1, output.components);
|
||||
EXPECT_EQ(0, output.pixels[0]);
|
||||
if (buffer) free(buffer);
|
||||
}
|
||||
|
||||
|
8
third_party/jpeg-xl/lib/jpegli/idct.h
vendored
8
third_party/jpeg-xl/lib/jpegli/idct.h
vendored
@ -6,13 +6,7 @@
|
||||
#ifndef LIB_JPEGLI_IDCT_H_
|
||||
#define LIB_JPEGLI_IDCT_H_
|
||||
|
||||
/* clang-format off */
|
||||
#include <stdio.h>
|
||||
#include <jpeglib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
/* clang-format on */
|
||||
|
||||
#include "lib/jpegli/common.h"
|
||||
#include "lib/jxl/base/compiler_specific.h"
|
||||
|
||||
namespace jpegli {
|
||||
|
5
third_party/jpeg-xl/lib/jpegli/input.h
vendored
5
third_party/jpeg-xl/lib/jpegli/input.h
vendored
@ -6,10 +6,7 @@
|
||||
#ifndef LIB_JPEGLI_INPUT_H_
|
||||
#define LIB_JPEGLI_INPUT_H_
|
||||
|
||||
/* clang-format off */
|
||||
#include <stdio.h>
|
||||
#include <jpeglib.h>
|
||||
/* clang-format on */
|
||||
#include "lib/jpegli/common.h"
|
||||
|
||||
namespace jpegli {
|
||||
|
||||
|
@ -243,7 +243,8 @@ TEST_P(InputSuspensionTestParam, InputOutputLockStepNonBuffered) {
|
||||
while (jpegli_read_header(&cinfo, TRUE) == JPEG_SUSPENDED) {
|
||||
JXL_CHECK(src.LoadNextChunk());
|
||||
}
|
||||
SetDecompressParams(dparams, &cinfo, true);
|
||||
SetDecompressParams(dparams, &cinfo);
|
||||
jpegli_set_output_format(&cinfo, dparams.data_type, dparams.endianness);
|
||||
if (config.jparams.add_marker) {
|
||||
EXPECT_EQ(num_markers_seen, kMarkerSequenceLen);
|
||||
EXPECT_EQ(0, memcmp(markers_seen, kMarkerSequence, num_markers_seen));
|
||||
@ -299,7 +300,8 @@ TEST_P(InputSuspensionTestParam, InputOutputLockStepBuffered) {
|
||||
while (jpegli_read_header(&cinfo, TRUE) == JPEG_SUSPENDED) {
|
||||
JXL_CHECK(src.LoadNextChunk());
|
||||
}
|
||||
SetDecompressParams(dparams, &cinfo, true);
|
||||
SetDecompressParams(dparams, &cinfo);
|
||||
jpegli_set_output_format(&cinfo, dparams.data_type, dparams.endianness);
|
||||
|
||||
cinfo.buffered_image = TRUE;
|
||||
cinfo.raw_data_out = dparams.output_mode == RAW_DATA;
|
||||
|
261
third_party/jpeg-xl/lib/jpegli/libjpeg_test_util.cc
vendored
Normal file
261
third_party/jpeg-xl/lib/jpegli/libjpeg_test_util.cc
vendored
Normal file
@ -0,0 +1,261 @@
|
||||
// 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.
|
||||
|
||||
#include "lib/jpegli/libjpeg_test_util.h"
|
||||
|
||||
/* clang-format off */
|
||||
#include <stdio.h>
|
||||
#include <jpeglib.h>
|
||||
#include <setjmp.h>
|
||||
/* clang-format on */
|
||||
|
||||
#include "lib/jxl/sanitizers.h"
|
||||
|
||||
namespace jpegli {
|
||||
|
||||
namespace {
|
||||
|
||||
#define JPEG_API_FN(name) jpeg_##name
|
||||
#include "lib/jpegli/test_utils-inl.h"
|
||||
#undef JPEG_API_FN
|
||||
|
||||
void ReadOutputPass(j_decompress_ptr cinfo, const DecompressParams& dparams,
|
||||
TestImage* output) {
|
||||
JDIMENSION xoffset = 0;
|
||||
JDIMENSION yoffset = 0;
|
||||
JDIMENSION xsize_cropped = cinfo->output_width;
|
||||
JDIMENSION ysize_cropped = cinfo->output_height;
|
||||
if (dparams.crop_output) {
|
||||
xoffset = xsize_cropped = cinfo->output_width / 3;
|
||||
yoffset = ysize_cropped = cinfo->output_height / 3;
|
||||
jpeg_crop_scanline(cinfo, &xoffset, &xsize_cropped);
|
||||
JXL_CHECK(xsize_cropped == cinfo->output_width);
|
||||
}
|
||||
output->xsize = xsize_cropped;
|
||||
output->ysize = ysize_cropped;
|
||||
output->components = cinfo->out_color_components;
|
||||
if (cinfo->quantize_colors) {
|
||||
jxl::msan::UnpoisonMemory(cinfo->colormap, cinfo->out_color_components *
|
||||
sizeof(cinfo->colormap[0]));
|
||||
for (int c = 0; c < cinfo->out_color_components; ++c) {
|
||||
jxl::msan::UnpoisonMemory(
|
||||
cinfo->colormap[c],
|
||||
cinfo->actual_number_of_colors * sizeof(cinfo->colormap[c][0]));
|
||||
}
|
||||
}
|
||||
if (!cinfo->raw_data_out) {
|
||||
size_t stride = output->xsize * output->components;
|
||||
output->pixels.resize(output->ysize * stride);
|
||||
output->color_space = cinfo->out_color_space;
|
||||
if (yoffset > 0) {
|
||||
jpeg_skip_scanlines(cinfo, yoffset);
|
||||
}
|
||||
for (size_t y = 0; y < output->ysize; ++y) {
|
||||
JSAMPROW rows[] = {
|
||||
reinterpret_cast<JSAMPLE*>(&output->pixels[y * stride])};
|
||||
JXL_CHECK(1 == jpeg_read_scanlines(cinfo, rows, 1));
|
||||
jxl::msan::UnpoisonMemory(
|
||||
rows[0], sizeof(JSAMPLE) * cinfo->output_components * output->xsize);
|
||||
if (cinfo->quantize_colors) {
|
||||
UnmapColors(rows[0], cinfo->output_width, cinfo->out_color_components,
|
||||
cinfo->colormap, cinfo->actual_number_of_colors);
|
||||
}
|
||||
}
|
||||
if (cinfo->output_scanline < cinfo->output_height) {
|
||||
jpeg_skip_scanlines(cinfo, cinfo->output_height - cinfo->output_scanline);
|
||||
}
|
||||
} else {
|
||||
output->color_space = cinfo->jpeg_color_space;
|
||||
for (int c = 0; c < cinfo->num_components; ++c) {
|
||||
size_t xsize = cinfo->comp_info[c].width_in_blocks * DCTSIZE;
|
||||
size_t ysize = cinfo->comp_info[c].height_in_blocks * DCTSIZE;
|
||||
std::vector<uint8_t> plane(ysize * xsize);
|
||||
output->raw_data.emplace_back(std::move(plane));
|
||||
}
|
||||
while (cinfo->output_scanline < cinfo->output_height) {
|
||||
size_t iMCU_height = cinfo->max_v_samp_factor * DCTSIZE;
|
||||
JXL_CHECK(cinfo->output_scanline == cinfo->output_iMCU_row * iMCU_height);
|
||||
std::vector<std::vector<JSAMPROW>> rowdata(cinfo->num_components);
|
||||
std::vector<JSAMPARRAY> data(cinfo->num_components);
|
||||
for (int c = 0; c < cinfo->num_components; ++c) {
|
||||
size_t xsize = cinfo->comp_info[c].width_in_blocks * DCTSIZE;
|
||||
size_t ysize = cinfo->comp_info[c].height_in_blocks * DCTSIZE;
|
||||
size_t num_lines = cinfo->comp_info[c].v_samp_factor * DCTSIZE;
|
||||
rowdata[c].resize(num_lines);
|
||||
size_t y0 = cinfo->output_iMCU_row * num_lines;
|
||||
for (size_t i = 0; i < num_lines; ++i) {
|
||||
rowdata[c][i] =
|
||||
y0 + i < ysize ? &output->raw_data[c][(y0 + i) * xsize] : nullptr;
|
||||
}
|
||||
data[c] = &rowdata[c][0];
|
||||
}
|
||||
JXL_CHECK(iMCU_height ==
|
||||
jpeg_read_raw_data(cinfo, &data[0], iMCU_height));
|
||||
}
|
||||
}
|
||||
JXL_CHECK(cinfo->total_iMCU_rows ==
|
||||
DivCeil(cinfo->image_height, cinfo->max_v_samp_factor * DCTSIZE));
|
||||
}
|
||||
|
||||
void DecodeWithLibjpeg(const CompressParams& jparams,
|
||||
const DecompressParams& dparams, j_decompress_ptr cinfo,
|
||||
TestImage* output) {
|
||||
if (jparams.add_marker) {
|
||||
jpeg_save_markers(cinfo, kSpecialMarker0, 0xffff);
|
||||
jpeg_save_markers(cinfo, kSpecialMarker1, 0xffff);
|
||||
}
|
||||
if (!jparams.icc.empty()) {
|
||||
jpeg_save_markers(cinfo, JPEG_APP0 + 2, 0xffff);
|
||||
}
|
||||
JXL_CHECK(JPEG_REACHED_SOS ==
|
||||
jpeg_read_header(cinfo, /*require_image=*/TRUE));
|
||||
if (!jparams.icc.empty()) {
|
||||
uint8_t* icc_data = nullptr;
|
||||
unsigned int icc_len;
|
||||
JXL_CHECK(jpeg_read_icc_profile(cinfo, &icc_data, &icc_len));
|
||||
JXL_CHECK(icc_data);
|
||||
jxl::msan::UnpoisonMemory(icc_data, icc_len);
|
||||
JXL_CHECK(0 == memcmp(jparams.icc.data(), icc_data, icc_len));
|
||||
free(icc_data);
|
||||
}
|
||||
SetDecompressParams(dparams, cinfo);
|
||||
VerifyHeader(jparams, cinfo);
|
||||
if (dparams.output_mode == COEFFICIENTS) {
|
||||
jvirt_barray_ptr* coef_arrays = jpeg_read_coefficients(cinfo);
|
||||
JXL_CHECK(coef_arrays != nullptr);
|
||||
CopyCoefficients(cinfo, coef_arrays, output);
|
||||
} else {
|
||||
JXL_CHECK(jpeg_start_decompress(cinfo));
|
||||
VerifyScanHeader(jparams, cinfo);
|
||||
ReadOutputPass(cinfo, dparams, output);
|
||||
}
|
||||
JXL_CHECK(jpeg_finish_decompress(cinfo));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// 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) {
|
||||
jpeg_decompress_struct cinfo = {};
|
||||
const auto try_catch_block = [&]() {
|
||||
jpeg_error_mgr jerr;
|
||||
jmp_buf env;
|
||||
cinfo.err = jpeg_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);
|
||||
jpeg_destroy(cinfo);
|
||||
longjmp(*env, 1);
|
||||
};
|
||||
jpeg_create_decompress(&cinfo);
|
||||
jpeg_mem_src(&cinfo, compressed.data(), compressed.size());
|
||||
if (jparams.add_marker) {
|
||||
jpeg_save_markers(&cinfo, kSpecialMarker0, 0xffff);
|
||||
jpeg_save_markers(&cinfo, kSpecialMarker1, 0xffff);
|
||||
}
|
||||
JXL_CHECK(JPEG_REACHED_SOS ==
|
||||
jpeg_read_header(&cinfo, /*require_image=*/TRUE));
|
||||
cinfo.buffered_image = TRUE;
|
||||
SetDecompressParams(dparams, &cinfo);
|
||||
VerifyHeader(jparams, &cinfo);
|
||||
JXL_CHECK(jpeg_start_decompress(&cinfo));
|
||||
// start decompress should not read the whole input in buffered image mode
|
||||
JXL_CHECK(!jpeg_input_complete(&cinfo));
|
||||
JXL_CHECK(cinfo.output_scan_number == 0);
|
||||
int sos_marker_cnt = 1; // read header reads the first SOS marker
|
||||
while (!jpeg_input_complete(&cinfo)) {
|
||||
JXL_CHECK(cinfo.input_scan_number == sos_marker_cnt);
|
||||
if (dparams.skip_scans && (cinfo.input_scan_number % 2) != 1) {
|
||||
int result = JPEG_SUSPENDED;
|
||||
while (result != JPEG_REACHED_SOS && result != JPEG_REACHED_EOI) {
|
||||
result = jpeg_consume_input(&cinfo);
|
||||
}
|
||||
if (result == JPEG_REACHED_SOS) ++sos_marker_cnt;
|
||||
continue;
|
||||
}
|
||||
SetScanDecompressParams(dparams, &cinfo, cinfo.input_scan_number);
|
||||
JXL_CHECK(jpeg_start_output(&cinfo, cinfo.input_scan_number));
|
||||
// start output sets output_scan_number, but does not change
|
||||
// input_scan_number
|
||||
JXL_CHECK(cinfo.output_scan_number == cinfo.input_scan_number);
|
||||
JXL_CHECK(cinfo.input_scan_number == sos_marker_cnt);
|
||||
VerifyScanHeader(jparams, &cinfo);
|
||||
TestImage output;
|
||||
ReadOutputPass(&cinfo, dparams, &output);
|
||||
output_progression->emplace_back(std::move(output));
|
||||
// read scanlines/read raw data does not change input/output scan number
|
||||
if (!cinfo.progressive_mode) {
|
||||
JXL_CHECK(cinfo.input_scan_number == sos_marker_cnt);
|
||||
JXL_CHECK(cinfo.output_scan_number == cinfo.input_scan_number);
|
||||
}
|
||||
JXL_CHECK(jpeg_finish_output(&cinfo));
|
||||
++sos_marker_cnt; // finish output reads the next SOS marker or EOI
|
||||
if (dparams.output_mode == COEFFICIENTS) {
|
||||
jvirt_barray_ptr* coef_arrays = jpeg_read_coefficients(&cinfo);
|
||||
JXL_CHECK(coef_arrays != nullptr);
|
||||
CopyCoefficients(&cinfo, coef_arrays, &output_progression->back());
|
||||
}
|
||||
}
|
||||
JXL_CHECK(jpeg_finish_decompress(&cinfo));
|
||||
return true;
|
||||
};
|
||||
JXL_CHECK(try_catch_block());
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
}
|
||||
|
||||
// Returns the number of bytes read from compressed.
|
||||
size_t DecodeWithLibjpeg(const CompressParams& jparams,
|
||||
const DecompressParams& dparams,
|
||||
const uint8_t* table_stream, size_t table_stream_size,
|
||||
const uint8_t* compressed, size_t len,
|
||||
TestImage* output) {
|
||||
jpeg_decompress_struct cinfo = {};
|
||||
size_t bytes_read;
|
||||
const auto try_catch_block = [&]() {
|
||||
jpeg_error_mgr jerr;
|
||||
jmp_buf env;
|
||||
cinfo.err = jpeg_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);
|
||||
jpeg_destroy(cinfo);
|
||||
longjmp(*env, 1);
|
||||
};
|
||||
jpeg_create_decompress(&cinfo);
|
||||
if (table_stream != nullptr) {
|
||||
jpeg_mem_src(&cinfo, table_stream, table_stream_size);
|
||||
jpeg_read_header(&cinfo, FALSE);
|
||||
}
|
||||
jpeg_mem_src(&cinfo, compressed, len);
|
||||
DecodeWithLibjpeg(jparams, dparams, &cinfo, output);
|
||||
bytes_read = len - cinfo.src->bytes_in_buffer;
|
||||
return true;
|
||||
};
|
||||
JXL_CHECK(try_catch_block());
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
void DecodeWithLibjpeg(const CompressParams& jparams,
|
||||
const DecompressParams& dparams,
|
||||
const std::vector<uint8_t>& compressed,
|
||||
TestImage* output) {
|
||||
DecodeWithLibjpeg(jparams, dparams, nullptr, 0, compressed.data(),
|
||||
compressed.size(), output);
|
||||
}
|
||||
|
||||
} // namespace jpegli
|
37
third_party/jpeg-xl/lib/jpegli/libjpeg_test_util.h
vendored
Normal file
37
third_party/jpeg-xl/lib/jpegli/libjpeg_test_util.h
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
// 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_LIBJPEG_TEST_UTIL_H_
|
||||
#define LIB_JPEGLI_LIBJPEG_TEST_UTIL_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "lib/jpegli/test_params.h"
|
||||
|
||||
namespace jpegli {
|
||||
|
||||
// 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);
|
||||
// Returns the number of bytes read from compressed.
|
||||
size_t DecodeWithLibjpeg(const CompressParams& jparams,
|
||||
const DecompressParams& dparams,
|
||||
const uint8_t* table_stream, size_t table_stream_size,
|
||||
const uint8_t* compressed, size_t len,
|
||||
TestImage* output);
|
||||
void DecodeWithLibjpeg(const CompressParams& jparams,
|
||||
const DecompressParams& dparams,
|
||||
const std::vector<uint8_t>& compressed,
|
||||
TestImage* output);
|
||||
|
||||
} // namespace jpegli
|
||||
|
||||
#endif // LIB_JPEGLI_LIBJPEG_TEST_UTIL_H_
|
@ -7,11 +7,6 @@
|
||||
// shared library that is API- and ABI-compatible with libjpeg-turbo's version
|
||||
// of libjpeg.so.
|
||||
|
||||
/* clang-format off */
|
||||
#include <stdio.h>
|
||||
#include <jpeglib.h>
|
||||
/* clang-format on */
|
||||
|
||||
#include "lib/jpegli/common.h"
|
||||
#include "lib/jpegli/decode.h"
|
||||
#include "lib/jpegli/encode.h"
|
||||
|
@ -6,11 +6,9 @@
|
||||
#ifndef LIB_JPEGLI_MEMORY_MANAGER_H_
|
||||
#define LIB_JPEGLI_MEMORY_MANAGER_H_
|
||||
|
||||
/* clang-format off */
|
||||
#include <stdio.h>
|
||||
#include <jpeglib.h>
|
||||
#include <stdlib.h>
|
||||
/* clang-format on */
|
||||
|
||||
#include "lib/jpegli/common.h"
|
||||
|
||||
#define JPOOL_PERMANENT_ALIGNED (JPOOL_NUMPOOLS + JPOOL_PERMANENT)
|
||||
#define JPOOL_IMAGE_ALIGNED (JPOOL_NUMPOOLS + JPOOL_IMAGE)
|
||||
|
404
third_party/jpeg-xl/lib/jpegli/quant.cc
vendored
404
third_party/jpeg-xl/lib/jpegli/quant.cc
vendored
@ -24,7 +24,7 @@ namespace {
|
||||
// Global scale is chosen in a way that butteraugli 3-norm matches libjpeg
|
||||
// with the same quality setting. Fitted for quality 90 on jyrki31 corpus.
|
||||
constexpr float kGlobalScaleXYB = 1.43951668f;
|
||||
constexpr float kGlobalScaleYCbCr = 1.66986909f;
|
||||
constexpr float kGlobalScaleYCbCr = 1.73966010f;
|
||||
|
||||
static constexpr float kBaseQuantMatrixXYB[] = {
|
||||
// c = 0
|
||||
@ -226,212 +226,212 @@ static constexpr float kBaseQuantMatrixXYB[] = {
|
||||
|
||||
static const float kBaseQuantMatrixYCbCr[] = {
|
||||
// c = 0
|
||||
1.4076321125f,
|
||||
2.6927082539f,
|
||||
2.6927735806f,
|
||||
2.9220938683f,
|
||||
3.0870633125f,
|
||||
3.4968640804f,
|
||||
3.5730612278f,
|
||||
3.5978596210f,
|
||||
2.6927082539f,
|
||||
2.6926636696f,
|
||||
2.7195601463f,
|
||||
2.9238407612f,
|
||||
3.1882488728f,
|
||||
3.0607142448f,
|
||||
3.1882314682f,
|
||||
3.8304426670f,
|
||||
2.6927735806f,
|
||||
2.7195601463f,
|
||||
2.9532215595f,
|
||||
3.5562388897f,
|
||||
3.7088179588f,
|
||||
3.0576279163f,
|
||||
3.7443304062f,
|
||||
4.2484717369f,
|
||||
2.9220938683f,
|
||||
2.9238407612f,
|
||||
3.5562388897f,
|
||||
3.0594384670f,
|
||||
4.1780085564f,
|
||||
4.9221563339f,
|
||||
4.7842588425f,
|
||||
4.6059336662f,
|
||||
3.0870633125f,
|
||||
3.1882488728f,
|
||||
3.7088179588f,
|
||||
4.1780085564f,
|
||||
4.3475294113f,
|
||||
5.5422372818f,
|
||||
5.5741071701f,
|
||||
5.4531836510f,
|
||||
3.4968640804f,
|
||||
3.0607142448f,
|
||||
3.0576279163f,
|
||||
4.9221563339f,
|
||||
5.5422372818f,
|
||||
5.4393601418f,
|
||||
5.1039180756f,
|
||||
6.0990614891f,
|
||||
3.5730612278f,
|
||||
3.1882314682f,
|
||||
3.7443304062f,
|
||||
4.7842588425f,
|
||||
5.5741071701f,
|
||||
5.1039180756f,
|
||||
5.4144043922f,
|
||||
5.4524297714f,
|
||||
3.5978596210f,
|
||||
3.8304426670f,
|
||||
4.2484717369f,
|
||||
4.6059336662f,
|
||||
5.4531836510f,
|
||||
6.0990614891f,
|
||||
5.4524297714f,
|
||||
4.3595433235f,
|
||||
1.2397409345866273f, //
|
||||
1.7227115097630963f, //
|
||||
2.9212167156636855f, //
|
||||
2.812737435286529f, //
|
||||
3.339819711906184f, //
|
||||
3.463603762596166f, //
|
||||
3.840915217993518f, //
|
||||
3.86956f, //
|
||||
1.7227115097630963f, //
|
||||
2.0928894413636874f, //
|
||||
2.8456760904429297f, //
|
||||
2.704506820909662f, //
|
||||
3.4407673520905337f, //
|
||||
3.166232352090534f, //
|
||||
4.025208741558432f, //
|
||||
4.035324490952577f, //
|
||||
2.9212167156636855f, //
|
||||
2.8456760904429297f, //
|
||||
2.9587403520905338f, //
|
||||
3.3862948970669273f, //
|
||||
3.619523781336757f, //
|
||||
3.9046279999999998f, //
|
||||
3.757835838431854f, //
|
||||
4.237447515714274f, //
|
||||
2.812737435286529f, //
|
||||
2.704506820909662f, //
|
||||
3.3862948970669273f, //
|
||||
3.380058821812233f, //
|
||||
4.1679867415584315f, //
|
||||
4.805510627261856f, //
|
||||
4.784259f, //
|
||||
4.605934f, //
|
||||
3.339819711906184f, //
|
||||
3.4407673520905337f, //
|
||||
3.619523781336757f, //
|
||||
4.1679867415584315f, //
|
||||
4.579851258441568f, //
|
||||
4.923237f, //
|
||||
5.574107f, //
|
||||
5.48533336146308f, //
|
||||
3.463603762596166f, //
|
||||
3.166232352090534f, //
|
||||
3.9046279999999998f, //
|
||||
4.805510627261856f, //
|
||||
4.923237f, //
|
||||
5.43936f, //
|
||||
5.093895741558431f, //
|
||||
6.0872254423617225f, //
|
||||
3.840915217993518f, //
|
||||
4.025208741558432f, //
|
||||
3.757835838431854f, //
|
||||
4.784259f, //
|
||||
5.574107f, //
|
||||
5.093895741558431f, //
|
||||
5.438461f, //
|
||||
5.4037359493250845f, //
|
||||
3.86956f, //
|
||||
4.035324490952577f, //
|
||||
4.237447515714274f, //
|
||||
4.605934f, //
|
||||
5.48533336146308f, //
|
||||
6.0872254423617225f, //
|
||||
5.4037359493250845f, //
|
||||
4.37787101190424f,
|
||||
// c = 1
|
||||
2.8152642250f,
|
||||
10.4298934937f,
|
||||
16.1451492310f,
|
||||
15.3725156784f,
|
||||
17.6543502808f,
|
||||
19.1104965210f,
|
||||
17.5021877289f,
|
||||
29.5177459717f,
|
||||
10.4298934937f,
|
||||
15.7448558807f,
|
||||
16.8441677094f,
|
||||
15.3214502335f,
|
||||
17.5918464661f,
|
||||
16.8787574768f,
|
||||
27.0867996216f,
|
||||
21.3443832397f,
|
||||
16.1451492310f,
|
||||
16.8441677094f,
|
||||
14.7525558472f,
|
||||
18.0765247345f,
|
||||
18.2206096649f,
|
||||
23.2126445770f,
|
||||
98.1291885376f,
|
||||
23.6039886475f,
|
||||
15.3725156784f,
|
||||
15.3214502335f,
|
||||
18.0765247345f,
|
||||
17.2925109863f,
|
||||
16.1435356140f,
|
||||
24.0464611053f,
|
||||
27.1577339172f,
|
||||
35.3269882202f,
|
||||
17.6543502808f,
|
||||
17.5918464661f,
|
||||
18.2206096649f,
|
||||
16.1435356140f,
|
||||
19.2819595337f,
|
||||
16.2939300537f,
|
||||
19.6862888336f,
|
||||
51.0941123962f,
|
||||
19.1104965210f,
|
||||
16.8787574768f,
|
||||
23.2126445770f,
|
||||
24.0464611053f,
|
||||
16.2939300537f,
|
||||
32.3153648376f,
|
||||
45.7272338867f,
|
||||
64.6245880127f,
|
||||
17.5021877289f,
|
||||
27.0867996216f,
|
||||
98.1291885376f,
|
||||
27.1577339172f,
|
||||
19.6862888336f,
|
||||
45.7272338867f,
|
||||
61.8331909180f,
|
||||
85.0626754761f,
|
||||
29.5177459717f,
|
||||
21.3443832397f,
|
||||
23.6039886475f,
|
||||
35.3269882202f,
|
||||
51.0941123962f,
|
||||
64.6245880127f,
|
||||
85.0626754761f,
|
||||
112.7605514526f,
|
||||
2.8236197786377537f, //
|
||||
6.495639358561486f, //
|
||||
9.310489207538302f, //
|
||||
10.64747864717083f, //
|
||||
11.07419143098738f, //
|
||||
17.146390223910462f, //
|
||||
18.463982229408998f, //
|
||||
29.087001644203088f, //
|
||||
6.495639358561486f, //
|
||||
8.890103846667353f, //
|
||||
8.976895794294748f, //
|
||||
13.666270550318826f, //
|
||||
16.547071905624193f, //
|
||||
16.63871382827686f, //
|
||||
26.778396930893695f, //
|
||||
21.33034294694781f, //
|
||||
9.310489207538302f, //
|
||||
8.976895794294748f, //
|
||||
11.08737706005991f, //
|
||||
18.20548239870446f, //
|
||||
19.752481654011646f, //
|
||||
23.985660533114896f, //
|
||||
102.6457378402362f, //
|
||||
24.450989f, //
|
||||
10.64747864717083f, //
|
||||
13.666270550318826f, //
|
||||
18.20548239870446f, //
|
||||
18.628012327860365f, //
|
||||
16.042509519487183f, //
|
||||
25.04918273242625f, //
|
||||
25.017140189353015f, //
|
||||
35.79788782635831f, //
|
||||
11.07419143098738f, //
|
||||
16.547071905624193f, //
|
||||
19.752481654011646f, //
|
||||
16.042509519487183f, //
|
||||
19.373482748612577f, //
|
||||
14.677529999999999f, //
|
||||
19.94695960400931f, //
|
||||
51.094112f, //
|
||||
17.146390223910462f, //
|
||||
16.63871382827686f, //
|
||||
23.985660533114896f, //
|
||||
25.04918273242625f, //
|
||||
14.677529999999999f, //
|
||||
31.320412426835304f, //
|
||||
46.357234000000005f, //
|
||||
67.48111451705412f, //
|
||||
18.463982229408998f, //
|
||||
26.778396930893695f, //
|
||||
102.6457378402362f, //
|
||||
25.017140189353015f, //
|
||||
19.94695960400931f, //
|
||||
46.357234000000005f, //
|
||||
61.315764694388044f, //
|
||||
88.34665293823721f, //
|
||||
29.087001644203088f, //
|
||||
21.33034294694781f, //
|
||||
24.450989f, //
|
||||
35.79788782635831f, //
|
||||
51.094112f, //
|
||||
67.48111451705412f, //
|
||||
88.34665293823721f, //
|
||||
112.16099098350989f,
|
||||
// c = 2
|
||||
2.8152642250f,
|
||||
5.4735932350f,
|
||||
7.3637795448f,
|
||||
6.5195322037f,
|
||||
8.1501169205f,
|
||||
8.7243938446f,
|
||||
8.7219915390f,
|
||||
9.3618907928f,
|
||||
5.4735932350f,
|
||||
7.1514792442f,
|
||||
7.2054982185f,
|
||||
8.1126995087f,
|
||||
8.1497650146f,
|
||||
7.1335659027f,
|
||||
7.8453893661f,
|
||||
8.3512821198f,
|
||||
7.3637795448f,
|
||||
7.2054982185f,
|
||||
6.9224662781f,
|
||||
8.0766754150f,
|
||||
9.1168527603f,
|
||||
7.3714752197f,
|
||||
7.3646650314f,
|
||||
8.6790895462f,
|
||||
6.5195322037f,
|
||||
8.1126995087f,
|
||||
8.0766754150f,
|
||||
7.8294739723f,
|
||||
7.7385902405f,
|
||||
7.8628563881f,
|
||||
7.4404106140f,
|
||||
8.4759435654f,
|
||||
8.1501169205f,
|
||||
8.1497650146f,
|
||||
9.1168527603f,
|
||||
7.7385902405f,
|
||||
7.0960793495f,
|
||||
8.9185447693f,
|
||||
8.2047510147f,
|
||||
7.8465061188f,
|
||||
8.7243938446f,
|
||||
7.1335659027f,
|
||||
7.3714752197f,
|
||||
7.8628563881f,
|
||||
8.9185447693f,
|
||||
8.6063842773f,
|
||||
9.7156696320f,
|
||||
64.6700744629f,
|
||||
8.7219915390f,
|
||||
7.8453893661f,
|
||||
7.3646650314f,
|
||||
7.4404106140f,
|
||||
8.2047510147f,
|
||||
9.7156696320f,
|
||||
61.9934043884f,
|
||||
83.2930450439f,
|
||||
9.3618907928f,
|
||||
8.3512821198f,
|
||||
8.6790895462f,
|
||||
8.4759435654f,
|
||||
7.8465061188f,
|
||||
64.6700744629f,
|
||||
83.2930450439f,
|
||||
113.0502548218f,
|
||||
2.9217254961255255f, //
|
||||
4.497681013199305f, //
|
||||
7.356344520940414f, //
|
||||
6.583891506504051f, //
|
||||
8.535608740100237f, //
|
||||
8.799434353234647f, //
|
||||
9.188341534163023f, //
|
||||
9.482700481227672f, //
|
||||
4.497681013199305f, //
|
||||
6.309548851989123f, //
|
||||
7.024608962670982f, //
|
||||
7.156445324163424f, //
|
||||
8.049059218663244f, //
|
||||
7.0124290657218555f, //
|
||||
6.711923184393611f, //
|
||||
8.380307846134853f, //
|
||||
7.356344520940414f, //
|
||||
7.024608962670982f, //
|
||||
6.892101177327445f, //
|
||||
6.882819916277163f, //
|
||||
8.782226090078568f, //
|
||||
6.8774750000000004f, //
|
||||
7.8858175969577955f, //
|
||||
8.67909f, //
|
||||
6.583891506504051f, //
|
||||
7.156445324163424f, //
|
||||
6.882819916277163f, //
|
||||
7.003072944847055f, //
|
||||
7.7223464701024875f, //
|
||||
7.955425720217421f, //
|
||||
7.4734110000000005f, //
|
||||
8.362933242943903f, //
|
||||
8.535608740100237f, //
|
||||
8.049059218663244f, //
|
||||
8.782226090078568f, //
|
||||
7.7223464701024875f, //
|
||||
6.778005927001542f, //
|
||||
9.484922741558432f, //
|
||||
9.043702663686046f, //
|
||||
8.053178199770173f, //
|
||||
8.799434353234647f, //
|
||||
7.0124290657218555f, //
|
||||
6.8774750000000004f, //
|
||||
7.955425720217421f, //
|
||||
9.484922741558432f, //
|
||||
8.607606527385098f, //
|
||||
9.922697394370815f, //
|
||||
64.25135180237939f, //
|
||||
9.188341534163023f, //
|
||||
6.711923184393611f, //
|
||||
7.8858175969577955f, //
|
||||
7.4734110000000005f, //
|
||||
9.043702663686046f, //
|
||||
9.922697394370815f, //
|
||||
63.184936549738225f, //
|
||||
83.35294340273799f, //
|
||||
9.482700481227672f, //
|
||||
8.380307846134853f, //
|
||||
8.67909f, //
|
||||
8.362933242943903f, //
|
||||
8.053178199770173f, //
|
||||
64.25135180237939f, //
|
||||
83.35294340273799f, //
|
||||
114.89202448569779f, //
|
||||
};
|
||||
|
||||
static const float k420GlobalScale = 1.2;
|
||||
static const float k420GlobalScale = 1.22;
|
||||
static const float k420Rescale[64] = {
|
||||
0.6386, 0.4213, 0.3994, 0.3333, 0.3143, 0.3367, 0.3612, 0.3794, //
|
||||
0.4213, 0.4026, 0.3309, 0.3344, 0.3059, 0.3118, 0.4069, 0.3595, //
|
||||
0.3994, 0.3309, 0.4080, 0.2531, 0.2645, 0.3630, 0.3502, 0.3231, //
|
||||
0.3333, 0.3344, 0.2531, 0.2960, 0.3153, 0.3476, 0.3430, 0.4004, //
|
||||
0.3143, 0.3059, 0.2645, 0.3153, 0.2733, 0.3296, 0.3338, 0.3418, //
|
||||
0.3367, 0.3118, 0.3630, 0.3476, 0.3296, 0.3144, 0.2262, 0.1326, //
|
||||
0.3612, 0.4069, 0.3502, 0.3430, 0.3338, 0.2262, 0.1000, 0.1000, //
|
||||
0.3794, 0.3595, 0.3231, 0.4004, 0.3418, 0.1326, 0.1000, 0.3366, //
|
||||
0.4093, 0.3209, 0.3477, 0.3333, 0.3144, 0.2823, 0.3214, 0.3354, //
|
||||
0.3209, 0.3111, 0.3489, 0.2801, 0.3059, 0.3119, 0.4135, 0.3445, //
|
||||
0.3477, 0.3489, 0.3586, 0.3257, 0.2727, 0.3754, 0.3369, 0.3484, //
|
||||
0.3333, 0.2801, 0.3257, 0.3020, 0.3515, 0.3410, 0.3971, 0.3839, //
|
||||
0.3144, 0.3059, 0.2727, 0.3515, 0.3105, 0.3397, 0.2716, 0.3836, //
|
||||
0.2823, 0.3119, 0.3754, 0.3410, 0.3397, 0.3212, 0.3203, 0.0726, //
|
||||
0.3214, 0.4135, 0.3369, 0.3971, 0.2716, 0.3203, 0.0798, 0.0553, //
|
||||
0.3354, 0.3445, 0.3484, 0.3839, 0.3836, 0.0726, 0.0553, 0.3368, //
|
||||
};
|
||||
|
||||
static const float kBaseQuantMatrixStd[] = {
|
||||
|
5
third_party/jpeg-xl/lib/jpegli/quant.h
vendored
5
third_party/jpeg-xl/lib/jpegli/quant.h
vendored
@ -6,10 +6,7 @@
|
||||
#ifndef LIB_JPEGLI_QUANT_H_
|
||||
#define LIB_JPEGLI_QUANT_H_
|
||||
|
||||
/* clang-format off */
|
||||
#include <stdio.h>
|
||||
#include <jpeglib.h>
|
||||
/* clang-format on */
|
||||
#include "lib/jpegli/common.h"
|
||||
|
||||
namespace jpegli {
|
||||
|
||||
|
1
third_party/jpeg-xl/lib/jpegli/render.cc
vendored
1
third_party/jpeg-xl/lib/jpegli/render.cc
vendored
@ -13,6 +13,7 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <hwy/aligned_allocator.h>
|
||||
#include <vector>
|
||||
|
||||
#include "lib/jpegli/color_quantize.h"
|
||||
#include "lib/jpegli/color_transform.h"
|
||||
|
6
third_party/jpeg-xl/lib/jpegli/render.h
vendored
6
third_party/jpeg-xl/lib/jpegli/render.h
vendored
@ -6,13 +6,9 @@
|
||||
#ifndef LIB_JPEGLI_RENDER_H_
|
||||
#define LIB_JPEGLI_RENDER_H_
|
||||
|
||||
/* clang-format off */
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <jpeglib.h>
|
||||
/* clang-format on */
|
||||
|
||||
#include <vector>
|
||||
#include "lib/jpegli/common.h"
|
||||
|
||||
namespace jpegli {
|
||||
|
||||
|
@ -107,7 +107,7 @@ TEST_P(StreamingTestParam, TestStreaming) {
|
||||
cinfo.image_width = input.xsize;
|
||||
cinfo.image_height = input.ysize;
|
||||
cinfo.input_components = input.components;
|
||||
cinfo.in_color_space = input.color_space;
|
||||
cinfo.in_color_space = (J_COLOR_SPACE)input.color_space;
|
||||
jpegli_set_defaults(&cinfo);
|
||||
cinfo.comp_info[0].v_samp_factor = config.jparams.v_sampling[0];
|
||||
jpegli_set_progressive_level(&cinfo, 0);
|
||||
|
163
third_party/jpeg-xl/lib/jpegli/test_params.h
vendored
Normal file
163
third_party/jpeg-xl/lib/jpegli/test_params.h
vendored
Normal file
@ -0,0 +1,163 @@
|
||||
// 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_PARAMS_H_
|
||||
#define LIB_JPEGLI_TEST_PARAMS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "lib/jpegli/types.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 ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0]))
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
int color_space = 2; // 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<int16_t>> coeffs;
|
||||
void AllocatePixels() {
|
||||
pixels.resize(ysize * xsize * components *
|
||||
jpegli_bytes_per_sample(data_type));
|
||||
}
|
||||
void Clear() {
|
||||
pixels.clear();
|
||||
raw_data.clear();
|
||||
coeffs.clear();
|
||||
}
|
||||
};
|
||||
|
||||
struct CompressParams {
|
||||
int quality = 90;
|
||||
bool set_jpeg_colorspace = false;
|
||||
int jpeg_color_space = 0; // 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() * 8) * 8;
|
||||
}
|
||||
int comp_height(const TestImage& input, int c) const {
|
||||
return DivCeil(input.ysize * v_samp(c), max_v_sample() * 8) * 8;
|
||||
}
|
||||
};
|
||||
|
||||
enum ColorQuantMode {
|
||||
CQUANT_1PASS,
|
||||
CQUANT_2PASS,
|
||||
CQUANT_EXTERNAL,
|
||||
CQUANT_REUSE,
|
||||
};
|
||||
|
||||
struct ScanDecompressParams {
|
||||
int max_scan_number;
|
||||
int 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;
|
||||
int out_color_space = 0; // 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;
|
||||
};
|
||||
|
||||
} // namespace jpegli
|
||||
|
||||
#endif // LIB_JPEGLI_TEST_PARAMS_H_
|
430
third_party/jpeg-xl/lib/jpegli/test_utils-inl.h
vendored
Normal file
430
third_party/jpeg-xl/lib/jpegli/test_utils-inl.h
vendored
Normal file
@ -0,0 +1,430 @@
|
||||
// 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.
|
||||
|
||||
// This template file is included in both the libjpeg_test_util.cc and the
|
||||
// test_utils.cc files with different JPEG_API_FN macros and possibly different
|
||||
// include paths for the jpeg headers.
|
||||
|
||||
// Sequential non-interleaved.
|
||||
static constexpr jpeg_scan_info kScript1[] = {
|
||||
{1, {0}, 0, 63, 0, 0},
|
||||
{1, {1}, 0, 63, 0, 0},
|
||||
{1, {2}, 0, 63, 0, 0},
|
||||
};
|
||||
// Sequential partially interleaved, chroma first.
|
||||
static constexpr jpeg_scan_info kScript2[] = {
|
||||
{2, {1, 2}, 0, 63, 0, 0},
|
||||
{1, {0}, 0, 63, 0, 0},
|
||||
};
|
||||
|
||||
// Rest of the scan scripts are progressive.
|
||||
|
||||
static constexpr jpeg_scan_info kScript3[] = {
|
||||
// Interleaved full DC.
|
||||
{3, {0, 1, 2}, 0, 0, 0, 0},
|
||||
// Full AC scans.
|
||||
{1, {0}, 1, 63, 0, 0},
|
||||
{1, {1}, 1, 63, 0, 0},
|
||||
{1, {2}, 1, 63, 0, 0},
|
||||
};
|
||||
static constexpr jpeg_scan_info kScript4[] = {
|
||||
// Non-interleaved full DC.
|
||||
{1, {0}, 0, 0, 0, 0},
|
||||
{1, {1}, 0, 0, 0, 0},
|
||||
{1, {2}, 0, 0, 0, 0},
|
||||
// Full AC scans.
|
||||
{1, {0}, 1, 63, 0, 0},
|
||||
{1, {1}, 1, 63, 0, 0},
|
||||
{1, {2}, 1, 63, 0, 0},
|
||||
};
|
||||
static constexpr jpeg_scan_info kScript5[] = {
|
||||
// Partially interleaved full DC, chroma first.
|
||||
{2, {1, 2}, 0, 0, 0, 0},
|
||||
{1, {0}, 0, 0, 0, 0},
|
||||
// AC shifted by 1 bit.
|
||||
{1, {0}, 1, 63, 0, 1},
|
||||
{1, {1}, 1, 63, 0, 1},
|
||||
{1, {2}, 1, 63, 0, 1},
|
||||
// AC refinement scan.
|
||||
{1, {0}, 1, 63, 1, 0},
|
||||
{1, {1}, 1, 63, 1, 0},
|
||||
{1, {2}, 1, 63, 1, 0},
|
||||
};
|
||||
static constexpr jpeg_scan_info kScript6[] = {
|
||||
// Interleaved DC shifted by 2 bits.
|
||||
{3, {0, 1, 2}, 0, 0, 0, 2},
|
||||
// Interleaved DC refinement scans.
|
||||
{3, {0, 1, 2}, 0, 0, 2, 1},
|
||||
{3, {0, 1, 2}, 0, 0, 1, 0},
|
||||
// Full AC scans.
|
||||
{1, {0}, 1, 63, 0, 0},
|
||||
{1, {1}, 1, 63, 0, 0},
|
||||
{1, {2}, 1, 63, 0, 0},
|
||||
};
|
||||
|
||||
static constexpr jpeg_scan_info kScript7[] = {
|
||||
// Non-interleaved DC shifted by 2 bits.
|
||||
{1, {0}, 0, 0, 0, 2},
|
||||
{1, {1}, 0, 0, 0, 2},
|
||||
{1, {2}, 0, 0, 0, 2},
|
||||
// Non-interleaved DC first refinement scans.
|
||||
{1, {0}, 0, 0, 2, 1},
|
||||
{1, {1}, 0, 0, 2, 1},
|
||||
{1, {2}, 0, 0, 2, 1},
|
||||
// Non-interleaved DC second refinement scans.
|
||||
{1, {0}, 0, 0, 1, 0},
|
||||
{1, {1}, 0, 0, 1, 0},
|
||||
{1, {2}, 0, 0, 1, 0},
|
||||
// Full AC scans.
|
||||
{1, {0}, 1, 63, 0, 0},
|
||||
{1, {1}, 1, 63, 0, 0},
|
||||
{1, {2}, 1, 63, 0, 0},
|
||||
};
|
||||
|
||||
static constexpr jpeg_scan_info kScript8[] = {
|
||||
// Partially interleaved DC shifted by 2 bits, chroma first
|
||||
{2, {1, 2}, 0, 0, 0, 2},
|
||||
{1, {0}, 0, 0, 0, 2},
|
||||
// Partially interleaved DC first refinement scans.
|
||||
{2, {0, 2}, 0, 0, 2, 1},
|
||||
{1, {1}, 0, 0, 2, 1},
|
||||
// Partially interleaved DC first refinement scans, chroma first.
|
||||
{2, {1, 2}, 0, 0, 1, 0},
|
||||
{1, {0}, 0, 0, 1, 0},
|
||||
// Full AC scans.
|
||||
{1, {0}, 1, 63, 0, 0},
|
||||
{1, {1}, 1, 63, 0, 0},
|
||||
{1, {2}, 1, 63, 0, 0},
|
||||
};
|
||||
|
||||
static constexpr jpeg_scan_info kScript9[] = {
|
||||
// Interleaved full DC.
|
||||
{3, {0, 1, 2}, 0, 0, 0, 0},
|
||||
// AC scans for component 0
|
||||
// shifted by 1 bit, two spectral ranges
|
||||
{1, {0}, 1, 6, 0, 1},
|
||||
{1, {0}, 7, 63, 0, 1},
|
||||
// refinement scan, full
|
||||
{1, {0}, 1, 63, 1, 0},
|
||||
// AC scans for component 1
|
||||
// shifted by 1 bit, full
|
||||
{1, {1}, 1, 63, 0, 1},
|
||||
// refinement scan, two spectral ranges
|
||||
{1, {1}, 1, 6, 1, 0},
|
||||
{1, {1}, 7, 63, 1, 0},
|
||||
// AC scans for component 2
|
||||
// shifted by 1 bit, two spectral ranges
|
||||
{1, {2}, 1, 6, 0, 1},
|
||||
{1, {2}, 7, 63, 0, 1},
|
||||
// refinement scan, two spectral ranges (but different from above)
|
||||
{1, {2}, 1, 16, 1, 0},
|
||||
{1, {2}, 17, 63, 1, 0},
|
||||
};
|
||||
|
||||
static constexpr jpeg_scan_info kScript10[] = {
|
||||
// Interleaved full DC.
|
||||
{3, {0, 1, 2}, 0, 0, 0, 0},
|
||||
// AC scans for spectral range 1..16
|
||||
// shifted by 1
|
||||
{1, {0}, 1, 16, 0, 1},
|
||||
{1, {1}, 1, 16, 0, 1},
|
||||
{1, {2}, 1, 16, 0, 1},
|
||||
// refinement scans, two sub-ranges
|
||||
{1, {0}, 1, 8, 1, 0},
|
||||
{1, {0}, 9, 16, 1, 0},
|
||||
{1, {1}, 1, 8, 1, 0},
|
||||
{1, {1}, 9, 16, 1, 0},
|
||||
{1, {2}, 1, 8, 1, 0},
|
||||
{1, {2}, 9, 16, 1, 0},
|
||||
// AC scans for spectral range 17..63
|
||||
{1, {0}, 17, 63, 0, 1},
|
||||
{1, {1}, 17, 63, 0, 1},
|
||||
{1, {2}, 17, 63, 0, 1},
|
||||
// refinement scans, two sub-ranges
|
||||
{1, {0}, 17, 28, 1, 0},
|
||||
{1, {0}, 29, 63, 1, 0},
|
||||
{1, {1}, 17, 28, 1, 0},
|
||||
{1, {1}, 29, 63, 1, 0},
|
||||
{1, {2}, 17, 28, 1, 0},
|
||||
{1, {2}, 29, 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},
|
||||
{ARRAY_SIZE(kScript5), kScript5}, {ARRAY_SIZE(kScript6), kScript6},
|
||||
{ARRAY_SIZE(kScript7), kScript7}, {ARRAY_SIZE(kScript8), kScript8},
|
||||
{ARRAY_SIZE(kScript9), kScript9}, {ARRAY_SIZE(kScript10), kScript10},
|
||||
};
|
||||
static constexpr int kNumTestScripts = ARRAY_SIZE(kTestScript);
|
||||
|
||||
void SetScanDecompressParams(const DecompressParams& dparams,
|
||||
j_decompress_ptr cinfo, int scan_number) {
|
||||
const ScanDecompressParams* sparams = nullptr;
|
||||
for (const auto& sp : dparams.scan_params) {
|
||||
if (scan_number <= sp.max_scan_number) {
|
||||
sparams = &sp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sparams == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (dparams.quantize_colors) {
|
||||
cinfo->dither_mode = (J_DITHER_MODE)sparams->dither_mode;
|
||||
if (sparams->color_quant_mode == CQUANT_1PASS) {
|
||||
cinfo->two_pass_quantize = FALSE;
|
||||
cinfo->colormap = nullptr;
|
||||
} else if (sparams->color_quant_mode == CQUANT_2PASS) {
|
||||
JXL_CHECK(cinfo->out_color_space == JCS_RGB);
|
||||
cinfo->two_pass_quantize = TRUE;
|
||||
cinfo->colormap = nullptr;
|
||||
} else if (sparams->color_quant_mode == CQUANT_EXTERNAL) {
|
||||
JXL_CHECK(cinfo->out_color_space == JCS_RGB);
|
||||
cinfo->two_pass_quantize = FALSE;
|
||||
bool have_colormap = cinfo->colormap != nullptr;
|
||||
cinfo->actual_number_of_colors = kTestColorMapNumColors;
|
||||
cinfo->colormap = (*cinfo->mem->alloc_sarray)(
|
||||
reinterpret_cast<j_common_ptr>(cinfo), JPOOL_IMAGE,
|
||||
cinfo->actual_number_of_colors, 3);
|
||||
jxl::msan::UnpoisonMemory(cinfo->colormap, 3 * sizeof(JSAMPROW));
|
||||
for (int i = 0; i < kTestColorMapNumColors; ++i) {
|
||||
cinfo->colormap[0][i] = (kTestColorMap[i] >> 16) & 0xff;
|
||||
cinfo->colormap[1][i] = (kTestColorMap[i] >> 8) & 0xff;
|
||||
cinfo->colormap[2][i] = (kTestColorMap[i] >> 0) & 0xff;
|
||||
}
|
||||
if (have_colormap) {
|
||||
JPEG_API_FN(new_colormap)(cinfo);
|
||||
}
|
||||
} else if (sparams->color_quant_mode == CQUANT_REUSE) {
|
||||
JXL_CHECK(cinfo->out_color_space == JCS_RGB);
|
||||
JXL_CHECK(cinfo->colormap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetDecompressParams(const DecompressParams& dparams,
|
||||
j_decompress_ptr cinfo) {
|
||||
cinfo->do_block_smoothing = dparams.do_block_smoothing;
|
||||
cinfo->do_fancy_upsampling = dparams.do_fancy_upsampling;
|
||||
if (dparams.output_mode == RAW_DATA) {
|
||||
cinfo->raw_data_out = TRUE;
|
||||
}
|
||||
if (dparams.set_out_color_space) {
|
||||
cinfo->out_color_space = (J_COLOR_SPACE)dparams.out_color_space;
|
||||
if (dparams.out_color_space == JCS_UNKNOWN) {
|
||||
cinfo->jpeg_color_space = JCS_UNKNOWN;
|
||||
}
|
||||
}
|
||||
cinfo->scale_num = dparams.scale_num;
|
||||
cinfo->scale_denom = dparams.scale_denom;
|
||||
cinfo->quantize_colors = dparams.quantize_colors;
|
||||
cinfo->desired_number_of_colors = dparams.desired_number_of_colors;
|
||||
if (!dparams.scan_params.empty()) {
|
||||
if (cinfo->buffered_image) {
|
||||
for (const auto& sparams : dparams.scan_params) {
|
||||
if (sparams.color_quant_mode == CQUANT_1PASS) {
|
||||
cinfo->enable_1pass_quant = TRUE;
|
||||
} else if (sparams.color_quant_mode == CQUANT_2PASS) {
|
||||
cinfo->enable_2pass_quant = TRUE;
|
||||
} else if (sparams.color_quant_mode == CQUANT_EXTERNAL) {
|
||||
cinfo->enable_external_quant = TRUE;
|
||||
}
|
||||
}
|
||||
SetScanDecompressParams(dparams, cinfo, 1);
|
||||
} else {
|
||||
SetScanDecompressParams(dparams, cinfo, kLastScan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CheckMarkerPresent(j_decompress_ptr cinfo, uint8_t marker_type) {
|
||||
bool marker_found = false;
|
||||
for (jpeg_saved_marker_ptr marker = cinfo->marker_list; marker != nullptr;
|
||||
marker = marker->next) {
|
||||
jxl::msan::UnpoisonMemory(marker, sizeof(*marker));
|
||||
jxl::msan::UnpoisonMemory(marker->data, marker->data_length);
|
||||
if (marker->marker == marker_type &&
|
||||
marker->data_length == sizeof(kMarkerData) &&
|
||||
memcmp(marker->data, kMarkerData, sizeof(kMarkerData)) == 0) {
|
||||
marker_found = true;
|
||||
}
|
||||
}
|
||||
JXL_CHECK(marker_found);
|
||||
}
|
||||
|
||||
void VerifyHeader(const CompressParams& jparams, j_decompress_ptr cinfo) {
|
||||
if (jparams.set_jpeg_colorspace) {
|
||||
JXL_CHECK(cinfo->jpeg_color_space == jparams.jpeg_color_space);
|
||||
}
|
||||
if (jparams.override_JFIF >= 0) {
|
||||
JXL_CHECK(cinfo->saw_JFIF_marker == jparams.override_JFIF);
|
||||
}
|
||||
if (jparams.override_Adobe >= 0) {
|
||||
JXL_CHECK(cinfo->saw_Adobe_marker == jparams.override_Adobe);
|
||||
}
|
||||
if (jparams.add_marker) {
|
||||
CheckMarkerPresent(cinfo, kSpecialMarker0);
|
||||
CheckMarkerPresent(cinfo, kSpecialMarker1);
|
||||
}
|
||||
jxl::msan::UnpoisonMemory(
|
||||
cinfo->comp_info, cinfo->num_components * sizeof(cinfo->comp_info[0]));
|
||||
int max_h_samp_factor = 1;
|
||||
int max_v_samp_factor = 1;
|
||||
for (int i = 0; i < cinfo->num_components; ++i) {
|
||||
jpeg_component_info* comp = &cinfo->comp_info[i];
|
||||
if (!jparams.comp_ids.empty()) {
|
||||
JXL_CHECK(comp->component_id == jparams.comp_ids[i]);
|
||||
}
|
||||
if (!jparams.h_sampling.empty()) {
|
||||
JXL_CHECK(comp->h_samp_factor == jparams.h_sampling[i]);
|
||||
}
|
||||
if (!jparams.v_sampling.empty()) {
|
||||
JXL_CHECK(comp->v_samp_factor == jparams.v_sampling[i]);
|
||||
}
|
||||
if (!jparams.quant_indexes.empty()) {
|
||||
JXL_CHECK(comp->quant_tbl_no == jparams.quant_indexes[i]);
|
||||
}
|
||||
max_h_samp_factor = std::max(max_h_samp_factor, comp->h_samp_factor);
|
||||
max_v_samp_factor = std::max(max_v_samp_factor, comp->v_samp_factor);
|
||||
}
|
||||
JXL_CHECK(max_h_samp_factor == cinfo->max_h_samp_factor);
|
||||
JXL_CHECK(max_v_samp_factor == cinfo->max_v_samp_factor);
|
||||
int referenced_tables[NUM_QUANT_TBLS] = {};
|
||||
for (int i = 0; i < cinfo->num_components; ++i) {
|
||||
jpeg_component_info* comp = &cinfo->comp_info[i];
|
||||
JXL_CHECK(comp->width_in_blocks ==
|
||||
DivCeil(cinfo->image_width * comp->h_samp_factor,
|
||||
max_h_samp_factor * DCTSIZE));
|
||||
JXL_CHECK(comp->height_in_blocks ==
|
||||
DivCeil(cinfo->image_height * comp->v_samp_factor,
|
||||
max_v_samp_factor * DCTSIZE));
|
||||
referenced_tables[comp->quant_tbl_no] = 1;
|
||||
}
|
||||
for (const auto& table : jparams.quant_tables) {
|
||||
JQUANT_TBL* quant_table = cinfo->quant_tbl_ptrs[table.slot_idx];
|
||||
if (!referenced_tables[table.slot_idx]) {
|
||||
JXL_CHECK(quant_table == nullptr);
|
||||
continue;
|
||||
}
|
||||
JXL_CHECK(quant_table != nullptr);
|
||||
jxl::msan::UnpoisonMemory(quant_table, sizeof(*quant_table));
|
||||
for (int k = 0; k < DCTSIZE2; ++k) {
|
||||
JXL_CHECK(quant_table->quantval[k] == table.quantval[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VerifyScanHeader(const CompressParams& jparams, j_decompress_ptr cinfo) {
|
||||
JXL_CHECK(cinfo->input_scan_number > 0);
|
||||
if (cinfo->progressive_mode) {
|
||||
JXL_CHECK(cinfo->Ss != 0 || cinfo->Se != 63);
|
||||
} else {
|
||||
JXL_CHECK(cinfo->Ss == 0 && cinfo->Se == 63);
|
||||
}
|
||||
if (jparams.progressive_mode > 2) {
|
||||
JXL_CHECK(jparams.progressive_mode < 3 + kNumTestScripts);
|
||||
const ScanScript& script = kTestScript[jparams.progressive_mode - 3];
|
||||
JXL_CHECK(cinfo->input_scan_number <= script.num_scans);
|
||||
const jpeg_scan_info& scan = script.scans[cinfo->input_scan_number - 1];
|
||||
JXL_CHECK(cinfo->comps_in_scan == scan.comps_in_scan);
|
||||
for (int i = 0; i < cinfo->comps_in_scan; ++i) {
|
||||
JXL_CHECK(cinfo->cur_comp_info[i]->component_index ==
|
||||
scan.component_index[i]);
|
||||
}
|
||||
JXL_CHECK(cinfo->Ss == scan.Ss);
|
||||
JXL_CHECK(cinfo->Se == scan.Se);
|
||||
JXL_CHECK(cinfo->Ah == scan.Ah);
|
||||
JXL_CHECK(cinfo->Al == scan.Al);
|
||||
}
|
||||
if (jparams.restart_interval > 0) {
|
||||
JXL_CHECK(cinfo->restart_interval == jparams.restart_interval);
|
||||
} else if (jparams.restart_in_rows > 0) {
|
||||
JXL_CHECK(cinfo->restart_interval ==
|
||||
jparams.restart_in_rows * cinfo->MCUs_per_row);
|
||||
}
|
||||
if (jparams.progressive_mode == 0 && jparams.optimize_coding == 0) {
|
||||
if (cinfo->jpeg_color_space == JCS_RGB) {
|
||||
JXL_CHECK(cinfo->comp_info[0].dc_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[1].dc_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[2].dc_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[0].ac_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[1].ac_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[2].ac_tbl_no == 0);
|
||||
} else if (cinfo->jpeg_color_space == JCS_YCbCr) {
|
||||
JXL_CHECK(cinfo->comp_info[0].dc_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[1].dc_tbl_no == 1);
|
||||
JXL_CHECK(cinfo->comp_info[2].dc_tbl_no == 1);
|
||||
JXL_CHECK(cinfo->comp_info[0].ac_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[1].ac_tbl_no == 1);
|
||||
JXL_CHECK(cinfo->comp_info[2].ac_tbl_no == 1);
|
||||
} else if (cinfo->jpeg_color_space == JCS_CMYK) {
|
||||
JXL_CHECK(cinfo->comp_info[0].dc_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[1].dc_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[2].dc_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[3].dc_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[0].ac_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[1].ac_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[2].ac_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[3].ac_tbl_no == 0);
|
||||
} else if (cinfo->jpeg_color_space == JCS_YCCK) {
|
||||
JXL_CHECK(cinfo->comp_info[0].dc_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[1].dc_tbl_no == 1);
|
||||
JXL_CHECK(cinfo->comp_info[2].dc_tbl_no == 1);
|
||||
JXL_CHECK(cinfo->comp_info[3].dc_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[0].ac_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[1].ac_tbl_no == 1);
|
||||
JXL_CHECK(cinfo->comp_info[2].ac_tbl_no == 1);
|
||||
JXL_CHECK(cinfo->comp_info[3].ac_tbl_no == 0);
|
||||
}
|
||||
if (jparams.use_flat_dc_luma_code) {
|
||||
JHUFF_TBL* tbl = cinfo->dc_huff_tbl_ptrs[0];
|
||||
jxl::msan::UnpoisonMemory(tbl, sizeof(*tbl));
|
||||
for (int i = 0; i < 15; ++i) {
|
||||
JXL_CHECK(tbl->huffval[i] == i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UnmapColors(uint8_t* row, size_t xsize, int components,
|
||||
JSAMPARRAY colormap, size_t num_colors) {
|
||||
JXL_CHECK(colormap != nullptr);
|
||||
std::vector<uint8_t> tmp(xsize * components);
|
||||
for (size_t x = 0; x < xsize; ++x) {
|
||||
JXL_CHECK(row[x] < num_colors);
|
||||
for (int c = 0; c < components; ++c) {
|
||||
tmp[x * components + c] = colormap[c][row[x]];
|
||||
}
|
||||
}
|
||||
memcpy(row, tmp.data(), tmp.size());
|
||||
}
|
||||
|
||||
void CopyCoefficients(j_decompress_ptr cinfo, jvirt_barray_ptr* coef_arrays,
|
||||
TestImage* output) {
|
||||
output->xsize = cinfo->image_width;
|
||||
output->ysize = cinfo->image_height;
|
||||
output->components = cinfo->num_components;
|
||||
output->color_space = cinfo->out_color_space;
|
||||
j_common_ptr comptr = reinterpret_cast<j_common_ptr>(cinfo);
|
||||
for (int c = 0; c < cinfo->num_components; ++c) {
|
||||
jpeg_component_info* comp = &cinfo->comp_info[c];
|
||||
std::vector<JCOEF> coeffs(comp->width_in_blocks * comp->height_in_blocks *
|
||||
DCTSIZE2);
|
||||
for (size_t by = 0; by < comp->height_in_blocks; ++by) {
|
||||
JBLOCKARRAY ba = (*cinfo->mem->access_virt_barray)(comptr, coef_arrays[c],
|
||||
by, 1, true);
|
||||
size_t stride = comp->width_in_blocks * sizeof(JBLOCK);
|
||||
size_t offset = by * comp->width_in_blocks * DCTSIZE2;
|
||||
memcpy(&coeffs[offset], ba[0], stride);
|
||||
}
|
||||
output->coeffs.emplace_back(std::move(coeffs));
|
||||
}
|
||||
}
|
487
third_party/jpeg-xl/lib/jpegli/test_utils.cc
vendored
487
third_party/jpeg-xl/lib/jpegli/test_utils.cc
vendored
@ -21,6 +21,10 @@
|
||||
|
||||
namespace jpegli {
|
||||
|
||||
#define JPEG_API_FN(name) jpegli_##name
|
||||
#include "lib/jpegli/test_utils-inl.h"
|
||||
#undef JPEG_API_FN
|
||||
|
||||
#if defined(TEST_DATA_PATH)
|
||||
std::string GetTestDataPath(const std::string& filename) {
|
||||
return std::string(TEST_DATA_PATH "/") + filename;
|
||||
@ -211,7 +215,7 @@ std::ostream& operator<<(std::ostream& os, const TestImage& input) {
|
||||
os << input.xsize << "x" << input.ysize;
|
||||
os << IOMethodName(input.data_type, input.endianness);
|
||||
if (input.color_space != JCS_RGB) {
|
||||
os << "InputColor" << ColorSpaceName(input.color_space);
|
||||
os << "InputColor" << ColorSpaceName((J_COLOR_SPACE)input.color_space);
|
||||
}
|
||||
if (input.color_space == JCS_UNKNOWN) {
|
||||
os << input.components;
|
||||
@ -223,7 +227,8 @@ std::ostream& operator<<(std::ostream& os, const CompressParams& jparams) {
|
||||
os << "Q" << jparams.quality;
|
||||
os << SamplingId(jparams);
|
||||
if (jparams.set_jpeg_colorspace) {
|
||||
os << "JpegColor" << ColorSpaceName(jparams.jpeg_color_space);
|
||||
os << "JpegColor"
|
||||
<< ColorSpaceName((J_COLOR_SPACE)jparams.jpeg_color_space);
|
||||
}
|
||||
if (!jparams.comp_ids.empty()) {
|
||||
os << "CID";
|
||||
@ -406,7 +411,7 @@ void GeneratePixels(TestImage* img) {
|
||||
size_t in_stride = xsize * in_bytes_per_pixel;
|
||||
size_t x0 = (xsize - img->xsize) / 2;
|
||||
size_t y0 = (ysize - img->ysize) / 2;
|
||||
SetNumChannels(img->color_space, &img->components);
|
||||
SetNumChannels((J_COLOR_SPACE)img->color_space, &img->components);
|
||||
size_t out_bytes_per_pixel =
|
||||
jpegli_bytes_per_sample(img->data_type) * img->components;
|
||||
size_t out_stride = img->xsize * out_bytes_per_pixel;
|
||||
@ -420,8 +425,9 @@ void GeneratePixels(TestImage* img) {
|
||||
size_t x = x0 + ix;
|
||||
size_t idx_in = y * in_stride + x * in_bytes_per_pixel;
|
||||
size_t idx_out = iy * out_stride + ix * out_bytes_per_pixel;
|
||||
ConvertPixel(&pixels[idx_in], &img->pixels[idx_out], img->color_space,
|
||||
img->components, img->data_type, swap_endianness);
|
||||
ConvertPixel(&pixels[idx_in], &img->pixels[idx_out],
|
||||
(J_COLOR_SPACE)img->color_space, img->components,
|
||||
img->data_type, swap_endianness);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -485,7 +491,7 @@ void EncodeWithJpegli(const TestImage& input, const CompressParams& jparams,
|
||||
jpegli_set_progressive_level(cinfo, 0);
|
||||
}
|
||||
jpegli_set_defaults(cinfo);
|
||||
cinfo->in_color_space = input.color_space;
|
||||
cinfo->in_color_space = (J_COLOR_SPACE)input.color_space;
|
||||
jpegli_default_colorspace(cinfo);
|
||||
if (jparams.override_JFIF >= 0) {
|
||||
cinfo->write_JFIF_header = jparams.override_JFIF;
|
||||
@ -494,7 +500,7 @@ void EncodeWithJpegli(const TestImage& input, const CompressParams& jparams,
|
||||
cinfo->write_Adobe_marker = jparams.override_Adobe;
|
||||
}
|
||||
if (jparams.set_jpeg_colorspace) {
|
||||
jpegli_set_colorspace(cinfo, jparams.jpeg_color_space);
|
||||
jpegli_set_colorspace(cinfo, (J_COLOR_SPACE)jparams.jpeg_color_space);
|
||||
}
|
||||
if (!jparams.comp_ids.empty()) {
|
||||
for (int c = 0; c < cinfo->num_components; ++c) {
|
||||
@ -672,472 +678,7 @@ bool EncodeWithJpegli(const TestImage& input, const CompressParams& jparams,
|
||||
return success;
|
||||
}
|
||||
|
||||
void SetScanDecompressParams(const DecompressParams& dparams,
|
||||
j_decompress_ptr cinfo, int scan_number,
|
||||
bool is_jpegli) {
|
||||
const ScanDecompressParams* sparams = nullptr;
|
||||
for (const auto& sp : dparams.scan_params) {
|
||||
if (scan_number <= sp.max_scan_number) {
|
||||
sparams = &sp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sparams == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (dparams.quantize_colors) {
|
||||
cinfo->dither_mode = sparams->dither_mode;
|
||||
if (sparams->color_quant_mode == CQUANT_1PASS) {
|
||||
cinfo->two_pass_quantize = FALSE;
|
||||
cinfo->colormap = nullptr;
|
||||
} else if (sparams->color_quant_mode == CQUANT_2PASS) {
|
||||
JXL_CHECK(cinfo->out_color_space = JCS_RGB);
|
||||
cinfo->two_pass_quantize = TRUE;
|
||||
cinfo->colormap = nullptr;
|
||||
} else if (sparams->color_quant_mode == CQUANT_EXTERNAL) {
|
||||
JXL_CHECK(cinfo->out_color_space = JCS_RGB);
|
||||
cinfo->two_pass_quantize = FALSE;
|
||||
bool have_colormap = cinfo->colormap != nullptr;
|
||||
cinfo->actual_number_of_colors = kTestColorMapNumColors;
|
||||
cinfo->colormap = (*cinfo->mem->alloc_sarray)(
|
||||
reinterpret_cast<j_common_ptr>(cinfo), JPOOL_IMAGE,
|
||||
cinfo->actual_number_of_colors, 3);
|
||||
jxl::msan::UnpoisonMemory(cinfo->colormap, 3 * sizeof(JSAMPROW));
|
||||
for (int i = 0; i < kTestColorMapNumColors; ++i) {
|
||||
cinfo->colormap[0][i] = (kTestColorMap[i] >> 16) & 0xff;
|
||||
cinfo->colormap[1][i] = (kTestColorMap[i] >> 8) & 0xff;
|
||||
cinfo->colormap[2][i] = (kTestColorMap[i] >> 0) & 0xff;
|
||||
}
|
||||
if (have_colormap) {
|
||||
if (is_jpegli) {
|
||||
jpegli_new_colormap(cinfo);
|
||||
} else {
|
||||
jpeg_new_colormap(cinfo);
|
||||
}
|
||||
}
|
||||
} else if (sparams->color_quant_mode == CQUANT_REUSE) {
|
||||
JXL_CHECK(cinfo->out_color_space = JCS_RGB);
|
||||
JXL_CHECK(cinfo->colormap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetDecompressParams(const DecompressParams& dparams,
|
||||
j_decompress_ptr cinfo, bool is_jpegli) {
|
||||
cinfo->do_block_smoothing = dparams.do_block_smoothing;
|
||||
cinfo->do_fancy_upsampling = dparams.do_fancy_upsampling;
|
||||
if (dparams.output_mode == RAW_DATA) {
|
||||
cinfo->raw_data_out = TRUE;
|
||||
}
|
||||
if (dparams.set_out_color_space) {
|
||||
cinfo->out_color_space = dparams.out_color_space;
|
||||
if (dparams.out_color_space == JCS_UNKNOWN) {
|
||||
cinfo->jpeg_color_space = JCS_UNKNOWN;
|
||||
}
|
||||
}
|
||||
cinfo->scale_num = dparams.scale_num;
|
||||
cinfo->scale_denom = dparams.scale_denom;
|
||||
cinfo->quantize_colors = dparams.quantize_colors;
|
||||
cinfo->desired_number_of_colors = dparams.desired_number_of_colors;
|
||||
if (!dparams.scan_params.empty()) {
|
||||
if (cinfo->buffered_image) {
|
||||
for (const auto& sparams : dparams.scan_params) {
|
||||
if (sparams.color_quant_mode == CQUANT_1PASS) {
|
||||
cinfo->enable_1pass_quant = TRUE;
|
||||
} else if (sparams.color_quant_mode == CQUANT_2PASS) {
|
||||
cinfo->enable_2pass_quant = TRUE;
|
||||
} else if (sparams.color_quant_mode == CQUANT_EXTERNAL) {
|
||||
cinfo->enable_external_quant = TRUE;
|
||||
}
|
||||
}
|
||||
SetScanDecompressParams(dparams, cinfo, 1, is_jpegli);
|
||||
} else {
|
||||
SetScanDecompressParams(dparams, cinfo, kLastScan, is_jpegli);
|
||||
}
|
||||
}
|
||||
if (is_jpegli) {
|
||||
jpegli_set_output_format(cinfo, dparams.data_type, dparams.endianness);
|
||||
}
|
||||
}
|
||||
|
||||
void CheckMarkerPresent(j_decompress_ptr cinfo, uint8_t marker_type) {
|
||||
bool marker_found = false;
|
||||
for (jpeg_saved_marker_ptr marker = cinfo->marker_list; marker != nullptr;
|
||||
marker = marker->next) {
|
||||
jxl::msan::UnpoisonMemory(marker, sizeof(*marker));
|
||||
jxl::msan::UnpoisonMemory(marker->data, marker->data_length);
|
||||
if (marker->marker == marker_type &&
|
||||
marker->data_length == sizeof(kMarkerData) &&
|
||||
memcmp(marker->data, kMarkerData, sizeof(kMarkerData)) == 0) {
|
||||
marker_found = true;
|
||||
}
|
||||
}
|
||||
JXL_CHECK(marker_found);
|
||||
}
|
||||
|
||||
void VerifyHeader(const CompressParams& jparams, j_decompress_ptr cinfo) {
|
||||
if (jparams.set_jpeg_colorspace) {
|
||||
JXL_CHECK(cinfo->jpeg_color_space == jparams.jpeg_color_space);
|
||||
}
|
||||
if (jparams.override_JFIF >= 0) {
|
||||
JXL_CHECK(cinfo->saw_JFIF_marker == jparams.override_JFIF);
|
||||
}
|
||||
if (jparams.override_Adobe >= 0) {
|
||||
JXL_CHECK(cinfo->saw_Adobe_marker == jparams.override_Adobe);
|
||||
}
|
||||
if (jparams.add_marker) {
|
||||
CheckMarkerPresent(cinfo, kSpecialMarker0);
|
||||
CheckMarkerPresent(cinfo, kSpecialMarker1);
|
||||
}
|
||||
jxl::msan::UnpoisonMemory(
|
||||
cinfo->comp_info, cinfo->num_components * sizeof(cinfo->comp_info[0]));
|
||||
int max_h_samp_factor = 1;
|
||||
int max_v_samp_factor = 1;
|
||||
for (int i = 0; i < cinfo->num_components; ++i) {
|
||||
jpeg_component_info* comp = &cinfo->comp_info[i];
|
||||
if (!jparams.comp_ids.empty()) {
|
||||
JXL_CHECK(comp->component_id == jparams.comp_ids[i]);
|
||||
}
|
||||
if (!jparams.h_sampling.empty()) {
|
||||
JXL_CHECK(comp->h_samp_factor == jparams.h_sampling[i]);
|
||||
}
|
||||
if (!jparams.v_sampling.empty()) {
|
||||
JXL_CHECK(comp->v_samp_factor == jparams.v_sampling[i]);
|
||||
}
|
||||
if (!jparams.quant_indexes.empty()) {
|
||||
JXL_CHECK(comp->quant_tbl_no == jparams.quant_indexes[i]);
|
||||
}
|
||||
max_h_samp_factor = std::max(max_h_samp_factor, comp->h_samp_factor);
|
||||
max_v_samp_factor = std::max(max_v_samp_factor, comp->v_samp_factor);
|
||||
}
|
||||
JXL_CHECK(max_h_samp_factor == cinfo->max_h_samp_factor);
|
||||
JXL_CHECK(max_v_samp_factor == cinfo->max_v_samp_factor);
|
||||
int referenced_tables[NUM_QUANT_TBLS] = {};
|
||||
for (int i = 0; i < cinfo->num_components; ++i) {
|
||||
jpeg_component_info* comp = &cinfo->comp_info[i];
|
||||
JXL_CHECK(comp->width_in_blocks ==
|
||||
DivCeil(cinfo->image_width * comp->h_samp_factor,
|
||||
max_h_samp_factor * DCTSIZE));
|
||||
JXL_CHECK(comp->height_in_blocks ==
|
||||
DivCeil(cinfo->image_height * comp->v_samp_factor,
|
||||
max_v_samp_factor * DCTSIZE));
|
||||
referenced_tables[comp->quant_tbl_no] = 1;
|
||||
}
|
||||
for (const auto& table : jparams.quant_tables) {
|
||||
JQUANT_TBL* quant_table = cinfo->quant_tbl_ptrs[table.slot_idx];
|
||||
if (!referenced_tables[table.slot_idx]) {
|
||||
JXL_CHECK(quant_table == nullptr);
|
||||
continue;
|
||||
}
|
||||
JXL_CHECK(quant_table != nullptr);
|
||||
jxl::msan::UnpoisonMemory(quant_table, sizeof(*quant_table));
|
||||
for (int k = 0; k < DCTSIZE2; ++k) {
|
||||
JXL_CHECK(quant_table->quantval[k] == table.quantval[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VerifyScanHeader(const CompressParams& jparams, j_decompress_ptr cinfo) {
|
||||
JXL_CHECK(cinfo->input_scan_number > 0);
|
||||
if (cinfo->progressive_mode) {
|
||||
JXL_CHECK(cinfo->Ss != 0 || cinfo->Se != 63);
|
||||
} else {
|
||||
JXL_CHECK(cinfo->Ss == 0 && cinfo->Se == 63);
|
||||
}
|
||||
if (jparams.progressive_mode > 2) {
|
||||
JXL_CHECK(jparams.progressive_mode < 3 + kNumTestScripts);
|
||||
const ScanScript& script = kTestScript[jparams.progressive_mode - 3];
|
||||
JXL_CHECK(cinfo->input_scan_number <= script.num_scans);
|
||||
const jpeg_scan_info& scan = script.scans[cinfo->input_scan_number - 1];
|
||||
JXL_CHECK(cinfo->comps_in_scan == scan.comps_in_scan);
|
||||
for (int i = 0; i < cinfo->comps_in_scan; ++i) {
|
||||
JXL_CHECK(cinfo->cur_comp_info[i]->component_index ==
|
||||
scan.component_index[i]);
|
||||
}
|
||||
JXL_CHECK(cinfo->Ss == scan.Ss);
|
||||
JXL_CHECK(cinfo->Se == scan.Se);
|
||||
JXL_CHECK(cinfo->Ah == scan.Ah);
|
||||
JXL_CHECK(cinfo->Al == scan.Al);
|
||||
}
|
||||
if (jparams.restart_interval > 0) {
|
||||
JXL_CHECK(cinfo->restart_interval == jparams.restart_interval);
|
||||
} else if (jparams.restart_in_rows > 0) {
|
||||
JXL_CHECK(cinfo->restart_interval ==
|
||||
jparams.restart_in_rows * cinfo->MCUs_per_row);
|
||||
}
|
||||
if (jparams.progressive_mode == 0 && jparams.optimize_coding == 0) {
|
||||
if (cinfo->jpeg_color_space == JCS_RGB) {
|
||||
JXL_CHECK(cinfo->comp_info[0].dc_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[1].dc_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[2].dc_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[0].ac_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[1].ac_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[2].ac_tbl_no == 0);
|
||||
} else if (cinfo->jpeg_color_space == JCS_YCbCr) {
|
||||
JXL_CHECK(cinfo->comp_info[0].dc_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[1].dc_tbl_no == 1);
|
||||
JXL_CHECK(cinfo->comp_info[2].dc_tbl_no == 1);
|
||||
JXL_CHECK(cinfo->comp_info[0].ac_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[1].ac_tbl_no == 1);
|
||||
JXL_CHECK(cinfo->comp_info[2].ac_tbl_no == 1);
|
||||
} else if (cinfo->jpeg_color_space == JCS_CMYK) {
|
||||
JXL_CHECK(cinfo->comp_info[0].dc_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[1].dc_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[2].dc_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[3].dc_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[0].ac_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[1].ac_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[2].ac_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[3].ac_tbl_no == 0);
|
||||
} else if (cinfo->jpeg_color_space == JCS_YCCK) {
|
||||
JXL_CHECK(cinfo->comp_info[0].dc_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[1].dc_tbl_no == 1);
|
||||
JXL_CHECK(cinfo->comp_info[2].dc_tbl_no == 1);
|
||||
JXL_CHECK(cinfo->comp_info[3].dc_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[0].ac_tbl_no == 0);
|
||||
JXL_CHECK(cinfo->comp_info[1].ac_tbl_no == 1);
|
||||
JXL_CHECK(cinfo->comp_info[2].ac_tbl_no == 1);
|
||||
JXL_CHECK(cinfo->comp_info[3].ac_tbl_no == 0);
|
||||
}
|
||||
if (jparams.use_flat_dc_luma_code) {
|
||||
JHUFF_TBL* tbl = cinfo->dc_huff_tbl_ptrs[0];
|
||||
jxl::msan::UnpoisonMemory(tbl, sizeof(*tbl));
|
||||
for (int i = 0; i < 15; ++i) {
|
||||
JXL_CHECK(tbl->huffval[i] == i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UnmapColors(uint8_t* row, size_t xsize, int components,
|
||||
JSAMPARRAY colormap, size_t num_colors) {
|
||||
JXL_CHECK(colormap != nullptr);
|
||||
std::vector<uint8_t> tmp(xsize * components);
|
||||
for (size_t x = 0; x < xsize; ++x) {
|
||||
JXL_CHECK(row[x] < num_colors);
|
||||
for (int c = 0; c < components; ++c) {
|
||||
tmp[x * components + c] = colormap[c][row[x]];
|
||||
}
|
||||
}
|
||||
memcpy(row, tmp.data(), tmp.size());
|
||||
}
|
||||
|
||||
void ReadOutputPass(j_decompress_ptr cinfo, const DecompressParams& dparams,
|
||||
TestImage* output) {
|
||||
JDIMENSION xoffset = 0;
|
||||
JDIMENSION yoffset = 0;
|
||||
JDIMENSION xsize_cropped = cinfo->output_width;
|
||||
JDIMENSION ysize_cropped = cinfo->output_height;
|
||||
if (dparams.crop_output) {
|
||||
xoffset = xsize_cropped = cinfo->output_width / 3;
|
||||
yoffset = ysize_cropped = cinfo->output_height / 3;
|
||||
jpeg_crop_scanline(cinfo, &xoffset, &xsize_cropped);
|
||||
JXL_CHECK(xsize_cropped == cinfo->output_width);
|
||||
}
|
||||
output->xsize = xsize_cropped;
|
||||
output->ysize = ysize_cropped;
|
||||
output->components = cinfo->out_color_components;
|
||||
if (cinfo->quantize_colors) {
|
||||
jxl::msan::UnpoisonMemory(cinfo->colormap, cinfo->out_color_components *
|
||||
sizeof(cinfo->colormap[0]));
|
||||
for (int c = 0; c < cinfo->out_color_components; ++c) {
|
||||
jxl::msan::UnpoisonMemory(
|
||||
cinfo->colormap[c],
|
||||
cinfo->actual_number_of_colors * sizeof(cinfo->colormap[c][0]));
|
||||
}
|
||||
}
|
||||
if (!cinfo->raw_data_out) {
|
||||
size_t stride = output->xsize * output->components;
|
||||
output->pixels.resize(output->ysize * stride);
|
||||
output->color_space = cinfo->out_color_space;
|
||||
if (yoffset > 0) {
|
||||
jpeg_skip_scanlines(cinfo, yoffset);
|
||||
}
|
||||
for (size_t y = 0; y < output->ysize; ++y) {
|
||||
JSAMPROW rows[] = {
|
||||
reinterpret_cast<JSAMPLE*>(&output->pixels[y * stride])};
|
||||
JXL_CHECK(1 == jpeg_read_scanlines(cinfo, rows, 1));
|
||||
jxl::msan::UnpoisonMemory(
|
||||
rows[0], sizeof(JSAMPLE) * cinfo->output_components * output->xsize);
|
||||
if (cinfo->quantize_colors) {
|
||||
UnmapColors(rows[0], cinfo->output_width, cinfo->out_color_components,
|
||||
cinfo->colormap, cinfo->actual_number_of_colors);
|
||||
}
|
||||
}
|
||||
if (cinfo->output_scanline < cinfo->output_height) {
|
||||
jpeg_skip_scanlines(cinfo, cinfo->output_height - cinfo->output_scanline);
|
||||
}
|
||||
} else {
|
||||
output->color_space = cinfo->jpeg_color_space;
|
||||
for (int c = 0; c < cinfo->num_components; ++c) {
|
||||
size_t xsize = cinfo->comp_info[c].width_in_blocks * DCTSIZE;
|
||||
size_t ysize = cinfo->comp_info[c].height_in_blocks * DCTSIZE;
|
||||
std::vector<uint8_t> plane(ysize * xsize);
|
||||
output->raw_data.emplace_back(std::move(plane));
|
||||
}
|
||||
while (cinfo->output_scanline < cinfo->output_height) {
|
||||
size_t iMCU_height = cinfo->max_v_samp_factor * DCTSIZE;
|
||||
JXL_CHECK(cinfo->output_scanline == cinfo->output_iMCU_row * iMCU_height);
|
||||
std::vector<std::vector<JSAMPROW>> rowdata(cinfo->num_components);
|
||||
std::vector<JSAMPARRAY> data(cinfo->num_components);
|
||||
for (int c = 0; c < cinfo->num_components; ++c) {
|
||||
size_t xsize = cinfo->comp_info[c].width_in_blocks * DCTSIZE;
|
||||
size_t ysize = cinfo->comp_info[c].height_in_blocks * DCTSIZE;
|
||||
size_t num_lines = cinfo->comp_info[c].v_samp_factor * DCTSIZE;
|
||||
rowdata[c].resize(num_lines);
|
||||
size_t y0 = cinfo->output_iMCU_row * num_lines;
|
||||
for (size_t i = 0; i < num_lines; ++i) {
|
||||
rowdata[c][i] =
|
||||
y0 + i < ysize ? &output->raw_data[c][(y0 + i) * xsize] : nullptr;
|
||||
}
|
||||
data[c] = &rowdata[c][0];
|
||||
}
|
||||
JXL_CHECK(iMCU_height ==
|
||||
jpeg_read_raw_data(cinfo, &data[0], iMCU_height));
|
||||
}
|
||||
}
|
||||
JXL_CHECK(cinfo->total_iMCU_rows ==
|
||||
DivCeil(cinfo->image_height, cinfo->max_v_samp_factor * DCTSIZE));
|
||||
}
|
||||
|
||||
void CopyCoefficients(j_decompress_ptr cinfo, jvirt_barray_ptr* coef_arrays,
|
||||
TestImage* output) {
|
||||
output->xsize = cinfo->image_width;
|
||||
output->ysize = cinfo->image_height;
|
||||
output->components = cinfo->num_components;
|
||||
output->color_space = cinfo->out_color_space;
|
||||
j_common_ptr comptr = reinterpret_cast<j_common_ptr>(cinfo);
|
||||
for (int c = 0; c < cinfo->num_components; ++c) {
|
||||
jpeg_component_info* comp = &cinfo->comp_info[c];
|
||||
std::vector<JCOEF> coeffs(comp->width_in_blocks * comp->height_in_blocks *
|
||||
DCTSIZE2);
|
||||
for (size_t by = 0; by < comp->height_in_blocks; ++by) {
|
||||
JBLOCKARRAY ba = (*cinfo->mem->access_virt_barray)(comptr, coef_arrays[c],
|
||||
by, 1, true);
|
||||
size_t stride = comp->width_in_blocks * sizeof(JBLOCK);
|
||||
size_t offset = by * comp->width_in_blocks * DCTSIZE2;
|
||||
memcpy(&coeffs[offset], ba[0], stride);
|
||||
}
|
||||
output->coeffs.emplace_back(std::move(coeffs));
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
jpeg_decompress_struct cinfo = {};
|
||||
const auto try_catch_block = [&]() {
|
||||
ERROR_HANDLER_SETUP(jpeg);
|
||||
jpeg_create_decompress(&cinfo);
|
||||
jpeg_mem_src(&cinfo, compressed.data(), compressed.size());
|
||||
if (jparams.add_marker) {
|
||||
jpeg_save_markers(&cinfo, kSpecialMarker0, 0xffff);
|
||||
jpeg_save_markers(&cinfo, kSpecialMarker1, 0xffff);
|
||||
}
|
||||
JXL_CHECK(JPEG_REACHED_SOS ==
|
||||
jpeg_read_header(&cinfo, /*require_image=*/TRUE));
|
||||
cinfo.buffered_image = TRUE;
|
||||
SetDecompressParams(dparams, &cinfo, /*is_jpegli=*/false);
|
||||
VerifyHeader(jparams, &cinfo);
|
||||
JXL_CHECK(jpeg_start_decompress(&cinfo));
|
||||
// start decompress should not read the whole input in buffered image mode
|
||||
JXL_CHECK(!jpeg_input_complete(&cinfo));
|
||||
JXL_CHECK(cinfo.output_scan_number == 0);
|
||||
int sos_marker_cnt = 1; // read header reads the first SOS marker
|
||||
while (!jpeg_input_complete(&cinfo)) {
|
||||
JXL_CHECK(cinfo.input_scan_number == sos_marker_cnt);
|
||||
if (dparams.skip_scans && (cinfo.input_scan_number % 2) != 1) {
|
||||
int result = JPEG_SUSPENDED;
|
||||
while (result != JPEG_REACHED_SOS && result != JPEG_REACHED_EOI) {
|
||||
result = jpeg_consume_input(&cinfo);
|
||||
}
|
||||
if (result == JPEG_REACHED_SOS) ++sos_marker_cnt;
|
||||
continue;
|
||||
}
|
||||
SetScanDecompressParams(dparams, &cinfo, cinfo.input_scan_number,
|
||||
/*is_jpegli=*/false);
|
||||
JXL_CHECK(jpeg_start_output(&cinfo, cinfo.input_scan_number));
|
||||
// start output sets output_scan_number, but does not change
|
||||
// input_scan_number
|
||||
JXL_CHECK(cinfo.output_scan_number == cinfo.input_scan_number);
|
||||
JXL_CHECK(cinfo.input_scan_number == sos_marker_cnt);
|
||||
VerifyScanHeader(jparams, &cinfo);
|
||||
TestImage output;
|
||||
ReadOutputPass(&cinfo, dparams, &output);
|
||||
output_progression->emplace_back(std::move(output));
|
||||
// read scanlines/read raw data does not change input/output scan number
|
||||
if (!cinfo.progressive_mode) {
|
||||
JXL_CHECK(cinfo.input_scan_number == sos_marker_cnt);
|
||||
JXL_CHECK(cinfo.output_scan_number == cinfo.input_scan_number);
|
||||
}
|
||||
JXL_CHECK(jpeg_finish_output(&cinfo));
|
||||
++sos_marker_cnt; // finish output reads the next SOS marker or EOI
|
||||
if (dparams.output_mode == COEFFICIENTS) {
|
||||
jvirt_barray_ptr* coef_arrays = jpeg_read_coefficients(&cinfo);
|
||||
JXL_CHECK(coef_arrays != nullptr);
|
||||
CopyCoefficients(&cinfo, coef_arrays, &output_progression->back());
|
||||
}
|
||||
}
|
||||
JXL_CHECK(jpeg_finish_decompress(&cinfo));
|
||||
return true;
|
||||
};
|
||||
JXL_CHECK(try_catch_block());
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
}
|
||||
|
||||
void DecodeWithLibjpeg(const CompressParams& jparams,
|
||||
const DecompressParams& dparams, j_decompress_ptr cinfo,
|
||||
TestImage* output) {
|
||||
if (jparams.add_marker) {
|
||||
jpeg_save_markers(cinfo, kSpecialMarker0, 0xffff);
|
||||
jpeg_save_markers(cinfo, kSpecialMarker1, 0xffff);
|
||||
}
|
||||
if (!jparams.icc.empty()) {
|
||||
jpeg_save_markers(cinfo, JPEG_APP0 + 2, 0xffff);
|
||||
}
|
||||
JXL_CHECK(JPEG_REACHED_SOS ==
|
||||
jpeg_read_header(cinfo, /*require_image=*/TRUE));
|
||||
if (!jparams.icc.empty()) {
|
||||
uint8_t* icc_data = nullptr;
|
||||
unsigned int icc_len;
|
||||
JXL_CHECK(jpeg_read_icc_profile(cinfo, &icc_data, &icc_len));
|
||||
JXL_CHECK(icc_data);
|
||||
jxl::msan::UnpoisonMemory(icc_data, icc_len);
|
||||
JXL_CHECK(0 == memcmp(jparams.icc.data(), icc_data, icc_len));
|
||||
free(icc_data);
|
||||
}
|
||||
SetDecompressParams(dparams, cinfo, /*is_jpegli=*/false);
|
||||
VerifyHeader(jparams, cinfo);
|
||||
if (dparams.output_mode == COEFFICIENTS) {
|
||||
jvirt_barray_ptr* coef_arrays = jpeg_read_coefficients(cinfo);
|
||||
JXL_CHECK(coef_arrays != nullptr);
|
||||
CopyCoefficients(cinfo, coef_arrays, output);
|
||||
} else {
|
||||
JXL_CHECK(jpeg_start_decompress(cinfo));
|
||||
VerifyScanHeader(jparams, cinfo);
|
||||
ReadOutputPass(cinfo, dparams, output);
|
||||
}
|
||||
JXL_CHECK(jpeg_finish_decompress(cinfo));
|
||||
}
|
||||
|
||||
void DecodeWithLibjpeg(const CompressParams& jparams,
|
||||
const DecompressParams& dparams,
|
||||
const std::vector<uint8_t>& compressed,
|
||||
TestImage* output) {
|
||||
jpeg_decompress_struct cinfo = {};
|
||||
const auto try_catch_block = [&]() {
|
||||
ERROR_HANDLER_SETUP(jpeg);
|
||||
jpeg_create_decompress(&cinfo);
|
||||
jpeg_mem_src(&cinfo, compressed.data(), compressed.size());
|
||||
DecodeWithLibjpeg(jparams, dparams, &cinfo, output);
|
||||
return true;
|
||||
};
|
||||
JXL_CHECK(try_catch_block());
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
}
|
||||
int NumTestScanScripts() { return kNumTestScripts; }
|
||||
|
||||
void DumpImage(const TestImage& image, const std::string fn) {
|
||||
JXL_CHECK(image.components == 1 || image.components == 3);
|
||||
|
323
third_party/jpeg-xl/lib/jpegli/test_utils.h
vendored
323
third_party/jpeg-xl/lib/jpegli/test_utils.h
vendored
@ -20,16 +20,11 @@
|
||||
/* clang-format on */
|
||||
|
||||
#include "lib/jpegli/common.h"
|
||||
#include "lib/jpegli/libjpeg_test_util.h"
|
||||
#include "lib/jpegli/test_params.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; \
|
||||
@ -45,316 +40,24 @@ constexpr inline T1 DivCeil(T1 a, T2 b) {
|
||||
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);
|
||||
|
||||
// Sequential non-interleaved.
|
||||
static constexpr jpeg_scan_info kScript1[] = {
|
||||
{1, {0}, 0, 63, 0, 0},
|
||||
{1, {1}, 0, 63, 0, 0},
|
||||
{1, {2}, 0, 63, 0, 0},
|
||||
};
|
||||
// Sequential partially interleaved, chroma first.
|
||||
static constexpr jpeg_scan_info kScript2[] = {
|
||||
{2, {1, 2}, 0, 63, 0, 0},
|
||||
{1, {0}, 0, 63, 0, 0},
|
||||
};
|
||||
|
||||
// Rest of the scan scripts are progressive.
|
||||
|
||||
static constexpr jpeg_scan_info kScript3[] = {
|
||||
// Interleaved full DC.
|
||||
{3, {0, 1, 2}, 0, 0, 0, 0},
|
||||
// Full AC scans.
|
||||
{1, {0}, 1, 63, 0, 0},
|
||||
{1, {1}, 1, 63, 0, 0},
|
||||
{1, {2}, 1, 63, 0, 0},
|
||||
};
|
||||
static constexpr jpeg_scan_info kScript4[] = {
|
||||
// Non-interleaved full DC.
|
||||
{1, {0}, 0, 0, 0, 0},
|
||||
{1, {1}, 0, 0, 0, 0},
|
||||
{1, {2}, 0, 0, 0, 0},
|
||||
// Full AC scans.
|
||||
{1, {0}, 1, 63, 0, 0},
|
||||
{1, {1}, 1, 63, 0, 0},
|
||||
{1, {2}, 1, 63, 0, 0},
|
||||
};
|
||||
static constexpr jpeg_scan_info kScript5[] = {
|
||||
// Partially interleaved full DC, chroma first.
|
||||
{2, {1, 2}, 0, 0, 0, 0},
|
||||
{1, {0}, 0, 0, 0, 0},
|
||||
// AC shifted by 1 bit.
|
||||
{1, {0}, 1, 63, 0, 1},
|
||||
{1, {1}, 1, 63, 0, 1},
|
||||
{1, {2}, 1, 63, 0, 1},
|
||||
// AC refinement scan.
|
||||
{1, {0}, 1, 63, 1, 0},
|
||||
{1, {1}, 1, 63, 1, 0},
|
||||
{1, {2}, 1, 63, 1, 0},
|
||||
};
|
||||
static constexpr jpeg_scan_info kScript6[] = {
|
||||
// Interleaved DC shifted by 2 bits.
|
||||
{3, {0, 1, 2}, 0, 0, 0, 2},
|
||||
// Interleaved DC refinement scans.
|
||||
{3, {0, 1, 2}, 0, 0, 2, 1},
|
||||
{3, {0, 1, 2}, 0, 0, 1, 0},
|
||||
// Full AC scans.
|
||||
{1, {0}, 1, 63, 0, 0},
|
||||
{1, {1}, 1, 63, 0, 0},
|
||||
{1, {2}, 1, 63, 0, 0},
|
||||
};
|
||||
|
||||
static constexpr jpeg_scan_info kScript7[] = {
|
||||
// Non-interleaved DC shifted by 2 bits.
|
||||
{1, {0}, 0, 0, 0, 2},
|
||||
{1, {1}, 0, 0, 0, 2},
|
||||
{1, {2}, 0, 0, 0, 2},
|
||||
// Non-interleaved DC first refinement scans.
|
||||
{1, {0}, 0, 0, 2, 1},
|
||||
{1, {1}, 0, 0, 2, 1},
|
||||
{1, {2}, 0, 0, 2, 1},
|
||||
// Non-interleaved DC second refinement scans.
|
||||
{1, {0}, 0, 0, 1, 0},
|
||||
{1, {1}, 0, 0, 1, 0},
|
||||
{1, {2}, 0, 0, 1, 0},
|
||||
// Full AC scans.
|
||||
{1, {0}, 1, 63, 0, 0},
|
||||
{1, {1}, 1, 63, 0, 0},
|
||||
{1, {2}, 1, 63, 0, 0},
|
||||
};
|
||||
|
||||
static constexpr jpeg_scan_info kScript8[] = {
|
||||
// Partially interleaved DC shifted by 2 bits, chroma first
|
||||
{2, {1, 2}, 0, 0, 0, 2},
|
||||
{1, {0}, 0, 0, 0, 2},
|
||||
// Partially interleaved DC first refinement scans.
|
||||
{2, {0, 2}, 0, 0, 2, 1},
|
||||
{1, {1}, 0, 0, 2, 1},
|
||||
// Partially interleaved DC first refinement scans, chroma first.
|
||||
{2, {1, 2}, 0, 0, 1, 0},
|
||||
{1, {0}, 0, 0, 1, 0},
|
||||
// Full AC scans.
|
||||
{1, {0}, 1, 63, 0, 0},
|
||||
{1, {1}, 1, 63, 0, 0},
|
||||
{1, {2}, 1, 63, 0, 0},
|
||||
};
|
||||
|
||||
static constexpr jpeg_scan_info kScript9[] = {
|
||||
// Interleaved full DC.
|
||||
{3, {0, 1, 2}, 0, 0, 0, 0},
|
||||
// AC scans for component 0
|
||||
// shifted by 1 bit, two spectral ranges
|
||||
{1, {0}, 1, 6, 0, 1},
|
||||
{1, {0}, 7, 63, 0, 1},
|
||||
// refinement scan, full
|
||||
{1, {0}, 1, 63, 1, 0},
|
||||
// AC scans for component 1
|
||||
// shifted by 1 bit, full
|
||||
{1, {1}, 1, 63, 0, 1},
|
||||
// refinement scan, two spectral ranges
|
||||
{1, {1}, 1, 6, 1, 0},
|
||||
{1, {1}, 7, 63, 1, 0},
|
||||
// AC scans for component 2
|
||||
// shifted by 1 bit, two spectral ranges
|
||||
{1, {2}, 1, 6, 0, 1},
|
||||
{1, {2}, 7, 63, 0, 1},
|
||||
// refinement scan, two spectral ranges (but different from above)
|
||||
{1, {2}, 1, 16, 1, 0},
|
||||
{1, {2}, 17, 63, 1, 0},
|
||||
};
|
||||
|
||||
static constexpr jpeg_scan_info kScript10[] = {
|
||||
// Interleaved full DC.
|
||||
{3, {0, 1, 2}, 0, 0, 0, 0},
|
||||
// AC scans for spectral range 1..16
|
||||
// shifted by 1
|
||||
{1, {0}, 1, 16, 0, 1},
|
||||
{1, {1}, 1, 16, 0, 1},
|
||||
{1, {2}, 1, 16, 0, 1},
|
||||
// refinement scans, two sub-ranges
|
||||
{1, {0}, 1, 8, 1, 0},
|
||||
{1, {0}, 9, 16, 1, 0},
|
||||
{1, {1}, 1, 8, 1, 0},
|
||||
{1, {1}, 9, 16, 1, 0},
|
||||
{1, {2}, 1, 8, 1, 0},
|
||||
{1, {2}, 9, 16, 1, 0},
|
||||
// AC scans for spectral range 17..63
|
||||
{1, {0}, 17, 63, 0, 1},
|
||||
{1, {1}, 17, 63, 0, 1},
|
||||
{1, {2}, 17, 63, 0, 1},
|
||||
// refinement scans, two sub-ranges
|
||||
{1, {0}, 17, 28, 1, 0},
|
||||
{1, {0}, 29, 63, 1, 0},
|
||||
{1, {1}, 17, 28, 1, 0},
|
||||
{1, {1}, 29, 63, 1, 0},
|
||||
{1, {2}, 17, 28, 1, 0},
|
||||
{1, {2}, 29, 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},
|
||||
{ARRAY_SIZE(kScript5), kScript5}, {ARRAY_SIZE(kScript6), kScript6},
|
||||
{ARRAY_SIZE(kScript7), kScript7}, {ARRAY_SIZE(kScript8), kScript8},
|
||||
{ARRAY_SIZE(kScript9), kScript9}, {ARRAY_SIZE(kScript10), kScript10},
|
||||
};
|
||||
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);
|
||||
|
||||
int NumTestScanScripts();
|
||||
|
||||
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);
|
||||
j_decompress_ptr cinfo);
|
||||
|
||||
void SetScanDecompressParams(const DecompressParams& dparams,
|
||||
j_decompress_ptr cinfo, int scan_number,
|
||||
bool is_jpegli);
|
||||
j_decompress_ptr cinfo, int scan_number);
|
||||
|
||||
void CopyCoefficients(j_decompress_ptr cinfo, jvirt_barray_ptr* coef_arrays,
|
||||
TestImage* output);
|
||||
@ -408,20 +111,6 @@ void EncodeWithJpegli(const TestImage& input, const CompressParams& jparams,
|
||||
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);
|
||||
|
38
third_party/jpeg-xl/lib/jpegli/types.h
vendored
Normal file
38
third_party/jpeg-xl/lib/jpegli/types.h
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
// 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_TYPES_H_
|
||||
#define LIB_JPEGLI_TYPES_H_
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//
|
||||
// New API structs and functions that are not available in libjpeg
|
||||
//
|
||||
// NOTE: This part of the API is still experimental and will probably change in
|
||||
// the future.
|
||||
//
|
||||
|
||||
typedef enum {
|
||||
JPEGLI_TYPE_FLOAT = 0,
|
||||
JPEGLI_TYPE_UINT8 = 2,
|
||||
JPEGLI_TYPE_UINT16 = 3,
|
||||
} JpegliDataType;
|
||||
|
||||
typedef enum {
|
||||
JPEGLI_NATIVE_ENDIAN = 0,
|
||||
JPEGLI_LITTLE_ENDIAN = 1,
|
||||
JPEGLI_BIG_ENDIAN = 2,
|
||||
} JpegliEndianness;
|
||||
|
||||
int jpegli_bytes_per_sample(JpegliDataType data_type);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // LIB_JPEGLI_TYPES_H_
|
@ -63,11 +63,11 @@
|
||||
#endif
|
||||
|
||||
#if JXL_COMPILER_MSVC
|
||||
#define JXL_UNREACHABLE __assume(false)
|
||||
#define JXL_UNREACHABLE_BUILTIN __assume(false)
|
||||
#elif JXL_COMPILER_CLANG || JXL_COMPILER_GCC >= 405
|
||||
#define JXL_UNREACHABLE __builtin_unreachable()
|
||||
#define JXL_UNREACHABLE_BUILTIN __builtin_unreachable()
|
||||
#else
|
||||
#define JXL_UNREACHABLE
|
||||
#define JXL_UNREACHABLE_BUILTIN
|
||||
#endif
|
||||
|
||||
#if JXL_COMPILER_MSVC
|
||||
|
3
third_party/jpeg-xl/lib/jxl/base/float.h
vendored
3
third_party/jpeg-xl/lib/jxl/base/float.h
vendored
@ -25,7 +25,8 @@ float LoadFloat16(uint16_t bits16) {
|
||||
|
||||
// Subnormal or zero
|
||||
if (biased_exp == 0) {
|
||||
const float subnormal = (1.0f / 16384) * (mantissa * (1.0f / 1024));
|
||||
const float subnormal =
|
||||
(1.0f / 16384) * (static_cast<float>(mantissa) * (1.0f / 1024));
|
||||
return sign ? -subnormal : subnormal;
|
||||
}
|
||||
|
||||
|
21
third_party/jpeg-xl/lib/jxl/base/status.h
vendored
21
third_party/jpeg-xl/lib/jxl/base/status.h
vendored
@ -68,10 +68,10 @@ namespace jxl {
|
||||
#define JXL_DEBUG_V_LEVEL 0
|
||||
#endif // JXL_DEBUG_V_LEVEL
|
||||
|
||||
// Pass -DJXL_DEBUG_ON_ABORT=0 to disable the debug messages on JXL_ASSERT,
|
||||
// JXL_CHECK and JXL_ABORT.
|
||||
// Pass -DJXL_DEBUG_ON_ABORT={0,1} to force disable/enable the debug messages on
|
||||
// JXL_ASSERT, JXL_CHECK and JXL_ABORT.
|
||||
#ifndef JXL_DEBUG_ON_ABORT
|
||||
#define JXL_DEBUG_ON_ABORT 1
|
||||
#define JXL_DEBUG_ON_ABORT JXL_DEBUG_ON_ERROR
|
||||
#endif // JXL_DEBUG_ON_ABORT
|
||||
|
||||
// Print a debug message on standard error. You should use the JXL_DEBUG macro
|
||||
@ -151,6 +151,21 @@ JXL_NORETURN inline JXL_NOINLINE bool Abort() {
|
||||
__FILE__, __LINE__, ##__VA_ARGS__), \
|
||||
::jxl::Abort())
|
||||
|
||||
// Use this for code paths that are unreachable unless the code would change
|
||||
// to make it reachable, in which case it will print a warning and abort in
|
||||
// debug builds. In release builds no code is produced for this, so only use
|
||||
// this if this path is really unreachable.
|
||||
#define JXL_UNREACHABLE(format, ...) \
|
||||
do { \
|
||||
if (JXL_DEBUG_WARNING) { \
|
||||
::jxl::Debug(("%s:%d: JXL_UNREACHABLE: " format "\n"), __FILE__, \
|
||||
__LINE__, ##__VA_ARGS__); \
|
||||
::jxl::Abort(); \
|
||||
} else { \
|
||||
JXL_UNREACHABLE_BUILTIN; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Does not guarantee running the code, use only for debug mode checks.
|
||||
#if JXL_ENABLE_ASSERT
|
||||
#define JXL_ASSERT(condition) \
|
||||
|
4
third_party/jpeg-xl/lib/jxl/blending.cc
vendored
4
third_party/jpeg-xl/lib/jxl/blending.cc
vendored
@ -80,7 +80,7 @@ void PerformBlending(const float* const* bg, const float* const* fg,
|
||||
} else if (ec_blending[i].mode == PatchBlendMode::kNone) {
|
||||
if (xsize) memcpy(tmp.Row(3 + i), bg[3 + i] + x0, xsize * sizeof(**fg));
|
||||
} else {
|
||||
JXL_ABORT("Unreachable");
|
||||
JXL_UNREACHABLE("new PatchBlendMode?");
|
||||
}
|
||||
}
|
||||
size_t alpha = color_blending.alpha_channel;
|
||||
@ -142,7 +142,7 @@ void PerformBlending(const float* const* bg, const float* const* fg,
|
||||
memcpy(tmp.Row(p), bg[p] + x0, xsize * sizeof(**fg));
|
||||
}
|
||||
} else {
|
||||
JXL_ABORT("Unreachable");
|
||||
JXL_UNREACHABLE("new PatchBlendMode?");
|
||||
}
|
||||
for (size_t i = 0; i < 3 + num_ec; i++) {
|
||||
if (xsize != 0) memcpy(out[i] + x0, tmp.Row(i), xsize * sizeof(**out));
|
||||
|
@ -182,23 +182,7 @@ void ConvolutionWithTranspose(const ImageF& in,
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("Warning: Unexpected kernel size! %" PRIuS "\n", len);
|
||||
for (size_t y = 0; y < in.ysize(); ++y) {
|
||||
const float* BUTTERAUGLI_RESTRICT row_in = in.Row(y);
|
||||
for (size_t x = border1; x < border2; ++x) {
|
||||
const int d = x - offset;
|
||||
float* BUTTERAUGLI_RESTRICT row_out = out->Row(x);
|
||||
float sum = 0.0f;
|
||||
size_t j;
|
||||
for (j = 0; j <= len / 2; ++j) {
|
||||
sum += row_in[d + j] * scaled_kernel[j];
|
||||
}
|
||||
for (; j < len; ++j) {
|
||||
sum += row_in[d + j] * scaled_kernel[len - 1 - j];
|
||||
}
|
||||
row_out[y] = sum;
|
||||
}
|
||||
}
|
||||
JXL_UNREACHABLE("Kernel size %" PRIuS " not implemented", len);
|
||||
}
|
||||
// left border
|
||||
for (size_t x = 0; x < border1; ++x) {
|
||||
|
@ -35,7 +35,7 @@ std::string ToString(ColorSpace color_space) {
|
||||
return "CS?";
|
||||
}
|
||||
// Should not happen - visitor fails if enum is invalid.
|
||||
JXL_ABORT("Invalid ColorSpace %u", static_cast<uint32_t>(color_space));
|
||||
JXL_UNREACHABLE("Invalid ColorSpace %u", static_cast<uint32_t>(color_space));
|
||||
}
|
||||
|
||||
std::string ToString(WhitePoint white_point) {
|
||||
@ -50,7 +50,7 @@ std::string ToString(WhitePoint white_point) {
|
||||
return "DCI";
|
||||
}
|
||||
// Should not happen - visitor fails if enum is invalid.
|
||||
JXL_ABORT("Invalid WhitePoint %u", static_cast<uint32_t>(white_point));
|
||||
JXL_UNREACHABLE("Invalid WhitePoint %u", static_cast<uint32_t>(white_point));
|
||||
}
|
||||
|
||||
std::string ToString(Primaries primaries) {
|
||||
@ -65,7 +65,7 @@ std::string ToString(Primaries primaries) {
|
||||
return "Cst";
|
||||
}
|
||||
// Should not happen - visitor fails if enum is invalid.
|
||||
JXL_ABORT("Invalid Primaries %u", static_cast<uint32_t>(primaries));
|
||||
JXL_UNREACHABLE("Invalid Primaries %u", static_cast<uint32_t>(primaries));
|
||||
}
|
||||
|
||||
std::string ToString(TransferFunction transfer_function) {
|
||||
@ -86,8 +86,8 @@ std::string ToString(TransferFunction transfer_function) {
|
||||
return "TF?";
|
||||
}
|
||||
// Should not happen - visitor fails if enum is invalid.
|
||||
JXL_ABORT("Invalid TransferFunction %u",
|
||||
static_cast<uint32_t>(transfer_function));
|
||||
JXL_UNREACHABLE("Invalid TransferFunction %u",
|
||||
static_cast<uint32_t>(transfer_function));
|
||||
}
|
||||
|
||||
std::string ToString(RenderingIntent rendering_intent) {
|
||||
@ -102,8 +102,8 @@ std::string ToString(RenderingIntent rendering_intent) {
|
||||
return "Abs";
|
||||
}
|
||||
// Should not happen - visitor fails if enum is invalid.
|
||||
JXL_ABORT("Invalid RenderingIntent %u",
|
||||
static_cast<uint32_t>(rendering_intent));
|
||||
JXL_UNREACHABLE("Invalid RenderingIntent %u",
|
||||
static_cast<uint32_t>(rendering_intent));
|
||||
}
|
||||
|
||||
static double F64FromCustomxyI32(const int32_t i) { return i * 1E-6; }
|
||||
@ -131,7 +131,8 @@ Status ConvertExternalToInternalWhitePoint(const JxlWhitePoint external,
|
||||
*internal = WhitePoint::kDCI;
|
||||
return true;
|
||||
}
|
||||
return JXL_FAILURE("Invalid WhitePoint enum value");
|
||||
return JXL_FAILURE("Invalid WhitePoint enum value %d",
|
||||
static_cast<int>(external));
|
||||
}
|
||||
|
||||
Status ConvertExternalToInternalPrimaries(const JxlPrimaries external,
|
||||
@ -314,7 +315,7 @@ CIExy ColorEncoding::GetWhitePoint() const {
|
||||
xy.x = xy.y = 1.0 / 3;
|
||||
return xy;
|
||||
}
|
||||
JXL_ABORT("Invalid WhitePoint %u", static_cast<uint32_t>(white_point));
|
||||
JXL_UNREACHABLE("Invalid WhitePoint %u", static_cast<uint32_t>(white_point));
|
||||
}
|
||||
|
||||
Status ColorEncoding::SetWhitePoint(const CIExy& xy) {
|
||||
@ -376,7 +377,7 @@ PrimariesCIExy ColorEncoding::GetPrimaries() const {
|
||||
xy.b.y = 0.060;
|
||||
return xy;
|
||||
}
|
||||
JXL_ABORT("Invalid Primaries %u", static_cast<uint32_t>(primaries));
|
||||
JXL_UNREACHABLE("Invalid Primaries %u", static_cast<uint32_t>(primaries));
|
||||
}
|
||||
|
||||
Status ColorEncoding::SetPrimaries(const PrimariesCIExy& xy) {
|
||||
@ -420,6 +421,44 @@ Status ColorEncoding::CreateICC() {
|
||||
return MaybeCreateProfile(*this, &icc_);
|
||||
}
|
||||
|
||||
Status ColorEncoding::SetFieldsFromICC(const JxlCmsInterface& cms) {
|
||||
// In case parsing fails, mark the ColorEncoding as invalid.
|
||||
SetColorSpace(ColorSpace::kUnknown);
|
||||
tf.SetTransferFunction(TransferFunction::kUnknown);
|
||||
|
||||
if (icc_.empty()) return JXL_FAILURE("Empty ICC profile");
|
||||
|
||||
JxlColorEncoding external;
|
||||
JXL_BOOL cmyk;
|
||||
JXL_RETURN_IF_ERROR(cms.set_fields_from_icc(cms.set_fields_data, icc_.data(),
|
||||
icc_.size(), &external, &cmyk));
|
||||
if (cmyk) {
|
||||
cmyk_ = true;
|
||||
return true;
|
||||
}
|
||||
PaddedBytes icc = std::move(icc_);
|
||||
JXL_RETURN_IF_ERROR(ConvertExternalToInternalColorEncoding(external, this));
|
||||
icc_ = std::move(icc);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ColorEncoding::DecideIfWantICC(const JxlCmsInterface& cms) {
|
||||
if (icc_.empty()) return;
|
||||
|
||||
JxlColorEncoding c;
|
||||
JXL_BOOL cmyk;
|
||||
if (!cms.set_fields_from_icc(cms.set_fields_data, icc_.data(), icc_.size(),
|
||||
&c, &cmyk)) {
|
||||
return;
|
||||
}
|
||||
if (cmyk) return;
|
||||
|
||||
PaddedBytes new_icc;
|
||||
if (!MaybeCreateProfile(*this, &new_icc)) return;
|
||||
|
||||
want_icc_ = false;
|
||||
}
|
||||
|
||||
std::string Description(const ColorEncoding& c_in) {
|
||||
// Copy required for Implicit*
|
||||
ColorEncoding c = c_in;
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
// Metadata for color space conversions.
|
||||
|
||||
#include <jxl/cms_interface.h>
|
||||
#include <jxl/color_encoding.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
@ -251,11 +252,17 @@ struct ColorEncoding : public Fields {
|
||||
// Returns true if `icc` is assigned and decoded successfully. If so,
|
||||
// subsequent WantICC() will return true until DecideIfWantICC() changes it.
|
||||
// Returning false indicates data has been lost.
|
||||
Status SetICC(PaddedBytes&& icc) {
|
||||
Status SetICC(PaddedBytes&& icc, const JxlCmsInterface* cms) {
|
||||
if (icc.empty()) return false;
|
||||
icc_ = std::move(icc);
|
||||
|
||||
if (!SetFieldsFromICC()) {
|
||||
if (cms == nullptr) {
|
||||
want_icc_ = true;
|
||||
have_fields_ = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!SetFieldsFromICC(*cms)) {
|
||||
InternalRemoveICC();
|
||||
return false;
|
||||
}
|
||||
@ -286,8 +293,7 @@ struct ColorEncoding : public Fields {
|
||||
bool HaveFields() const { return have_fields_; }
|
||||
|
||||
// Causes WantICC() to return false if ICC() can be reconstructed from fields.
|
||||
// Defined in color_management.cc.
|
||||
void DecideIfWantICC();
|
||||
void DecideIfWantICC(const JxlCmsInterface& cms);
|
||||
|
||||
bool IsGray() const { return color_space_ == ColorSpace::kGray; }
|
||||
bool IsCMYK() const { return cmyk_; }
|
||||
@ -400,8 +406,7 @@ struct ColorEncoding : public Fields {
|
||||
private:
|
||||
// Returns true if all fields have been initialized (possibly to kUnknown).
|
||||
// Returns false if the ICC profile is invalid or decoding it fails.
|
||||
// Defined in enc_color_management.cc.
|
||||
Status SetFieldsFromICC();
|
||||
Status SetFieldsFromICC(const JxlCmsInterface& cms);
|
||||
|
||||
// If true, the codestream contains an ICC profile and we do not serialize
|
||||
// fields. Otherwise, fields are serialized and we create an ICC profile.
|
||||
@ -428,11 +433,7 @@ struct ColorEncoding : public Fields {
|
||||
|
||||
// Returns whether the two inputs are approximately equal.
|
||||
static inline bool ApproxEq(const double a, const double b,
|
||||
#if JPEGXL_ENABLE_SKCMS
|
||||
double max_l1 = 1E-3) {
|
||||
#else
|
||||
double max_l1 = 8E-5) {
|
||||
#endif
|
||||
// Threshold should be sufficient for ICC's 15-bit fixed-point numbers.
|
||||
// We have seen differences of 7.1E-5 with lcms2 and 1E-3 with skcms.
|
||||
return std::abs(a - b) <= max_l1;
|
||||
|
@ -828,8 +828,8 @@ Status MaybeCreateProfile(const ColorEncoding& c,
|
||||
CreateICCCurvParaTag({2.6, 1.0, 0.0, 1.0, 0.0}, 3, &tags));
|
||||
break;
|
||||
default:
|
||||
JXL_ABORT("Unknown TF %u",
|
||||
static_cast<unsigned int>(c.tf.GetTransferFunction()));
|
||||
JXL_UNREACHABLE("Unknown TF %u", static_cast<unsigned int>(
|
||||
c.tf.GetTransferFunction()));
|
||||
}
|
||||
}
|
||||
FinalizeICCTag(&tags, &tag_offset, &tag_size);
|
||||
|
@ -200,7 +200,7 @@ TEST_P(ColorManagementTest, VerifyAllProfiles) {
|
||||
|
||||
// Can set an equivalent ColorEncoding from the generated ICC profile.
|
||||
ColorEncoding c3;
|
||||
ASSERT_TRUE(c3.SetICC(PaddedBytes(c.ICC())));
|
||||
ASSERT_TRUE(c3.SetICC(PaddedBytes(c.ICC()), &GetJxlCms()));
|
||||
EXPECT_THAT(c3, HasSameFieldsAs(c));
|
||||
|
||||
VerifyPixelRoundTrip(c);
|
||||
@ -233,7 +233,7 @@ TEST_F(ColorManagementTest, D2700Chromaticity) {
|
||||
PaddedBytes icc =
|
||||
jxl::test::ReadTestData("jxl/color_management/sRGB-D2700.icc");
|
||||
ColorEncoding sRGB_D2700;
|
||||
ASSERT_TRUE(sRGB_D2700.SetICC(std::move(icc)));
|
||||
ASSERT_TRUE(sRGB_D2700.SetICC(std::move(icc), &GetJxlCms()));
|
||||
|
||||
EXPECT_THAT(sRGB_D2700.GetWhitePoint(), CIExyIs(0.45986, 0.41060));
|
||||
// The illuminant-relative chromaticities of this profile's primaries are the
|
||||
@ -245,12 +245,13 @@ TEST_F(ColorManagementTest, D2700Chromaticity) {
|
||||
}
|
||||
|
||||
TEST_F(ColorManagementTest, D2700ToSRGB) {
|
||||
const JxlCmsInterface& cms = GetJxlCms();
|
||||
PaddedBytes icc =
|
||||
jxl::test::ReadTestData("jxl/color_management/sRGB-D2700.icc");
|
||||
ColorEncoding sRGB_D2700;
|
||||
ASSERT_TRUE(sRGB_D2700.SetICC(std::move(icc)));
|
||||
ASSERT_TRUE(sRGB_D2700.SetICC(std::move(icc), &cms));
|
||||
|
||||
ColorSpaceTransform transform(GetJxlCms());
|
||||
ColorSpaceTransform transform(cms);
|
||||
ASSERT_TRUE(transform.Init(sRGB_D2700, ColorEncoding::SRGB(),
|
||||
kDefaultIntensityTarget, 1, 1));
|
||||
const float sRGB_D2700_values[3] = {0.863, 0.737, 0.490};
|
||||
|
110
third_party/jpeg-xl/lib/jxl/dec_ans.h
vendored
110
third_party/jpeg-xl/lib/jxl/dec_ans.h
vendored
@ -276,9 +276,10 @@ class ANSSymbolReader {
|
||||
}
|
||||
|
||||
// Takes a *clustered* idx. Can only use if HuffRleOnly() is true.
|
||||
void ReadHybridUintClusteredHuffRleOnly(size_t ctx,
|
||||
BitReader* JXL_RESTRICT br,
|
||||
uint32_t* value, uint32_t* run) {
|
||||
JXL_INLINE void ReadHybridUintClusteredHuffRleOnly(size_t ctx,
|
||||
BitReader* JXL_RESTRICT br,
|
||||
uint32_t* value,
|
||||
uint32_t* run) {
|
||||
JXL_DASSERT(HuffRleOnly());
|
||||
br->Refill(); // covers ReadSymbolWithoutRefill + PeekBits
|
||||
size_t token = ReadSymbolHuffWithoutRefill(ctx, br);
|
||||
@ -300,55 +301,80 @@ class ANSSymbolReader {
|
||||
if (configs[lz77_ctx_].split_token > 1) return false;
|
||||
return true;
|
||||
}
|
||||
bool UsesLZ77() { return lz77_window_ != nullptr; }
|
||||
|
||||
// Takes a *clustered* idx.
|
||||
size_t ReadHybridUintClustered(size_t ctx, BitReader* JXL_RESTRICT br) {
|
||||
if (JXL_UNLIKELY(num_to_copy_ > 0)) {
|
||||
size_t ret = lz77_window_[(copy_pos_++) & kWindowMask];
|
||||
num_to_copy_--;
|
||||
lz77_window_[(num_decoded_++) & kWindowMask] = ret;
|
||||
return ret;
|
||||
// Takes a *clustered* idx. Inlined, for use in hot paths.
|
||||
template <bool uses_lz77>
|
||||
JXL_INLINE size_t ReadHybridUintClustered(size_t ctx,
|
||||
BitReader* JXL_RESTRICT br) {
|
||||
if (uses_lz77) {
|
||||
if (JXL_UNLIKELY(num_to_copy_ > 0)) {
|
||||
size_t ret = lz77_window_[(copy_pos_++) & kWindowMask];
|
||||
num_to_copy_--;
|
||||
lz77_window_[(num_decoded_++) & kWindowMask] = ret;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
br->Refill(); // covers ReadSymbolWithoutRefill + PeekBits
|
||||
size_t token = ReadSymbolWithoutRefill(ctx, br);
|
||||
if (JXL_UNLIKELY(token >= lz77_threshold_)) {
|
||||
num_to_copy_ =
|
||||
ReadHybridUintConfig(lz77_length_uint_, token - lz77_threshold_, br) +
|
||||
lz77_min_length_;
|
||||
br->Refill(); // covers ReadSymbolWithoutRefill + PeekBits
|
||||
// Distance code.
|
||||
size_t token = ReadSymbolWithoutRefill(lz77_ctx_, br);
|
||||
size_t distance = ReadHybridUintConfig(configs[lz77_ctx_], token, br);
|
||||
if (JXL_LIKELY(distance < num_special_distances_)) {
|
||||
distance = special_distances_[distance];
|
||||
} else {
|
||||
distance = distance + 1 - num_special_distances_;
|
||||
if (uses_lz77) {
|
||||
if (JXL_UNLIKELY(token >= lz77_threshold_)) {
|
||||
num_to_copy_ = ReadHybridUintConfig(lz77_length_uint_,
|
||||
token - lz77_threshold_, br) +
|
||||
lz77_min_length_;
|
||||
br->Refill(); // covers ReadSymbolWithoutRefill + PeekBits
|
||||
// Distance code.
|
||||
size_t token = ReadSymbolWithoutRefill(lz77_ctx_, br);
|
||||
size_t distance = ReadHybridUintConfig(configs[lz77_ctx_], token, br);
|
||||
if (JXL_LIKELY(distance < num_special_distances_)) {
|
||||
distance = special_distances_[distance];
|
||||
} else {
|
||||
distance = distance + 1 - num_special_distances_;
|
||||
}
|
||||
if (JXL_UNLIKELY(distance > num_decoded_)) {
|
||||
distance = num_decoded_;
|
||||
}
|
||||
if (JXL_UNLIKELY(distance > kWindowSize)) {
|
||||
distance = kWindowSize;
|
||||
}
|
||||
copy_pos_ = num_decoded_ - distance;
|
||||
if (JXL_UNLIKELY(distance == 0)) {
|
||||
JXL_DASSERT(lz77_window_ != nullptr);
|
||||
// distance 0 -> num_decoded_ == copy_pos_ == 0
|
||||
size_t to_fill = std::min<size_t>(num_to_copy_, kWindowSize);
|
||||
memset(lz77_window_, 0, to_fill * sizeof(lz77_window_[0]));
|
||||
}
|
||||
// TODO(eustas): overflow; mark BitReader as unhealthy
|
||||
if (num_to_copy_ < lz77_min_length_) return 0;
|
||||
// the code below is the same as doing this:
|
||||
// return ReadHybridUintClustered<uses_lz77>(ctx, br);
|
||||
// but gcc doesn't like recursive inlining
|
||||
|
||||
size_t ret = lz77_window_[(copy_pos_++) & kWindowMask];
|
||||
num_to_copy_--;
|
||||
lz77_window_[(num_decoded_++) & kWindowMask] = ret;
|
||||
return ret;
|
||||
}
|
||||
if (JXL_UNLIKELY(distance > num_decoded_)) {
|
||||
distance = num_decoded_;
|
||||
}
|
||||
if (JXL_UNLIKELY(distance > kWindowSize)) {
|
||||
distance = kWindowSize;
|
||||
}
|
||||
copy_pos_ = num_decoded_ - distance;
|
||||
if (JXL_UNLIKELY(distance == 0)) {
|
||||
JXL_DASSERT(lz77_window_ != nullptr);
|
||||
// distance 0 -> num_decoded_ == copy_pos_ == 0
|
||||
size_t to_fill = std::min<size_t>(num_to_copy_, kWindowSize);
|
||||
memset(lz77_window_, 0, to_fill * sizeof(lz77_window_[0]));
|
||||
}
|
||||
// TODO(eustas): overflow; mark BitReader as unhealthy
|
||||
if (num_to_copy_ < lz77_min_length_) return 0;
|
||||
return ReadHybridUintClustered(ctx, br); // will trigger a copy.
|
||||
}
|
||||
size_t ret = ReadHybridUintConfig(configs[ctx], token, br);
|
||||
if (lz77_window_) lz77_window_[(num_decoded_++) & kWindowMask] = ret;
|
||||
if (uses_lz77 && lz77_window_)
|
||||
lz77_window_[(num_decoded_++) & kWindowMask] = ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
JXL_INLINE size_t ReadHybridUint(size_t ctx, BitReader* JXL_RESTRICT br,
|
||||
const std::vector<uint8_t>& context_map) {
|
||||
return ReadHybridUintClustered(context_map[ctx], br);
|
||||
// inlined, for use in hot paths
|
||||
template <bool uses_lz77>
|
||||
JXL_INLINE size_t
|
||||
ReadHybridUintInlined(size_t ctx, BitReader* JXL_RESTRICT br,
|
||||
const std::vector<uint8_t>& context_map) {
|
||||
return ReadHybridUintClustered<uses_lz77>(context_map[ctx], br);
|
||||
}
|
||||
|
||||
// not inlined, for use in non-hot paths
|
||||
size_t ReadHybridUint(size_t ctx, BitReader* JXL_RESTRICT br,
|
||||
const std::vector<uint8_t>& context_map) {
|
||||
return ReadHybridUintClustered</*uses_lz77=*/true>(context_map[ctx], br);
|
||||
}
|
||||
|
||||
// ctx is a *clustered* context!
|
||||
|
11
third_party/jpeg-xl/lib/jxl/dec_context_map.cc
vendored
11
third_party/jpeg-xl/lib/jxl/dec_context_map.cc
vendored
@ -64,14 +64,17 @@ Status DecodeContextMap(std::vector<uint8_t>* context_map, size_t* num_htrees,
|
||||
/*disallow_lz77=*/context_map->size() <= 2));
|
||||
ANSSymbolReader reader(&code, input);
|
||||
size_t i = 0;
|
||||
uint32_t maxsym = 0;
|
||||
while (i < context_map->size()) {
|
||||
uint32_t sym = reader.ReadHybridUint(0, input, dummy_ctx_map);
|
||||
if (sym >= kMaxClusters) {
|
||||
return JXL_FAILURE("Invalid cluster ID");
|
||||
}
|
||||
uint32_t sym = reader.ReadHybridUintInlined</*uses_lz77=*/true>(
|
||||
0, input, dummy_ctx_map);
|
||||
maxsym = sym > maxsym ? sym : maxsym;
|
||||
(*context_map)[i] = sym;
|
||||
i++;
|
||||
}
|
||||
if (maxsym >= kMaxClusters) {
|
||||
return JXL_FAILURE("Invalid cluster ID");
|
||||
}
|
||||
if (!reader.CheckANSFinalState()) {
|
||||
return JXL_FAILURE("Invalid context map");
|
||||
}
|
||||
|
@ -235,18 +235,8 @@ void StoreFloatRow(const float* JXL_RESTRICT* rows_in, size_t num_channels,
|
||||
|
||||
void JXL_INLINE Store8(uint32_t value, uint8_t* dest) { *dest = value & 0xff; }
|
||||
|
||||
// Maximum number of channels for the ConvertChannelsToExternal function.
|
||||
const size_t kConvertMaxChannels = 4;
|
||||
} // namespace
|
||||
|
||||
// Converts a list of channels to an interleaved image, applying transformations
|
||||
// when needed.
|
||||
// The input channels are given as a (non-const!) array of channel pointers and
|
||||
// interleaved in that order.
|
||||
//
|
||||
// Note: if a pointer in channels[] is nullptr, a 1.0 value will be used
|
||||
// instead. This is useful for handling when a user requests an alpha channel
|
||||
// from an image that doesn't have one. The first channel in the list may not
|
||||
// be nullptr, since it is used to determine the image size.
|
||||
Status ConvertChannelsToExternal(const ImageF* channels[], size_t num_channels,
|
||||
size_t bits_per_sample, bool float_out,
|
||||
JxlEndianness endianness, size_t stride,
|
||||
@ -448,8 +438,6 @@ Status ConvertChannelsToExternal(const ImageF* channels[], size_t num_channels,
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Status ConvertToExternal(const jxl::ImageBundle& ib, size_t bits_per_sample,
|
||||
bool float_out, size_t num_channels,
|
||||
JxlEndianness endianness, size_t stride,
|
||||
|
20
third_party/jpeg-xl/lib/jxl/dec_external_image.h
vendored
20
third_party/jpeg-xl/lib/jxl/dec_external_image.h
vendored
@ -21,6 +21,26 @@
|
||||
|
||||
namespace jxl {
|
||||
|
||||
// Maximum number of channels for the ConvertChannelsToExternal function.
|
||||
const size_t kConvertMaxChannels = 4;
|
||||
|
||||
// Converts a list of channels to an interleaved image, applying transformations
|
||||
// when needed.
|
||||
// The input channels are given as a (non-const!) array of channel pointers and
|
||||
// interleaved in that order.
|
||||
//
|
||||
// Note: if a pointer in channels[] is nullptr, a 1.0 value will be used
|
||||
// instead. This is useful for handling when a user requests an alpha channel
|
||||
// from an image that doesn't have one. The first channel in the list may not
|
||||
// be nullptr, since it is used to determine the image size.
|
||||
Status ConvertChannelsToExternal(const ImageF* channels[], size_t num_channels,
|
||||
size_t bits_per_sample, bool float_out,
|
||||
JxlEndianness endianness, size_t stride,
|
||||
jxl::ThreadPool* pool, void* out_image,
|
||||
size_t out_size,
|
||||
const PixelCallback& out_callback,
|
||||
jxl::Orientation undo_orientation);
|
||||
|
||||
// Converts ib to interleaved void* pixel buffer with the given format.
|
||||
// bits_per_sample: must be 16 or 32 if float_out is true, and at most 16
|
||||
// if it is false. No bit packing is done.
|
||||
|
18
third_party/jpeg-xl/lib/jxl/dec_group.cc
vendored
18
third_party/jpeg-xl/lib/jxl/dec_group.cc
vendored
@ -431,7 +431,7 @@ namespace jxl {
|
||||
namespace {
|
||||
// Decode quantized AC coefficients of DCT blocks.
|
||||
// LLF components in the output block will not be modified.
|
||||
template <ACType ac_type>
|
||||
template <ACType ac_type, bool uses_lz77>
|
||||
Status DecodeACVarBlock(size_t ctx_offset, size_t log2_covered_blocks,
|
||||
int32_t* JXL_RESTRICT row_nzeros,
|
||||
const int32_t* JXL_RESTRICT row_nzeros_top,
|
||||
@ -458,7 +458,8 @@ Status DecodeACVarBlock(size_t ctx_offset, size_t log2_covered_blocks,
|
||||
const int32_t nzero_ctx =
|
||||
block_ctx_map.NonZeroContext(predicted_nzeros, block_ctx) + ctx_offset;
|
||||
|
||||
size_t nzeros = decoder->ReadHybridUint(nzero_ctx, br, context_map);
|
||||
size_t nzeros =
|
||||
decoder->ReadHybridUintInlined<uses_lz77>(nzero_ctx, br, context_map);
|
||||
if (nzeros + covered_blocks > size) {
|
||||
return JXL_FAILURE("Invalid AC: nzeros too large");
|
||||
}
|
||||
@ -477,7 +478,8 @@ Status DecodeACVarBlock(size_t ctx_offset, size_t log2_covered_blocks,
|
||||
const size_t ctx =
|
||||
histo_offset + ZeroDensityContext(nzeros, k, covered_blocks,
|
||||
log2_covered_blocks, prev);
|
||||
const size_t u_coeff = decoder->ReadHybridUint(ctx, br, context_map);
|
||||
const size_t u_coeff =
|
||||
decoder->ReadHybridUintInlined<uses_lz77>(ctx, br, context_map);
|
||||
// Hand-rolled version of UnpackSigned, shifting before the conversion to
|
||||
// signed integer to avoid undefined behavior of shifting negative numbers.
|
||||
const size_t magnitude = u_coeff >> 1;
|
||||
@ -525,9 +527,7 @@ struct GetBlockFromBitstream : public GetBlock {
|
||||
Status LoadBlock(size_t bx, size_t by, const AcStrategy& acs, size_t size,
|
||||
size_t log2_covered_blocks, ACPtr block[3],
|
||||
ACType ac_type) override {
|
||||
auto decode_ac_varblock = ac_type == ACType::k16
|
||||
? DecodeACVarBlock<ACType::k16>
|
||||
: DecodeACVarBlock<ACType::k32>;
|
||||
;
|
||||
for (size_t c : {1, 0, 2}) {
|
||||
size_t sbx = bx >> hshift[c];
|
||||
size_t sby = by >> vshift[c];
|
||||
@ -536,6 +536,12 @@ struct GetBlockFromBitstream : public GetBlock {
|
||||
}
|
||||
|
||||
for (size_t pass = 0; JXL_UNLIKELY(pass < num_passes); pass++) {
|
||||
auto decode_ac_varblock =
|
||||
decoders[pass].UsesLZ77()
|
||||
? (ac_type == ACType::k16 ? DecodeACVarBlock<ACType::k16, 1>
|
||||
: DecodeACVarBlock<ACType::k32, 1>)
|
||||
: (ac_type == ACType::k16 ? DecodeACVarBlock<ACType::k16, 0>
|
||||
: DecodeACVarBlock<ACType::k32, 0>);
|
||||
JXL_RETURN_IF_ERROR(decode_ac_varblock(
|
||||
ctx_offset[pass], log2_covered_blocks, row_nzeros[pass][c],
|
||||
row_nzeros_top[pass][c], nzeros_stride, c, sbx, sby, bx, acs,
|
||||
|
@ -685,7 +685,7 @@ HWY_MAYBE_UNUSED void TransformToPixels(const AcStrategy::Type strategy,
|
||||
break;
|
||||
}
|
||||
case Type::kNumValidStrategies:
|
||||
JXL_ABORT("Invalid strategy");
|
||||
JXL_UNREACHABLE("Invalid strategy");
|
||||
}
|
||||
}
|
||||
|
||||
@ -813,7 +813,7 @@ HWY_MAYBE_UNUSED void LowestFrequenciesFromDC(const AcStrategy::Type strategy,
|
||||
llf[0] = dc[0];
|
||||
break;
|
||||
case Type::kNumValidStrategies:
|
||||
JXL_ABORT("Invalid strategy");
|
||||
JXL_UNREACHABLE("Invalid strategy");
|
||||
};
|
||||
}
|
||||
|
||||
|
2
third_party/jpeg-xl/lib/jxl/dec_xyb-inl.h
vendored
2
third_party/jpeg-xl/lib/jxl/dec_xyb-inl.h
vendored
@ -333,7 +333,7 @@ static inline HWY_MAYBE_UNUSED void FastXYBTosRGB8(const float* input[4],
|
||||
(void)output;
|
||||
(void)is_rgba;
|
||||
(void)xsize;
|
||||
JXL_ABORT("Unreachable");
|
||||
JXL_UNREACHABLE("Unreachable");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
99
third_party/jpeg-xl/lib/jxl/decode.cc
vendored
99
third_party/jpeg-xl/lib/jxl/decode.cc
vendored
@ -46,14 +46,6 @@ bool OutOfBounds(size_t a, size_t b, size_t size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SumOverflows(size_t a, size_t b, size_t c) {
|
||||
size_t sum = a + b;
|
||||
if (sum < b) return true;
|
||||
sum += c;
|
||||
if (sum < c) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
JXL_INLINE size_t InitialBasicInfoSizeHint() {
|
||||
// Amount of bytes before the start of the codestream in the container format,
|
||||
// assuming that the codestream is the first box after the signature and
|
||||
@ -85,12 +77,22 @@ JXL_INLINE size_t InitialBasicInfoSizeHint() {
|
||||
JXL_DEC_ERROR)
|
||||
#endif // JXL_CRASH_ON_ERROR
|
||||
|
||||
// Error caused by bad input (invalid file) rather than incorrect API usage.
|
||||
// For now there is no way to distinguish these two types of errors yet.
|
||||
#define JXL_INPUT_ERROR(format, ...) JXL_API_ERROR(format, ##__VA_ARGS__)
|
||||
|
||||
JxlDecoderStatus ConvertStatus(JxlDecoderStatus status) { return status; }
|
||||
|
||||
JxlDecoderStatus ConvertStatus(jxl::Status status) {
|
||||
return status ? JXL_DEC_SUCCESS : JXL_DEC_ERROR;
|
||||
}
|
||||
|
||||
#define JXL_API_RETURN_IF_ERROR(expr) \
|
||||
{ \
|
||||
JxlDecoderStatus status_ = ConvertStatus(expr); \
|
||||
if (status_ != JXL_DEC_SUCCESS) return status_; \
|
||||
}
|
||||
|
||||
JxlSignature ReadSignature(const uint8_t* buf, size_t len, size_t* pos) {
|
||||
if (*pos >= len) return JXL_SIG_NOT_ENOUGH_BYTES;
|
||||
|
||||
@ -165,9 +167,8 @@ uint32_t GetBitDepth(JxlBitDepth bit_depth, const T& metadata,
|
||||
return metadata.bit_depth.bits_per_sample;
|
||||
} else if (bit_depth.type == JXL_BIT_DEPTH_CUSTOM) {
|
||||
return bit_depth.bits_per_sample;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum class DecoderStage : uint32_t {
|
||||
@ -842,7 +843,7 @@ void JxlDecoderSkipFrames(JxlDecoder* dec, size_t amount) {
|
||||
|
||||
JxlDecoderStatus JxlDecoderSkipCurrentFrame(JxlDecoder* dec) {
|
||||
if (dec->frame_stage != FrameStage::kFull) {
|
||||
return JXL_DEC_ERROR;
|
||||
return JXL_API_ERROR("JxlDecoderSkipCurrentFrame called at the wrong time");
|
||||
}
|
||||
JXL_DASSERT(dec->frame_dec);
|
||||
dec->frame_stage = FrameStage::kHeader;
|
||||
@ -857,7 +858,8 @@ JXL_EXPORT JxlDecoderStatus
|
||||
JxlDecoderSetParallelRunner(JxlDecoder* dec, JxlParallelRunner parallel_runner,
|
||||
void* parallel_runner_opaque) {
|
||||
if (dec->stage != DecoderStage::kInited) {
|
||||
return JXL_API_ERROR("parallel_runner must be set before starting");
|
||||
return JXL_API_ERROR(
|
||||
"JxlDecoderSetParallelRunner must be called before starting");
|
||||
}
|
||||
dec->thread_pool.reset(
|
||||
new jxl::ThreadPool(parallel_runner, parallel_runner_opaque));
|
||||
@ -965,12 +967,6 @@ JxlDecoderStatus ReadBundle(JxlDecoder* dec, Span<const uint8_t> data,
|
||||
return JXL_DEC_SUCCESS;
|
||||
}
|
||||
|
||||
#define JXL_API_RETURN_IF_ERROR(expr) \
|
||||
{ \
|
||||
JxlDecoderStatus status_ = ConvertStatus(expr); \
|
||||
if (status_ != JXL_DEC_SUCCESS) return status_; \
|
||||
}
|
||||
|
||||
std::unique_ptr<BitReader, std::function<void(BitReader*)>> GetBitReader(
|
||||
Span<const uint8_t> span) {
|
||||
BitReader* reader = new BitReader(span);
|
||||
@ -995,7 +991,7 @@ JxlDecoderStatus JxlDecoderReadBasicInfo(JxlDecoder* dec) {
|
||||
return dec->RequestMoreInput();
|
||||
}
|
||||
if (span.data()[0] != 0xff || span.data()[1] != jxl::kCodestreamMarker) {
|
||||
return JXL_API_ERROR("invalid signature");
|
||||
return JXL_INPUT_ERROR("invalid signature");
|
||||
}
|
||||
dec->got_codestream_signature = true;
|
||||
dec->AdvanceCodestream(2);
|
||||
@ -1018,7 +1014,7 @@ JxlDecoderStatus JxlDecoderReadBasicInfo(JxlDecoder* dec) {
|
||||
|
||||
if (!CheckSizeLimit(dec, dec->metadata.size.xsize(),
|
||||
dec->metadata.size.ysize())) {
|
||||
return JXL_API_ERROR("image is too large");
|
||||
return JXL_INPUT_ERROR("image is too large");
|
||||
}
|
||||
|
||||
return JXL_DEC_SUCCESS;
|
||||
@ -1135,17 +1131,17 @@ JxlDecoderStatus JxlDecoderProcessSections(JxlDecoder* dec) {
|
||||
// If any bit reader indicates out of bounds, it's an error, not just
|
||||
// needing more input, since we ensure only bit readers containing
|
||||
// a complete section are provided to the FrameDecoder.
|
||||
return JXL_API_ERROR("frame out of bounds");
|
||||
return JXL_INPUT_ERROR("frame out of bounds");
|
||||
}
|
||||
if (!status) {
|
||||
return JXL_API_ERROR("frame processing failed");
|
||||
return JXL_INPUT_ERROR("frame processing failed");
|
||||
}
|
||||
for (size_t i = 0; i < section_status.size(); ++i) {
|
||||
auto status = section_status[i];
|
||||
if (status == jxl::FrameDecoder::kDone) {
|
||||
dec->section_processed[section_info[i].index] = 1;
|
||||
} else if (status != jxl::FrameDecoder::kSkipped) {
|
||||
return JXL_API_ERROR("unexpected section status");
|
||||
return JXL_INPUT_ERROR("unexpected section status");
|
||||
}
|
||||
}
|
||||
size_t completed_prefix_bytes = 0;
|
||||
@ -1250,14 +1246,14 @@ JxlDecoderStatus JxlDecoderProcessCodestream(JxlDecoder* dec) {
|
||||
status.code() == StatusCode::kNotEnoughBytes) {
|
||||
return dec->RequestMoreInput();
|
||||
} else if (!status) {
|
||||
return JXL_API_ERROR("invalid frame header");
|
||||
return JXL_INPUT_ERROR("invalid frame header");
|
||||
}
|
||||
dec->AdvanceCodestream(reader->TotalBitsConsumed() / kBitsPerByte);
|
||||
*dec->frame_header = dec->frame_dec->GetFrameHeader();
|
||||
jxl::FrameDimensions frame_dim = dec->frame_header->ToFrameDimensions();
|
||||
if (!CheckSizeLimit(dec, frame_dim.xsize_upsampled_padded,
|
||||
frame_dim.ysize_upsampled_padded)) {
|
||||
return JXL_API_ERROR("frame is too large");
|
||||
return JXL_INPUT_ERROR("frame is too large");
|
||||
}
|
||||
bool output_needed =
|
||||
(dec->preview_frame ? (dec->events_wanted & JXL_DEC_PREVIEW_IMAGE)
|
||||
@ -1269,11 +1265,11 @@ JxlDecoderStatus JxlDecoderProcessCodestream(JxlDecoder* dec) {
|
||||
// No overflow, checked in CheckSizeLimit.
|
||||
size_t num_pixels = frame_dim.xsize * frame_dim.ysize;
|
||||
if (dec->used_cpu_base + num_pixels < dec->used_cpu_base) {
|
||||
return JXL_API_ERROR("used too much CPU");
|
||||
return JXL_INPUT_ERROR("image too large");
|
||||
}
|
||||
dec->used_cpu_base += num_pixels;
|
||||
if (dec->used_cpu_base > dec->cpu_limit_base) {
|
||||
return JXL_API_ERROR("used too much CPU");
|
||||
return JXL_INPUT_ERROR("image too large");
|
||||
}
|
||||
}
|
||||
dec->remaining_frame_size = dec->frame_dec->SumSectionSizes();
|
||||
@ -1472,7 +1468,7 @@ JxlDecoderStatus JxlDecoderProcessCodestream(JxlDecoder* dec) {
|
||||
}
|
||||
|
||||
if (!dec->frame_dec->FinalizeFrame()) {
|
||||
return JXL_API_ERROR("decoding frame failed");
|
||||
return JXL_INPUT_ERROR("decoding frame failed");
|
||||
}
|
||||
#if JPEGXL_ENABLE_TRANSCODE_JPEG
|
||||
// If jpeg output was requested, we merely return the JXL_DEC_FULL_IMAGE
|
||||
@ -1601,10 +1597,10 @@ static JxlDecoderStatus ParseBoxHeader(const uint8_t* in, size_t size,
|
||||
pos += 4;
|
||||
*header_size = pos - box_start;
|
||||
if (*box_size > 0 && *box_size < *header_size) {
|
||||
return JXL_API_ERROR("invalid box size");
|
||||
return JXL_INPUT_ERROR("invalid box size");
|
||||
}
|
||||
if (SumOverflows(file_pos, pos, *box_size)) {
|
||||
return JXL_API_ERROR("Box size overflow");
|
||||
if (file_pos + *box_size < file_pos) {
|
||||
return JXL_INPUT_ERROR("Box size overflow");
|
||||
}
|
||||
return JXL_DEC_SUCCESS;
|
||||
}
|
||||
@ -1793,10 +1789,10 @@ static JxlDecoderStatus HandleBoxes(JxlDecoder* dec) {
|
||||
return JXL_DEC_SUCCESS;
|
||||
}
|
||||
if (dec->box_count == 2 && memcmp(dec->box_type, "ftyp", 4) != 0) {
|
||||
return JXL_API_ERROR("the second box must be the ftyp box");
|
||||
return JXL_INPUT_ERROR("the second box must be the ftyp box");
|
||||
}
|
||||
if (memcmp(dec->box_type, "ftyp", 4) == 0 && dec->box_count != 2) {
|
||||
return JXL_API_ERROR("the ftyp box must come second");
|
||||
return JXL_INPUT_ERROR("the ftyp box must come second");
|
||||
}
|
||||
|
||||
dec->box_contents_unbounded = (box_size == 0);
|
||||
@ -1841,7 +1837,7 @@ static JxlDecoderStatus HandleBoxes(JxlDecoder* dec) {
|
||||
dec->box_stage = BoxStage::kFtyp;
|
||||
} else if (memcmp(dec->box_type, "jxlc", 4) == 0) {
|
||||
if (dec->last_codestream_seen) {
|
||||
return JXL_API_ERROR("there can only be one jxlc box");
|
||||
return JXL_INPUT_ERROR("there can only be one jxlc box");
|
||||
}
|
||||
dec->last_codestream_seen = true;
|
||||
dec->box_stage = BoxStage::kCodestream;
|
||||
@ -1851,7 +1847,7 @@ static JxlDecoderStatus HandleBoxes(JxlDecoder* dec) {
|
||||
} else if ((dec->orig_events_wanted & JXL_DEC_JPEG_RECONSTRUCTION) &&
|
||||
memcmp(dec->box_type, "jbrd", 4) == 0) {
|
||||
if (!(dec->events_wanted & JXL_DEC_JPEG_RECONSTRUCTION)) {
|
||||
return JXL_API_ERROR(
|
||||
return JXL_INPUT_ERROR(
|
||||
"multiple JPEG reconstruction boxes not supported");
|
||||
}
|
||||
dec->box_stage = BoxStage::kJpegRecon;
|
||||
@ -1867,22 +1863,22 @@ static JxlDecoderStatus HandleBoxes(JxlDecoder* dec) {
|
||||
}
|
||||
} else if (dec->box_stage == BoxStage::kFtyp) {
|
||||
if (dec->box_contents_size < 12) {
|
||||
return JXL_API_ERROR("file type box too small");
|
||||
return JXL_INPUT_ERROR("file type box too small");
|
||||
}
|
||||
if (dec->avail_in < 4) return JXL_DEC_NEED_MORE_INPUT;
|
||||
if (memcmp(dec->next_in, "jxl ", 4) != 0) {
|
||||
return JXL_API_ERROR("file type box major brand must be \"jxl \"");
|
||||
return JXL_INPUT_ERROR("file type box major brand must be \"jxl \"");
|
||||
}
|
||||
dec->AdvanceInput(4);
|
||||
dec->box_stage = BoxStage::kSkip;
|
||||
} else if (dec->box_stage == BoxStage::kPartialCodestream) {
|
||||
if (dec->last_codestream_seen) {
|
||||
return JXL_API_ERROR("cannot have jxlp box after last jxlp box");
|
||||
return JXL_INPUT_ERROR("cannot have jxlp box after last jxlp box");
|
||||
}
|
||||
// TODO(lode): error if box is unbounded but last bit not set
|
||||
if (dec->avail_in < 4) return JXL_DEC_NEED_MORE_INPUT;
|
||||
if (!dec->box_contents_unbounded && dec->box_contents_size < 4) {
|
||||
return JXL_API_ERROR("jxlp box too small to contain index");
|
||||
return JXL_INPUT_ERROR("jxlp box too small to contain index");
|
||||
}
|
||||
size_t jxlp_index = LoadBE32(dec->next_in);
|
||||
// The high bit of jxlp_index indicates whether this is the last
|
||||
@ -1946,22 +1942,22 @@ static JxlDecoderStatus HandleBoxes(JxlDecoder* dec) {
|
||||
size_t num_xmp = jxl::JxlToJpegDecoder::NumXmpMarkers(*jpeg_data);
|
||||
if (num_exif) {
|
||||
if (num_exif > 1) {
|
||||
return JXL_API_ERROR(
|
||||
return JXL_INPUT_ERROR(
|
||||
"multiple exif markers for JPEG reconstruction not supported");
|
||||
}
|
||||
if (JXL_DEC_SUCCESS != jxl::JxlToJpegDecoder::ExifBoxContentSize(
|
||||
*jpeg_data, &dec->recon_exif_size)) {
|
||||
return JXL_API_ERROR("invalid jbrd exif size");
|
||||
return JXL_INPUT_ERROR("invalid jbrd exif size");
|
||||
}
|
||||
}
|
||||
if (num_xmp) {
|
||||
if (num_xmp > 1) {
|
||||
return JXL_API_ERROR(
|
||||
return JXL_INPUT_ERROR(
|
||||
"multiple XMP markers for JPEG reconstruction not supported");
|
||||
}
|
||||
if (JXL_DEC_SUCCESS != jxl::JxlToJpegDecoder::XmlBoxContentSize(
|
||||
*jpeg_data, &dec->recon_xmp_size)) {
|
||||
return JXL_API_ERROR("invalid jbrd XMP size");
|
||||
return JXL_INPUT_ERROR("invalid jbrd XMP size");
|
||||
}
|
||||
}
|
||||
|
||||
@ -2027,10 +2023,10 @@ JxlDecoderStatus JxlDecoderProcessInput(JxlDecoder* dec) {
|
||||
|
||||
if (!dec->got_signature) {
|
||||
JxlSignature sig = JxlSignatureCheck(dec->next_in, dec->avail_in);
|
||||
if (sig == JXL_SIG_INVALID) return JXL_API_ERROR("invalid signature");
|
||||
if (sig == JXL_SIG_INVALID) return JXL_INPUT_ERROR("invalid signature");
|
||||
if (sig == JXL_SIG_NOT_ENOUGH_BYTES) {
|
||||
if (dec->input_closed) {
|
||||
return JXL_API_ERROR("file too small for signature");
|
||||
return JXL_INPUT_ERROR("file too small for signature");
|
||||
}
|
||||
return JXL_DEC_NEED_MORE_INPUT;
|
||||
}
|
||||
@ -2047,18 +2043,18 @@ JxlDecoderStatus JxlDecoderProcessInput(JxlDecoder* dec) {
|
||||
JxlDecoderStatus status = HandleBoxes(dec);
|
||||
|
||||
if (status == JXL_DEC_NEED_MORE_INPUT && dec->input_closed) {
|
||||
return JXL_API_ERROR("missing input");
|
||||
return JXL_INPUT_ERROR("premature end of input");
|
||||
}
|
||||
|
||||
// Even if the box handling returns success, certain types of
|
||||
// data may be missing.
|
||||
if (status == JXL_DEC_SUCCESS) {
|
||||
if (dec->CanUseMoreCodestreamInput()) {
|
||||
return JXL_API_ERROR("codestream never finished");
|
||||
return JXL_INPUT_ERROR("codestream never finished");
|
||||
}
|
||||
#if JPEGXL_ENABLE_TRANSCODE_JPEG
|
||||
if (dec->JbrdNeedMoreBoxes()) {
|
||||
return JXL_API_ERROR("missing metadata boxes for jpeg reconstruction");
|
||||
return JXL_INPUT_ERROR("missing metadata boxes for jpeg reconstruction");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -2769,12 +2765,11 @@ template <typename T>
|
||||
JxlDecoderStatus VerifyOutputBitDepth(JxlBitDepth bit_depth, const T& metadata,
|
||||
JxlPixelFormat format) {
|
||||
uint32_t bits_per_sample = GetBitDepth(bit_depth, metadata, format);
|
||||
if (format.data_type == JXL_TYPE_UINT8 &&
|
||||
(bits_per_sample == 0 || bits_per_sample > 8)) {
|
||||
if (bits_per_sample == 0) return JXL_API_ERROR("Invalid output bit depth");
|
||||
if (format.data_type == JXL_TYPE_UINT8 && bits_per_sample > 8) {
|
||||
return JXL_API_ERROR("Invalid bit depth %u for uint8 output",
|
||||
bits_per_sample);
|
||||
} else if (format.data_type == JXL_TYPE_UINT16 &&
|
||||
(bits_per_sample == 0 || bits_per_sample > 16)) {
|
||||
} else if (format.data_type == JXL_TYPE_UINT16 && bits_per_sample > 16) {
|
||||
return JXL_API_ERROR("Invalid bit depth %u for uint16 output",
|
||||
bits_per_sample);
|
||||
}
|
||||
|
50
third_party/jpeg-xl/lib/jxl/decode_test.cc
vendored
50
third_party/jpeg-xl/lib/jxl/decode_test.cc
vendored
@ -242,7 +242,7 @@ PaddedBytes CreateTestJXLCodestream(Span<const uint8_t> pixels, size_t xsize,
|
||||
// the hardcoded ICC profile we attach requires RGB.
|
||||
EXPECT_EQ(false, grayscale);
|
||||
EXPECT_TRUE(params.color_space.empty());
|
||||
EXPECT_TRUE(color_encoding.SetICC(GetIccTestProfile()));
|
||||
EXPECT_TRUE(color_encoding.SetICC(GetIccTestProfile(), &GetJxlCms()));
|
||||
} else if (!params.color_space.empty()) {
|
||||
JxlColorEncoding c;
|
||||
EXPECT_TRUE(jxl::ParseDescription(params.color_space, &c));
|
||||
@ -269,22 +269,22 @@ PaddedBytes CreateTestJXLCodestream(Span<const uint8_t> pixels, size_t xsize,
|
||||
&io.Main()));
|
||||
jxl::PaddedBytes jpeg_data;
|
||||
if (params.jpeg_codestream != nullptr) {
|
||||
#if JPEGXL_ENABLE_JPEG
|
||||
std::vector<uint8_t> jpeg_bytes;
|
||||
io.jpeg_quality = 70;
|
||||
EXPECT_TRUE(Encode(io, extras::Codec::kJPG, io.metadata.m.color_encoding,
|
||||
/*bits_per_sample=*/8, &jpeg_bytes, &pool));
|
||||
params.jpeg_codestream->append(jpeg_bytes.data(),
|
||||
jpeg_bytes.data() + jpeg_bytes.size());
|
||||
EXPECT_TRUE(jxl::jpeg::DecodeImageJPG(
|
||||
jxl::Span<const uint8_t>(jpeg_bytes.data(), jpeg_bytes.size()), &io));
|
||||
EXPECT_TRUE(
|
||||
EncodeJPEGData(*io.Main().jpeg_data, &jpeg_data, params.cparams));
|
||||
io.metadata.m.xyb_encoded = false;
|
||||
#else // JPEGXL_ENABLE_JPEG
|
||||
JXL_ABORT(
|
||||
"unable to create reconstructible JPEG without JPEG support enabled");
|
||||
#endif // JPEGXL_ENABLE_JPEG
|
||||
if (jxl::extras::CanDecode(jxl::extras::Codec::kJPG)) {
|
||||
std::vector<uint8_t> jpeg_bytes;
|
||||
io.jpeg_quality = 70;
|
||||
EXPECT_TRUE(Encode(io, extras::Codec::kJPG, io.metadata.m.color_encoding,
|
||||
/*bits_per_sample=*/8, &jpeg_bytes, &pool));
|
||||
params.jpeg_codestream->append(jpeg_bytes.data(),
|
||||
jpeg_bytes.data() + jpeg_bytes.size());
|
||||
EXPECT_TRUE(jxl::jpeg::DecodeImageJPG(
|
||||
jxl::Span<const uint8_t>(jpeg_bytes.data(), jpeg_bytes.size()), &io));
|
||||
EXPECT_TRUE(
|
||||
EncodeJPEGData(*io.Main().jpeg_data, &jpeg_data, params.cparams));
|
||||
io.metadata.m.xyb_encoded = false;
|
||||
} else {
|
||||
JXL_ABORT(
|
||||
"unable to create reconstructible JPEG without JPEG support enabled");
|
||||
}
|
||||
}
|
||||
if (params.preview_mode) {
|
||||
io.preview_frame = io.Main().Copy();
|
||||
@ -740,7 +740,8 @@ std::vector<uint8_t> GetTestHeader(size_t xsize, size_t ysize,
|
||||
|
||||
if (!icc_profile.empty()) {
|
||||
jxl::PaddedBytes copy = icc_profile;
|
||||
EXPECT_TRUE(metadata.m.color_encoding.SetICC(std::move(copy)));
|
||||
EXPECT_TRUE(
|
||||
metadata.m.color_encoding.SetICC(std::move(copy), &jxl::GetJxlCms()));
|
||||
}
|
||||
|
||||
EXPECT_TRUE(jxl::Bundle::Write(metadata.m, &writer, 0, nullptr));
|
||||
@ -1644,7 +1645,7 @@ TEST(DecodeTest, PixelTestWithICCProfileLossy) {
|
||||
// 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()));
|
||||
EXPECT_TRUE(color_encoding0.SetICC(GetIccTestProfile(), &jxl::GetJxlCms()));
|
||||
jxl::Span<const uint8_t> span0(pixels.data(), pixels.size());
|
||||
jxl::CodecInOut io0;
|
||||
io0.SetSize(xsize, ysize);
|
||||
@ -1653,7 +1654,7 @@ TEST(DecodeTest, PixelTestWithICCProfileLossy) {
|
||||
/*pool=*/nullptr, &io0.Main()));
|
||||
|
||||
jxl::ColorEncoding color_encoding1;
|
||||
EXPECT_TRUE(color_encoding1.SetICC(std::move(icc)));
|
||||
EXPECT_TRUE(color_encoding1.SetICC(std::move(icc), &jxl::GetJxlCms()));
|
||||
jxl::Span<const uint8_t> span1(pixels2.data(), pixels2.size());
|
||||
jxl::CodecInOut io1;
|
||||
io1.SetSize(xsize, ysize);
|
||||
@ -2302,12 +2303,11 @@ void TestPartialStream(bool reconstructible_jpeg) {
|
||||
// should return JXL_DEC_NEED_MORE_INPUT, not error.
|
||||
TEST(DecodeTest, PixelPartialTest) { TestPartialStream(false); }
|
||||
|
||||
#if JPEGXL_ENABLE_JPEG
|
||||
// Tests the return status when trying to decode JPEG bytes on incomplete file.
|
||||
TEST(DecodeTest, JXL_TRANSCODE_JPEG_TEST(JPEGPartialTest)) {
|
||||
TEST_LIBJPEG_SUPPORT();
|
||||
TestPartialStream(true);
|
||||
}
|
||||
#endif // JPEGXL_ENABLE_JPEG
|
||||
|
||||
// The DC event still exists, but is no longer implemented, it is deprecated.
|
||||
TEST(DecodeTest, DCNotGettableTest) {
|
||||
@ -4031,8 +4031,8 @@ TEST(DecodeTest, InputHandlingTestOneShot) {
|
||||
}
|
||||
}
|
||||
|
||||
#if JPEGXL_ENABLE_JPEG
|
||||
TEST(DecodeTest, JXL_TRANSCODE_JPEG_TEST(InputHandlingTestJPEGOneshot)) {
|
||||
TEST_LIBJPEG_SUPPORT();
|
||||
size_t xsize = 123;
|
||||
size_t ysize = 77;
|
||||
size_t channels = 3;
|
||||
@ -4122,7 +4122,6 @@ TEST(DecodeTest, JXL_TRANSCODE_JPEG_TEST(InputHandlingTestJPEGOneshot)) {
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // JPEGXL_ENABLE_JPEG
|
||||
|
||||
TEST(DecodeTest, InputHandlingTestStreaming) {
|
||||
size_t xsize = 508, ysize = 470;
|
||||
@ -4805,8 +4804,8 @@ void VerifyJPEGReconstruction(const jxl::PaddedBytes& container,
|
||||
EXPECT_EQ(0, memcmp(reconstructed_buffer.data(), jpeg_bytes.data(), used));
|
||||
}
|
||||
|
||||
#if JPEGXL_ENABLE_JPEG
|
||||
TEST(DecodeTest, JXL_TRANSCODE_JPEG_TEST(JPEGReconstructTestCodestream)) {
|
||||
TEST_LIBJPEG_SUPPORT();
|
||||
size_t xsize = 123;
|
||||
size_t ysize = 77;
|
||||
size_t channels = 3;
|
||||
@ -4823,7 +4822,6 @@ TEST(DecodeTest, JXL_TRANSCODE_JPEG_TEST(JPEGReconstructTestCodestream)) {
|
||||
channels, params);
|
||||
VerifyJPEGReconstruction(compressed, jpeg_codestream);
|
||||
}
|
||||
#endif // JPEGXL_ENABLE_JPEG
|
||||
|
||||
TEST(DecodeTest, JXL_TRANSCODE_JPEG_TEST(JPEGReconstructionTest)) {
|
||||
const std::string jpeg_path = "jxl/flower/flower.png.im_q85_420.jpg";
|
||||
|
@ -12,7 +12,7 @@ namespace jxl {
|
||||
JxlDecoderStatus JxlToJpegDecoder::Process(const uint8_t** next_in,
|
||||
size_t* avail_in) {
|
||||
if (!inside_box_) {
|
||||
JXL_ABORT(
|
||||
JXL_UNREACHABLE(
|
||||
"processing of JPEG reconstruction data outside JPEG reconstruction "
|
||||
"box");
|
||||
}
|
||||
@ -38,7 +38,7 @@ JxlDecoderStatus JxlToJpegDecoder::Process(const uint8_t** next_in,
|
||||
to_decode = Span<const uint8_t>(buffer_.data(), buffer_.size());
|
||||
}
|
||||
if (!box_until_eof_ && to_decode.size() > box_size_) {
|
||||
JXL_ABORT("JPEG reconstruction data to decode larger than expected");
|
||||
JXL_UNREACHABLE("JPEG reconstruction data to decode larger than expected");
|
||||
}
|
||||
if (box_until_eof_ || to_decode.size() == box_size_) {
|
||||
// If undefined size, or the right size, try to decode.
|
||||
|
19
third_party/jpeg-xl/lib/jxl/enc_ac_strategy.cc
vendored
19
third_party/jpeg-xl/lib/jxl/enc_ac_strategy.cc
vendored
@ -26,6 +26,7 @@
|
||||
#include "lib/jxl/convolve.h"
|
||||
#include "lib/jxl/dct_scales.h"
|
||||
#include "lib/jxl/enc_aux_out.h"
|
||||
#include "lib/jxl/enc_debug_image.h"
|
||||
#include "lib/jxl/enc_params.h"
|
||||
#include "lib/jxl/enc_transforms-inl.h"
|
||||
#include "lib/jxl/entropy_coder.h"
|
||||
@ -44,12 +45,18 @@
|
||||
// sensitive to some kind of degradation. Unfortunately image quality
|
||||
// is still more of an art than science.
|
||||
|
||||
// Set JXL_DEBUG_AC_STRATEGY to 1 to enable debugging.
|
||||
#ifndef JXL_DEBUG_AC_STRATEGY
|
||||
#define JXL_DEBUG_AC_STRATEGY 0
|
||||
#endif
|
||||
|
||||
// This must come before the begin/end_target, but HWY_ONCE is only true
|
||||
// after that, so use an "include guard".
|
||||
#ifndef LIB_JXL_ENC_AC_STRATEGY_
|
||||
#define LIB_JXL_ENC_AC_STRATEGY_
|
||||
// Parameters of the heuristic are marked with a OPTIMIZE comment.
|
||||
namespace jxl {
|
||||
namespace {
|
||||
|
||||
// Debugging utilities.
|
||||
|
||||
@ -207,7 +214,8 @@ const uint8_t* TypeMask(const uint8_t& raw_strategy) {
|
||||
}
|
||||
|
||||
void DumpAcStrategy(const AcStrategyImage& ac_strategy, size_t xsize,
|
||||
size_t ysize, const char* tag, AuxOut* aux_out) {
|
||||
size_t ysize, const char* tag, AuxOut* aux_out,
|
||||
const CompressParams& cparams) {
|
||||
Image3F color_acs(xsize, ysize);
|
||||
for (size_t y = 0; y < ysize; y++) {
|
||||
float* JXL_RESTRICT rows[3] = {
|
||||
@ -259,9 +267,10 @@ void DumpAcStrategy(const AcStrategyImage& ac_strategy, size_t xsize,
|
||||
}
|
||||
}
|
||||
}
|
||||
aux_out->DumpImage(tag, color_acs);
|
||||
DumpImage(cparams, tag, color_acs);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace jxl
|
||||
#endif // LIB_JXL_ENC_AC_STRATEGY_
|
||||
|
||||
@ -1156,9 +1165,11 @@ void AcStrategyHeuristics::Finalize(AuxOut* aux_out) {
|
||||
ac_strategy.CountBlocks(AcStrategy::Type::DCT64X64);
|
||||
}
|
||||
|
||||
if (WantDebugOutput(aux_out)) {
|
||||
// if (JXL_DEBUG_AC_STRATEGY && WantDebugOutput(aux_out)) {
|
||||
if (JXL_DEBUG_AC_STRATEGY && WantDebugOutput(enc_state->cparams)) {
|
||||
DumpAcStrategy(ac_strategy, enc_state->shared.frame_dim.xsize,
|
||||
enc_state->shared.frame_dim.ysize, "ac_strategy", aux_out);
|
||||
enc_state->shared.frame_dim.ysize, "ac_strategy", aux_out,
|
||||
enc_state->cparams);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,10 +65,6 @@ struct AcStrategyHeuristics {
|
||||
PassesEncoderState* enc_state;
|
||||
};
|
||||
|
||||
// Debug.
|
||||
void DumpAcStrategy(const AcStrategyImage& ac_strategy, size_t xsize,
|
||||
size_t ysize, const char* tag, AuxOut* aux_out);
|
||||
|
||||
} // namespace jxl
|
||||
|
||||
#endif // LIB_JXL_ENC_AC_STRATEGY_H_
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "lib/jxl/enc_aux_out.h"
|
||||
#include "lib/jxl/enc_butteraugli_comparator.h"
|
||||
#include "lib/jxl/enc_cache.h"
|
||||
#include "lib/jxl/enc_debug_image.h"
|
||||
#include "lib/jxl/enc_group.h"
|
||||
#include "lib/jxl/enc_modular.h"
|
||||
#include "lib/jxl/enc_params.h"
|
||||
@ -46,6 +47,12 @@
|
||||
#include "lib/jxl/image_ops.h"
|
||||
#include "lib/jxl/opsin_params.h"
|
||||
#include "lib/jxl/quant_weights.h"
|
||||
|
||||
// Set JXL_DEBUG_ADAPTIVE_QUANTIZATION to 1 to enable debugging.
|
||||
#ifndef JXL_DEBUG_ADAPTIVE_QUANTIZATION
|
||||
#define JXL_DEBUG_ADAPTIVE_QUANTIZATION 0
|
||||
#endif
|
||||
|
||||
HWY_BEFORE_NAMESPACE();
|
||||
namespace jxl {
|
||||
namespace HWY_NAMESPACE {
|
||||
@ -623,38 +630,43 @@ namespace jxl {
|
||||
HWY_EXPORT(AdaptiveQuantizationMap);
|
||||
|
||||
namespace {
|
||||
// If true, prints the quantization maps at each iteration.
|
||||
bool FLAGS_dump_quant_state = false;
|
||||
|
||||
void DumpHeatmap(const AuxOut* aux_out, const std::string& label,
|
||||
const ImageF& image, float good_threshold,
|
||||
float bad_threshold) {
|
||||
Image3F heatmap = CreateHeatMapImage(image, good_threshold, bad_threshold);
|
||||
char filename[200];
|
||||
snprintf(filename, sizeof(filename), "%s%05d", label.c_str(),
|
||||
aux_out->num_butteraugli_iters);
|
||||
aux_out->DumpImage(filename, heatmap);
|
||||
// If true, prints the quantization maps at each iteration.
|
||||
constexpr bool FLAGS_dump_quant_state = false;
|
||||
|
||||
void DumpHeatmap(const CompressParams& cparams, const AuxOut* aux_out,
|
||||
const std::string& label, const ImageF& image,
|
||||
float good_threshold, float bad_threshold) {
|
||||
if (JXL_DEBUG_ADAPTIVE_QUANTIZATION) {
|
||||
Image3F heatmap = CreateHeatMapImage(image, good_threshold, bad_threshold);
|
||||
char filename[200];
|
||||
snprintf(filename, sizeof(filename), "%s%05d", label.c_str(),
|
||||
aux_out->num_butteraugli_iters);
|
||||
DumpImage(cparams, filename, heatmap);
|
||||
}
|
||||
}
|
||||
|
||||
void DumpHeatmaps(const AuxOut* aux_out, float ba_target,
|
||||
const ImageF& quant_field, const ImageF& tile_heatmap,
|
||||
const ImageF& bt_diffmap) {
|
||||
if (!WantDebugOutput(aux_out)) return;
|
||||
ImageF inv_qmap(quant_field.xsize(), quant_field.ysize());
|
||||
for (size_t y = 0; y < quant_field.ysize(); ++y) {
|
||||
const float* JXL_RESTRICT row_q = quant_field.ConstRow(y);
|
||||
float* JXL_RESTRICT row_inv_q = inv_qmap.Row(y);
|
||||
for (size_t x = 0; x < quant_field.xsize(); ++x) {
|
||||
row_inv_q[x] = 1.0f / row_q[x]; // never zero
|
||||
void DumpHeatmaps(const CompressParams& cparams, const AuxOut* aux_out,
|
||||
float ba_target, const ImageF& quant_field,
|
||||
const ImageF& tile_heatmap, const ImageF& bt_diffmap) {
|
||||
if (JXL_DEBUG_ADAPTIVE_QUANTIZATION) {
|
||||
if (!WantDebugOutput(cparams)) return;
|
||||
ImageF inv_qmap(quant_field.xsize(), quant_field.ysize());
|
||||
for (size_t y = 0; y < quant_field.ysize(); ++y) {
|
||||
const float* JXL_RESTRICT row_q = quant_field.ConstRow(y);
|
||||
float* JXL_RESTRICT row_inv_q = inv_qmap.Row(y);
|
||||
for (size_t x = 0; x < quant_field.xsize(); ++x) {
|
||||
row_inv_q[x] = 1.0f / row_q[x]; // never zero
|
||||
}
|
||||
}
|
||||
DumpHeatmap(cparams, aux_out, "quant_heatmap", inv_qmap, 4.0f * ba_target,
|
||||
6.0f * ba_target);
|
||||
DumpHeatmap(cparams, aux_out, "tile_heatmap", tile_heatmap, ba_target,
|
||||
1.5f * ba_target);
|
||||
// matches heat maps produced by the command line tool.
|
||||
DumpHeatmap(cparams, aux_out, "bt_diffmap", bt_diffmap,
|
||||
ButteraugliFuzzyInverse(1.5), ButteraugliFuzzyInverse(0.5));
|
||||
}
|
||||
DumpHeatmap(aux_out, "quant_heatmap", inv_qmap, 4.0f * ba_target,
|
||||
6.0f * ba_target);
|
||||
DumpHeatmap(aux_out, "tile_heatmap", tile_heatmap, ba_target,
|
||||
1.5f * ba_target);
|
||||
// matches heat maps produced by the command line tool.
|
||||
DumpHeatmap(aux_out, "bt_diffmap", bt_diffmap, ButteraugliFuzzyInverse(1.5),
|
||||
ButteraugliFuzzyInverse(0.5));
|
||||
}
|
||||
|
||||
ImageF TileDistMap(const ImageF& distmap, int tile_size, int margin,
|
||||
@ -799,6 +811,8 @@ ImageBundle RoundtripImage(const Image3F& opsin, PassesEncoderState* enc_state,
|
||||
return decoded;
|
||||
}
|
||||
|
||||
constexpr int kMaxButteraugliIters = 4;
|
||||
|
||||
void FindBestQuantization(const ImageBundle& linear, const Image3F& opsin,
|
||||
PassesEncoderState* enc_state,
|
||||
const JxlCmsInterface& cms, ThreadPool* pool,
|
||||
@ -838,7 +852,7 @@ void FindBestQuantization(const ImageBundle& linear, const Image3F& opsin,
|
||||
|
||||
const float butteraugli_target = cparams.butteraugli_distance;
|
||||
const float original_butteraugli = cparams.original_butteraugli_distance;
|
||||
ButteraugliParams params = cparams.ba_params;
|
||||
ButteraugliParams params;
|
||||
params.intensity_target = linear.metadata()->IntensityTarget();
|
||||
// Hack the default intensity target value to be 80.0, the intensity
|
||||
// target of sRGB images and a more reasonable viewing default than
|
||||
@ -869,15 +883,12 @@ void FindBestQuantization(const ImageBundle& linear, const Image3F& opsin,
|
||||
JXL_ASSERT(qf_higher / qf_lower < 253);
|
||||
|
||||
constexpr int kOriginalComparisonRound = 1;
|
||||
int iters = cparams.max_butteraugli_iters;
|
||||
if (iters > 7) {
|
||||
iters = 7;
|
||||
}
|
||||
int iters = kMaxButteraugliIters;
|
||||
if (cparams.speed_tier != SpeedTier::kTortoise) {
|
||||
iters = 2;
|
||||
}
|
||||
for (int i = 0; i < iters + 1; ++i) {
|
||||
if (FLAGS_dump_quant_state) {
|
||||
if (JXL_DEBUG_ADAPTIVE_QUANTIZATION) {
|
||||
printf("\nQuantization field:\n");
|
||||
for (size_t y = 0; y < quant_field.ysize(); ++y) {
|
||||
for (size_t x = 0; x < quant_field.xsize(); ++x) {
|
||||
@ -897,16 +908,16 @@ void FindBestQuantization(const ImageBundle& linear, const Image3F& opsin,
|
||||
}
|
||||
tile_distmap = TileDistMap(diffmap, 8 * cparams.resampling, 0,
|
||||
enc_state->shared.ac_strategy);
|
||||
if (WantDebugOutput(aux_out)) {
|
||||
aux_out->DumpImage(("dec" + ToString(i)).c_str(), *dec_linear.color());
|
||||
DumpHeatmaps(aux_out, butteraugli_target, quant_field, tile_distmap,
|
||||
diffmap);
|
||||
if (JXL_DEBUG_ADAPTIVE_QUANTIZATION && WantDebugOutput(cparams)) {
|
||||
DumpImage(cparams, ("dec" + ToString(i)).c_str(), *dec_linear.color());
|
||||
DumpHeatmaps(cparams, aux_out, butteraugli_target, quant_field,
|
||||
tile_distmap, diffmap);
|
||||
}
|
||||
if (aux_out != nullptr) ++aux_out->num_butteraugli_iters;
|
||||
if (cparams.log_search_state) {
|
||||
if (JXL_DEBUG_ADAPTIVE_QUANTIZATION) {
|
||||
float minval, maxval;
|
||||
ImageMinMax(quant_field, &minval, &maxval);
|
||||
printf("\nButteraugli iter: %d/%d\n", i, cparams.max_butteraugli_iters);
|
||||
printf("\nButteraugli iter: %d/%d\n", i, kMaxButteraugliIters);
|
||||
printf("Butteraugli distance: %f (target = %f)\n", score,
|
||||
original_butteraugli);
|
||||
printf("quant range: %f ... %f DC quant: %f\n", minval, maxval,
|
||||
@ -1016,16 +1027,15 @@ void FindBestQuantizationMaxError(const Image3F& opsin,
|
||||
1.0f / enc_state->cparams.max_error[1],
|
||||
1.0f / enc_state->cparams.max_error[2]};
|
||||
|
||||
for (int i = 0; i < cparams.max_butteraugli_iters + 1; ++i) {
|
||||
for (int i = 0; i < kMaxButteraugliIters + 1; ++i) {
|
||||
quantizer.SetQuantField(initial_quant_dc, quant_field, &raw_quant_field);
|
||||
if (aux_out) {
|
||||
aux_out->DumpXybImage(("ops" + ToString(i)).c_str(), opsin);
|
||||
if (JXL_DEBUG_ADAPTIVE_QUANTIZATION && aux_out) {
|
||||
DumpXybImage(cparams, ("ops" + ToString(i)).c_str(), opsin);
|
||||
}
|
||||
ImageBundle decoded = RoundtripImage(opsin, enc_state, cms, pool);
|
||||
if (aux_out) {
|
||||
aux_out->DumpXybImage(("dec" + ToString(i)).c_str(), *decoded.color());
|
||||
if (JXL_DEBUG_ADAPTIVE_QUANTIZATION && aux_out) {
|
||||
DumpXybImage(cparams, ("dec" + ToString(i)).c_str(), *decoded.color());
|
||||
}
|
||||
|
||||
for (size_t by = 0; by < enc_state->shared.frame_dim.ysize_blocks; by++) {
|
||||
AcStrategyRow ac_strategy_row =
|
||||
enc_state->shared.ac_strategy.ConstRow(by);
|
||||
|
@ -44,7 +44,7 @@ ImageF InitialQuantField(float butteraugli_target, const Image3F& opsin,
|
||||
float InitialQuantDC(float butteraugli_target);
|
||||
|
||||
void AdjustQuantField(const AcStrategyImage& ac_strategy, const Rect& rect,
|
||||
float original_butteraugli, ImageF* quant_field);
|
||||
float butteraugli_target, ImageF* quant_field);
|
||||
|
||||
// Returns a quantizer that uses an adjusted version of the provided
|
||||
// quant_field. Also computes the dequant_map corresponding to the given
|
||||
|
7
third_party/jpeg-xl/lib/jxl/enc_ans.cc
vendored
7
third_party/jpeg-xl/lib/jxl/enc_ans.cc
vendored
@ -32,7 +32,10 @@ namespace jxl {
|
||||
|
||||
namespace {
|
||||
|
||||
bool ans_fuzzer_friendly_ = false;
|
||||
#if !JXL_IS_DEBUG_BUILD
|
||||
constexpr
|
||||
#endif
|
||||
bool ans_fuzzer_friendly_ = false;
|
||||
|
||||
static const int kMaxNumSymbolsForSmallCode = 4;
|
||||
|
||||
@ -1463,7 +1466,7 @@ void ApplyLZ77(const HistogramParams& params, size_t num_contexts,
|
||||
} else if (params.lz77_method == HistogramParams::LZ77Method::kOptimal) {
|
||||
ApplyLZ77_Optimal(params, num_contexts, tokens, lz77, tokens_lz77);
|
||||
} else {
|
||||
JXL_ABORT("Not implemented");
|
||||
JXL_UNREACHABLE("Not implemented");
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
150
third_party/jpeg-xl/lib/jxl/enc_aux_out.cc
vendored
150
third_party/jpeg-xl/lib/jxl/enc_aux_out.cc
vendored
@ -16,9 +16,6 @@
|
||||
|
||||
#include "lib/jxl/base/printf_macros.h"
|
||||
#include "lib/jxl/base/status.h"
|
||||
#include "lib/jxl/color_encoding_internal.h"
|
||||
#include "lib/jxl/dec_xyb.h"
|
||||
#include "lib/jxl/image_ops.h"
|
||||
|
||||
namespace jxl {
|
||||
|
||||
@ -55,21 +52,24 @@ const char* LayerName(size_t layer) {
|
||||
case kLayerModularAcGroup:
|
||||
return "ModularAcGroup";
|
||||
default:
|
||||
JXL_ABORT("Invalid layer %d\n", static_cast<int>(layer));
|
||||
JXL_UNREACHABLE("Invalid layer %d\n", static_cast<int>(layer));
|
||||
}
|
||||
}
|
||||
|
||||
void AuxOut::LayerTotals::Print(size_t num_inputs) const {
|
||||
printf("%10" PRId64, static_cast<int64_t>(total_bits));
|
||||
if (histogram_bits != 0) {
|
||||
printf(" [c/i:%6.2f | hst:%8" PRId64 " | ex:%8" PRId64 " | h+c+e:%12.3f",
|
||||
num_clustered_histograms * 1.0 / num_inputs,
|
||||
static_cast<int64_t>(histogram_bits >> 3),
|
||||
static_cast<int64_t>(extra_bits >> 3),
|
||||
(histogram_bits + clustered_entropy + extra_bits) / 8.0);
|
||||
printf("]");
|
||||
if (JXL_DEBUG_V_LEVEL > 0) {
|
||||
printf("%10" PRId64, static_cast<int64_t>(total_bits));
|
||||
if (histogram_bits != 0) {
|
||||
printf(" [c/i:%6.2f | hst:%8" PRId64 " | ex:%8" PRId64
|
||||
" | h+c+e:%12.3f",
|
||||
num_clustered_histograms * 1.0 / num_inputs,
|
||||
static_cast<int64_t>(histogram_bits >> 3),
|
||||
static_cast<int64_t>(extra_bits >> 3),
|
||||
(histogram_bits + clustered_entropy + extra_bits) / 8.0);
|
||||
printf("]");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void AuxOut::Assimilate(const AuxOut& victim) {
|
||||
@ -89,117 +89,39 @@ void AuxOut::Assimilate(const AuxOut& victim) {
|
||||
num_dct32x64_blocks += victim.num_dct32x64_blocks;
|
||||
num_dct64_blocks += victim.num_dct64_blocks;
|
||||
num_butteraugli_iters += victim.num_butteraugli_iters;
|
||||
for (size_t i = 0; i < dc_pred_usage.size(); ++i) {
|
||||
dc_pred_usage[i] += victim.dc_pred_usage[i];
|
||||
dc_pred_usage_xb[i] += victim.dc_pred_usage_xb[i];
|
||||
}
|
||||
max_quant_rescale = std::max(max_quant_rescale, victim.max_quant_rescale);
|
||||
min_quant_rescale = std::min(min_quant_rescale, victim.min_quant_rescale);
|
||||
max_bitrate_error = std::max(max_bitrate_error, victim.max_bitrate_error);
|
||||
min_bitrate_error = std::min(min_bitrate_error, victim.min_bitrate_error);
|
||||
}
|
||||
|
||||
void AuxOut::Print(size_t num_inputs) const {
|
||||
if (num_inputs == 0) return;
|
||||
if (JXL_DEBUG_V_LEVEL > 0) {
|
||||
if (num_inputs == 0) return;
|
||||
|
||||
LayerTotals all_layers;
|
||||
for (size_t i = 0; i < layers.size(); ++i) {
|
||||
all_layers.Assimilate(layers[i]);
|
||||
}
|
||||
|
||||
printf("Average butteraugli iters: %10.2f\n",
|
||||
num_butteraugli_iters * 1.0 / num_inputs);
|
||||
if (min_quant_rescale != 1.0 || max_quant_rescale != 1.0) {
|
||||
printf("quant rescale range: %f .. %f\n", min_quant_rescale,
|
||||
max_quant_rescale);
|
||||
printf("bitrate error range: %.3f%% .. %.3f%%\n",
|
||||
100.0f * min_bitrate_error, 100.0f * max_bitrate_error);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < layers.size(); ++i) {
|
||||
if (layers[i].total_bits != 0) {
|
||||
printf("Total layer bits %-10s\t", LayerName(i));
|
||||
printf("%10f%%", 100.0 * layers[i].total_bits / all_layers.total_bits);
|
||||
layers[i].Print(num_inputs);
|
||||
LayerTotals all_layers;
|
||||
for (size_t i = 0; i < layers.size(); ++i) {
|
||||
all_layers.Assimilate(layers[i]);
|
||||
}
|
||||
}
|
||||
printf("Total image size ");
|
||||
all_layers.Print(num_inputs);
|
||||
|
||||
const uint32_t dc_pred_total =
|
||||
std::accumulate(dc_pred_usage.begin(), dc_pred_usage.end(), 0u);
|
||||
const uint32_t dc_pred_total_xb =
|
||||
std::accumulate(dc_pred_usage_xb.begin(), dc_pred_usage_xb.end(), 0u);
|
||||
if (dc_pred_total + dc_pred_total_xb != 0) {
|
||||
printf("\nDC pred Y XB:\n");
|
||||
for (size_t i = 0; i < dc_pred_usage.size(); ++i) {
|
||||
printf(" %6u (%5.2f%%) %6u (%5.2f%%)\n", dc_pred_usage[i],
|
||||
100.0 * dc_pred_usage[i] / dc_pred_total, dc_pred_usage_xb[i],
|
||||
100.0 * dc_pred_usage_xb[i] / dc_pred_total_xb);
|
||||
}
|
||||
}
|
||||
printf("Average butteraugli iters: %10.2f\n",
|
||||
num_butteraugli_iters * 1.0 / num_inputs);
|
||||
|
||||
size_t total_blocks = 0;
|
||||
size_t total_positions = 0;
|
||||
if (total_blocks != 0 && total_positions != 0) {
|
||||
printf("\n\t\t Blocks\t\tPositions\t\t\tBlocks/Position\n");
|
||||
printf(" Total:\t\t %7" PRIuS "\t\t %7" PRIuS " \t\t\t%10f%%\n\n",
|
||||
total_blocks, total_positions,
|
||||
100.0 * total_blocks / total_positions);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void AuxOut::DumpImage(const char* label, const Image3<T>& image) const {
|
||||
if (!dump_image) return;
|
||||
if (debug_prefix.empty()) return;
|
||||
std::ostringstream pathname;
|
||||
pathname << debug_prefix << label << ".png";
|
||||
(void)dump_image(ConvertToFloat(image), ColorEncoding::SRGB(),
|
||||
pathname.str());
|
||||
}
|
||||
template void AuxOut::DumpImage(const char* label,
|
||||
const Image3<float>& image) const;
|
||||
template void AuxOut::DumpImage(const char* label,
|
||||
const Image3<uint8_t>& image) const;
|
||||
|
||||
template <typename T>
|
||||
void AuxOut::DumpPlaneNormalized(const char* label,
|
||||
const Plane<T>& image) const {
|
||||
T min;
|
||||
T max;
|
||||
ImageMinMax(image, &min, &max);
|
||||
Image3B normalized(image.xsize(), image.ysize());
|
||||
for (size_t c = 0; c < 3; ++c) {
|
||||
float mul = min == max ? 0 : (255.0f / (max - min));
|
||||
for (size_t y = 0; y < image.ysize(); ++y) {
|
||||
const T* JXL_RESTRICT row_in = image.ConstRow(y);
|
||||
uint8_t* JXL_RESTRICT row_out = normalized.PlaneRow(c, y);
|
||||
for (size_t x = 0; x < image.xsize(); ++x) {
|
||||
row_out[x] = static_cast<uint8_t>((row_in[x] - min) * mul);
|
||||
for (size_t i = 0; i < layers.size(); ++i) {
|
||||
if (layers[i].total_bits != 0) {
|
||||
printf("Total layer bits %-10s\t", LayerName(i));
|
||||
printf("%10f%%", 100.0 * layers[i].total_bits / all_layers.total_bits);
|
||||
layers[i].Print(num_inputs);
|
||||
}
|
||||
}
|
||||
printf("Total image size ");
|
||||
all_layers.Print(num_inputs);
|
||||
|
||||
size_t total_blocks = 0;
|
||||
size_t total_positions = 0;
|
||||
if (total_blocks != 0 && total_positions != 0) {
|
||||
printf("\n\t\t Blocks\t\tPositions\t\t\tBlocks/Position\n");
|
||||
printf(" Total:\t\t %7" PRIuS "\t\t %7" PRIuS " \t\t\t%10f%%\n\n",
|
||||
total_blocks, total_positions,
|
||||
100.0 * total_blocks / total_positions);
|
||||
}
|
||||
}
|
||||
DumpImage(label, normalized);
|
||||
}
|
||||
template void AuxOut::DumpPlaneNormalized(const char* label,
|
||||
const Plane<float>& image) const;
|
||||
template void AuxOut::DumpPlaneNormalized(const char* label,
|
||||
const Plane<uint8_t>& image) const;
|
||||
|
||||
void AuxOut::DumpXybImage(const char* label, const Image3F& image) const {
|
||||
if (!dump_image) return;
|
||||
if (debug_prefix.empty()) return;
|
||||
std::ostringstream pathname;
|
||||
pathname << debug_prefix << label << ".png";
|
||||
|
||||
Image3F linear(image.xsize(), image.ysize());
|
||||
OpsinParams opsin_params;
|
||||
opsin_params.Init(kDefaultIntensityTarget);
|
||||
OpsinToLinear(image, Rect(linear), nullptr, &linear, opsin_params);
|
||||
|
||||
(void)dump_image(std::move(linear), ColorEncoding::LinearSRGB(),
|
||||
pathname.str());
|
||||
}
|
||||
|
||||
} // namespace jxl
|
||||
|
61
third_party/jpeg-xl/lib/jxl/enc_aux_out.h
vendored
61
third_party/jpeg-xl/lib/jxl/enc_aux_out.h
vendored
@ -14,9 +14,6 @@
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#include "lib/jxl/image.h"
|
||||
#include "lib/jxl/jxl_inspection.h"
|
||||
|
||||
namespace jxl {
|
||||
|
||||
struct ColorEncoding;
|
||||
@ -82,27 +79,6 @@ struct AuxOut {
|
||||
return total;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void DumpImage(const char* label, const Image3<T>& image) const;
|
||||
|
||||
void DumpXybImage(const char* label, const Image3F& image) const;
|
||||
|
||||
template <typename T>
|
||||
void DumpPlaneNormalized(const char* label, const Plane<T>& image) const;
|
||||
|
||||
void SetInspectorImage3F(const jxl::InspectorImage3F& inspector) {
|
||||
inspector_image3f_ = inspector;
|
||||
}
|
||||
|
||||
// Allows hooking intermediate data inspection into various places of the
|
||||
// processing pipeline. Returns true iff processing should proceed.
|
||||
bool InspectImage3F(const char* label, const Image3F& image) {
|
||||
if (inspector_image3f_ != nullptr) {
|
||||
return inspector_image3f_(label, image);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::array<LayerTotals, kNumImageLayers> layers;
|
||||
size_t num_blocks = 0;
|
||||
|
||||
@ -119,45 +95,8 @@ struct AuxOut {
|
||||
size_t num_dct32x64_blocks = 0;
|
||||
size_t num_dct64_blocks = 0;
|
||||
|
||||
std::array<uint32_t, 8> dc_pred_usage = {{0}};
|
||||
std::array<uint32_t, 8> dc_pred_usage_xb = {{0}};
|
||||
|
||||
int num_butteraugli_iters = 0;
|
||||
|
||||
float max_quant_rescale = 1.0f;
|
||||
float min_quant_rescale = 1.0f;
|
||||
float min_bitrate_error = 0.0f;
|
||||
float max_bitrate_error = 0.0f;
|
||||
|
||||
// If not empty, additional debugging information (e.g. debug images) is
|
||||
// saved in files with this prefix.
|
||||
std::string debug_prefix;
|
||||
|
||||
// By how much the decoded image was downsampled relative to the encoded
|
||||
// image.
|
||||
size_t downsampling = 1;
|
||||
|
||||
jxl::InspectorImage3F inspector_image3f_;
|
||||
|
||||
std::function<Status(Image3F&&, const ColorEncoding&, const std::string&)>
|
||||
dump_image = nullptr;
|
||||
};
|
||||
|
||||
extern template void AuxOut::DumpImage(const char* label,
|
||||
const Image3<float>& image) const;
|
||||
extern template void AuxOut::DumpImage(const char* label,
|
||||
const Image3<uint8_t>& image) const;
|
||||
extern template void AuxOut::DumpPlaneNormalized(
|
||||
const char* label, const Plane<float>& image) const;
|
||||
extern template void AuxOut::DumpPlaneNormalized(
|
||||
const char* label, const Plane<uint8_t>& image) const;
|
||||
|
||||
// Used to skip image creation if they won't be written to debug directory.
|
||||
static inline bool WantDebugOutput(const AuxOut* aux_out) {
|
||||
// Need valid pointer and filename.
|
||||
return aux_out != nullptr && !aux_out->debug_prefix.empty();
|
||||
}
|
||||
|
||||
} // namespace jxl
|
||||
|
||||
#endif // LIB_JXL_AUX_OUT_H_
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user