зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1884859 - Update libjxl to f06a34c77b1bd11bafbe82989241e68c756ccca2 r=saschanaz
Differential Revision: https://phabricator.services.mozilla.com/D204327
This commit is contained in:
Родитель
a58d54f79b
Коммит
85a91db376
|
@ -40,7 +40,6 @@ SOURCES += [
|
|||
"/third_party/jpeg-xl/lib/jxl/decode.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",
|
||||
"/third_party/jpeg-xl/lib/jxl/fields.cc",
|
||||
"/third_party/jpeg-xl/lib/jxl/frame_header.cc",
|
||||
"/third_party/jpeg-xl/lib/jxl/headers.cc",
|
||||
|
|
|
@ -10,9 +10,9 @@ origin:
|
|||
|
||||
url: https://github.com/libjxl/libjxl
|
||||
|
||||
release: ab47708dcf002fae0164555b370aa36487df0f5d (2024-02-19T19:38:30Z).
|
||||
release: f06a34c77b1bd11bafbe82989241e68c756ccca2 (2024-03-11T15:14:53Z).
|
||||
|
||||
revision: ab47708dcf002fae0164555b370aa36487df0f5d
|
||||
revision: f06a34c77b1bd11bafbe82989241e68c756ccca2
|
||||
|
||||
license: Apache-2.0
|
||||
|
||||
|
|
|
@ -25,16 +25,31 @@ Checks: >-
|
|||
modernize-*,
|
||||
performance-*,
|
||||
readability-*,
|
||||
-bugprone-narrowing-conversions,
|
||||
-bugprone-branch-clone,
|
||||
-bugprone-easily-swappable-parameters,
|
||||
-bugprone-implicit-widening-of-multiplication-result,
|
||||
-bugprone-infinite-loop,
|
||||
-bugprone-unused-local-non-trivial-variable,
|
||||
-modernize-avoid-c-arrays,
|
||||
-modernize-deprecated-headers,
|
||||
-modernize-return-braced-init-list,
|
||||
-modernize-use-auto,
|
||||
-modernize-use-default-member-init,
|
||||
-modernize-use-trailing-return-type,
|
||||
-modernize-use-using,
|
||||
-performance-enum-size,
|
||||
-readability-avoid-nested-conditional-operator,
|
||||
-readability-else-after-return,
|
||||
-readability-function-cognitive-complexity,
|
||||
-readability-identifier-length,
|
||||
-readability-magic-numbers,
|
||||
-readability-redundant-access-specifiers,
|
||||
-readability-simplify-boolean-expr,
|
||||
-readability-static-accessed-through-instance,
|
||||
-readability-suspicious-call-argument,
|
||||
-readability-uppercase-literal-suffix,
|
||||
-readability-use-anyofallof,
|
||||
|
||||
|
||||
WarningsAsErrors: >-
|
||||
|
@ -57,11 +72,13 @@ WarningsAsErrors: >-
|
|||
HeaderFilterRegex: '^.*/(lib|tools)/.*\.h$'
|
||||
|
||||
CheckOptions:
|
||||
- key: readability-braces-around-statements.ShortStatementLines
|
||||
value: '2'
|
||||
- key: google-readability-braces-around-statements.ShortStatementLines
|
||||
value: '2'
|
||||
- key: readability-implicit-bool-conversion.AllowPointerConditions
|
||||
value: '1'
|
||||
- key: readability-implicit-bool-conversion.AllowIntegerConditions
|
||||
value: '1'
|
||||
- key: readability-braces-around-statements.ShortStatementLines
|
||||
value: '2'
|
||||
- key: google-readability-braces-around-statements.ShortStatementLines
|
||||
value: '2'
|
||||
- key: readability-implicit-bool-conversion.AllowPointerConditions
|
||||
value: '1'
|
||||
- key: readability-implicit-bool-conversion.AllowIntegerConditions
|
||||
value: '1'
|
||||
- key: bugprone-signed-char-misuse.CharTypdefsToIgnore
|
||||
value: 'int8_t'
|
||||
|
|
|
@ -8,12 +8,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
## Unreleased
|
||||
|
||||
### Added
|
||||
- decoder API: added `JxlDecoderGetBoxSizeContents` for getting the size of the
|
||||
content of a box without the headers.
|
||||
|
||||
### Removed
|
||||
|
||||
### Changed / clarified
|
||||
|
||||
### Fixed
|
||||
|
||||
|
||||
## [0.10.0] - 2024-02-21
|
||||
|
||||
### Added
|
||||
- decoder API: added `JxlDecoderGetBoxSizeContents` for getting the size of the
|
||||
content of a box without the headers.
|
||||
- encoder API: implemented new api functions for streaming encoding.
|
||||
|
||||
### Changed / clarified
|
||||
- decoder/encoder API: return failure when surface allocation fail
|
||||
- encoder API / cjxl: updated modular effort levels to faster settings; the
|
||||
effort range is now 1-10, with 11 available in advanced mode.
|
||||
|
||||
## [0.9.2] - 2024-02-07
|
||||
|
||||
### Fixed
|
||||
|
|
|
@ -167,7 +167,7 @@ set(JPEGXL_ENABLE_WASM_TRHEADS true CACHE BOOL
|
|||
set(JPEGXL_FORCE_SYSTEM_BROTLI false CACHE BOOL
|
||||
"Force using system installed brotli instead of third_party/brotli source.")
|
||||
set(JPEGXL_FORCE_SYSTEM_GTEST false CACHE BOOL
|
||||
"Force using system installed googletest (gtest/gmock) instead of third_party/googletest source.")
|
||||
"Force using system installed googletest (gtest) instead of third_party/googletest source.")
|
||||
set(JPEGXL_FORCE_SYSTEM_LCMS2 false CACHE BOOL
|
||||
"Force using system installed lcms2 instead of third_party/lcms source.")
|
||||
set(JPEGXL_FORCE_SYSTEM_HWY false CACHE BOOL
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
bazel_dep(name = "bazel_skylib", version = "1.5.0")
|
||||
bazel_dep(name = "giflib", version = "5.2.1")
|
||||
bazel_dep(name = "googletest", version = "1.14.0")
|
||||
bazel_dep(name = "openexr", version = "3.2.1")
|
||||
bazel_dep(name = "libjpeg_turbo", version = "2.1.91")
|
||||
bazel_dep(name = "libpng", version = "1.6.40")
|
||||
bazel_dep(name = "libwebp", version = "1.3.2")
|
||||
bazel_dep(name = "openexr", version = "3.2.1")
|
||||
|
|
|
@ -73,11 +73,14 @@ To decode a JPEG XL file run:
|
|||
djxl input.jxl output.png
|
||||
```
|
||||
|
||||
When possible `cjxl`/`djxl` are able to read/write the following
|
||||
image formats: .exr, .gif, .jpeg/.jpg, .pfm, .pgm/.ppm, .pgx, .png.
|
||||
When possible, `cjxl`/`djxl` are able to read/write the following image formats:
|
||||
OpenEXR (`.exr`), GIF (`.gif`), JPEG (`.jpg`/`.jpeg`), NetPBM (`.pam`/`.pgm`/`.ppm`),
|
||||
Portable FloatMap (`.pfm`), PGX Test Format (`.pgx`), Portable Network Graphics (`.png`),
|
||||
Animated PNG (`.png`/`.apng`), and JPEG XL itself (`.jxl`).
|
||||
|
||||
Specifically for JPEG files, the default `cjxl` behavior is to apply lossless
|
||||
recompression and the default `djxl` behavior is to reconstruct the original
|
||||
JPEG file (when the extension of the output file is .jpg).
|
||||
JPEG file (when the extension of the output file is `.jpg`).
|
||||
|
||||
### Benchmarking
|
||||
|
||||
|
|
|
@ -30,185 +30,3 @@ cc_library(
|
|||
""",
|
||||
path = "third_party/skcms",
|
||||
)
|
||||
|
||||
new_git_repository(
|
||||
name = "libjpeg_turbo",
|
||||
build_file_content = """
|
||||
load("@bazel_skylib//rules:expand_template.bzl", "expand_template")
|
||||
SUBSTITUTIONS = {
|
||||
"@BUILD@" : "20230208",
|
||||
"@CMAKE_PROJECT_NAME@" : "libjpeg-turbo",
|
||||
"@COPYRIGHT_YEAR@" : "2023",
|
||||
"@INLINE@" : "__inline__",
|
||||
"@JPEG_LIB_VERSION@" : "62",
|
||||
"@LIBJPEG_TURBO_VERSION_NUMBER@" : "2001091",
|
||||
"@SIZE_T@" : "8",
|
||||
"@THREAD_LOCAL@" : "__thread",
|
||||
"@VERSION@" : "2.1.91",
|
||||
}
|
||||
YES_DEFINES = [
|
||||
"C_ARITH_CODING_SUPPORTED", "D_ARITH_CODING_SUPPORTED",
|
||||
"HAVE_BUILTIN_CTZL", "MEM_SRCDST_SUPPORTED"
|
||||
]
|
||||
NO_DEFINES = [
|
||||
"WITH_SIMD", "RIGHT_SHIFT_IS_UNSIGNED", "HAVE_INTRIN_H"
|
||||
]
|
||||
SUBSTITUTIONS.update({
|
||||
"#cmakedefine " + key : "#define " + key for key in YES_DEFINES
|
||||
})
|
||||
SUBSTITUTIONS.update({
|
||||
"#cmakedefine " + key : "// #define " + key for key in NO_DEFINES
|
||||
})
|
||||
[
|
||||
expand_template(
|
||||
name = "expand_" + src,
|
||||
template = src + ".in",
|
||||
out = src,
|
||||
substitutions = SUBSTITUTIONS,
|
||||
visibility = ["//visibility:public"],
|
||||
) for src in ["jconfig.h", "jconfigint.h", "jversion.h"]
|
||||
]
|
||||
JPEG16_SOURCES = [
|
||||
"jccolor.c",
|
||||
"jcdiffct.c",
|
||||
"jclossls.c",
|
||||
"jcmainct.c",
|
||||
"jcprepct.c",
|
||||
"jcsample.c",
|
||||
"jdcolor.c",
|
||||
"jddiffct.c",
|
||||
"jdlossls.c",
|
||||
"jdmainct.c",
|
||||
"jdmerge.c",
|
||||
"jdpostct.c",
|
||||
"jdsample.c",
|
||||
"jquant1.c",
|
||||
"jquant2.c",
|
||||
"jutils.c",
|
||||
]
|
||||
JPEG12_SOURCES = JPEG16_SOURCES + [
|
||||
"jccoefct.c",
|
||||
"jcdctmgr.c",
|
||||
"jdcoefct.c",
|
||||
"jddctmgr.c",
|
||||
"jfdctfst.c",
|
||||
"jfdctint.c",
|
||||
"jidctflt.c",
|
||||
"jidctfst.c",
|
||||
"jidctint.c",
|
||||
"jidctred.c",
|
||||
]
|
||||
JPEG_SOURCES = JPEG12_SOURCES + [
|
||||
"jaricom.c",
|
||||
"jcapimin.c",
|
||||
"jcapistd.c",
|
||||
"jcarith.c",
|
||||
"jchuff.c",
|
||||
"jcicc.c",
|
||||
"jcinit.c",
|
||||
"jclhuff.c",
|
||||
"jcmarker.c",
|
||||
"jcmaster.c",
|
||||
"jcomapi.c",
|
||||
"jcparam.c",
|
||||
"jcphuff.c",
|
||||
"jdapimin.c",
|
||||
"jdapistd.c",
|
||||
"jdarith.c",
|
||||
"jdatadst.c",
|
||||
"jdatasrc.c",
|
||||
"jdhuff.c",
|
||||
"jdicc.c",
|
||||
"jdinput.c",
|
||||
"jdlhuff.c",
|
||||
"jdmarker.c",
|
||||
"jdmaster.c",
|
||||
"jdphuff.c",
|
||||
"jdtrans.c",
|
||||
"jerror.c",
|
||||
"jfdctflt.c",
|
||||
"jmemmgr.c",
|
||||
"jmemnobs.c",
|
||||
]
|
||||
JPEG_HEADERS = [
|
||||
"jccolext.c",
|
||||
"jchuff.h",
|
||||
"jcmaster.h",
|
||||
"jconfig.h",
|
||||
"jconfigint.h",
|
||||
"jdcoefct.h",
|
||||
"jdcol565.c",
|
||||
"jdcolext.c",
|
||||
"jdct.h",
|
||||
"jdhuff.h",
|
||||
"jdmainct.h",
|
||||
"jdmaster.h",
|
||||
"jdmerge.h",
|
||||
"jdmrg565.c",
|
||||
"jdmrgext.c",
|
||||
"jdsample.h",
|
||||
"jerror.h",
|
||||
"jinclude.h",
|
||||
"jlossls.h",
|
||||
"jmemsys.h",
|
||||
"jmorecfg.h",
|
||||
"jpeg_nbits_table.h",
|
||||
"jpegapicomp.h",
|
||||
"jpegint.h",
|
||||
"jpeglib.h",
|
||||
"jsamplecomp.h",
|
||||
"jsimd.h",
|
||||
"jsimddct.h",
|
||||
"jstdhuff.c",
|
||||
"jversion.h",
|
||||
]
|
||||
cc_library(
|
||||
name = "jpeg16",
|
||||
srcs = JPEG16_SOURCES,
|
||||
hdrs = JPEG_HEADERS,
|
||||
local_defines = ["BITS_IN_JSAMPLE=16"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
cc_library(
|
||||
name = "jpeg12",
|
||||
srcs = JPEG12_SOURCES,
|
||||
hdrs = JPEG_HEADERS,
|
||||
local_defines = ["BITS_IN_JSAMPLE=12"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
cc_library(
|
||||
name = "jpeg",
|
||||
srcs = JPEG_SOURCES,
|
||||
hdrs = JPEG_HEADERS,
|
||||
deps = [":jpeg16", ":jpeg12"],
|
||||
includes = ["."],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
exports_files([
|
||||
"jmorecfg.h",
|
||||
"jpeglib.h",
|
||||
])
|
||||
""",
|
||||
remote = "https://github.com/libjpeg-turbo/libjpeg-turbo.git",
|
||||
tag = "2.1.91",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "gif",
|
||||
build_file_content = """
|
||||
cc_library(
|
||||
name = "gif",
|
||||
srcs = [
|
||||
"dgif_lib.c", "egif_lib.c", "gifalloc.c", "gif_err.c", "gif_font.c",
|
||||
"gif_hash.c", "openbsd-reallocarray.c", "gif_hash.h",
|
||||
"gif_lib_private.h"
|
||||
],
|
||||
hdrs = ["gif_lib.h"],
|
||||
includes = ["."],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "31da5562f44c5f15d63340a09a4fd62b48c45620cd302f77a6d9acf0077879bd",
|
||||
strip_prefix = "giflib-5.2.1",
|
||||
url = "https://netcologne.dl.sourceforge.net/project/giflib/giflib-5.2.1.tar.gz",
|
||||
)
|
||||
|
|
|
@ -106,12 +106,6 @@ test_printf_size_t() {
|
|||
ret=1
|
||||
fi
|
||||
|
||||
if grep -n -E 'gmock\.h' \
|
||||
$(git ls-files | grep -E '(\.c|\.cc|\.cpp|\.h)$' | grep -v -F /testing.h); then
|
||||
echo "Don't include gmock directly, instead include 'testing.h'. " >&2
|
||||
ret=1
|
||||
fi
|
||||
|
||||
local f
|
||||
for f in $(git ls-files | grep -E "\.cc$" | xargs grep 'PRI[udx]S' |
|
||||
cut -f 1 -d : | uniq); do
|
||||
|
|
|
@ -16,6 +16,8 @@ MYDIR=$(dirname $(realpath "$0"))
|
|||
|
||||
### Environment parameters:
|
||||
TEST_STACK_LIMIT="${TEST_STACK_LIMIT:-256}"
|
||||
BENCHMARK_NUM_THREADS="${BENCHMARK_NUM_THREADS:-0}"
|
||||
BUILD_CONFIG=${BUILD_CONFIG:-}
|
||||
CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE:-RelWithDebInfo}
|
||||
CMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH:-}
|
||||
CMAKE_C_COMPILER_LAUNCHER=${CMAKE_C_COMPILER_LAUNCHER:-}
|
||||
|
@ -79,6 +81,12 @@ if [[ "${ENABLE_WASM_SIMD}" -eq "2" ]]; then
|
|||
CMAKE_C_FLAGS="${CMAKE_C_FLAGS} -DHWY_WANT_WASM2"
|
||||
fi
|
||||
|
||||
if [[ -z "${BUILD_CONFIG}" ]]; then
|
||||
TOOLS_DIR="${BUILD_DIR}/tools"
|
||||
else
|
||||
TOOLS_DIR="${BUILD_DIR}/tools/${BUILD_CONFIG}"
|
||||
fi
|
||||
|
||||
if [[ ! -z "${HWY_BASELINE_TARGETS}" ]]; then
|
||||
CMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS} -DHWY_BASELINE_TARGETS=${HWY_BASELINE_TARGETS}"
|
||||
fi
|
||||
|
@ -128,17 +136,17 @@ if [[ "${BUILD_TARGET%%-*}" != "arm" ]]; then
|
|||
)
|
||||
fi
|
||||
|
||||
CLANG_TIDY_BIN=$(which clang-tidy-6.0 clang-tidy-7 clang-tidy-8 clang-tidy | head -n 1)
|
||||
CLANG_TIDY_BIN=$(which clang-tidy-6.0 clang-tidy-7 clang-tidy-8 clang-tidy 2>/dev/null | head -n 1)
|
||||
# Default to "cat" if "colordiff" is not installed or if stdout is not a tty.
|
||||
if [[ -t 1 ]]; then
|
||||
COLORDIFF_BIN=$(which colordiff cat | head -n 1)
|
||||
COLORDIFF_BIN=$(which colordiff cat 2>/dev/null | head -n 1)
|
||||
else
|
||||
COLORDIFF_BIN="cat"
|
||||
fi
|
||||
FIND_BIN=$(which gfind find | head -n 1)
|
||||
FIND_BIN=$(which gfind find 2>/dev/null | head -n 1)
|
||||
# "false" will disable wine64 when not installed. This won't allow
|
||||
# cross-compiling.
|
||||
WINE_BIN=$(which wine64 false | head -n 1)
|
||||
WINE_BIN=$(which wine64 false 2>/dev/null | head -n 1)
|
||||
|
||||
CLANG_VERSION="${CLANG_VERSION:-}"
|
||||
# Detect the clang version suffix and store it in CLANG_VERSION. For example,
|
||||
|
@ -411,7 +419,7 @@ cmake_build_and_test() {
|
|||
if [[ "${PACK_TEST:-}" == "1" ]]; then
|
||||
(cd "${BUILD_DIR}"
|
||||
${FIND_BIN} -name '*.cmake' -a '!' -path '*CMakeFiles*'
|
||||
# gtest / gmock / gtest_main shared libs
|
||||
# gtest / gtest_main shared libs
|
||||
${FIND_BIN} lib/ -name 'libg*.so*'
|
||||
${FIND_BIN} -type d -name tests -a '!' -path '*CMakeFiles*'
|
||||
) | tar -C "${BUILD_DIR}" -cf "${BUILD_DIR}/tests.tar.xz" -T - \
|
||||
|
@ -791,9 +799,13 @@ cmd_ossfuzz_ninja() {
|
|||
|
||||
cmd_fast_benchmark() {
|
||||
local small_corpus_tar="${BENCHMARK_CORPORA}/jyrki-full.tar"
|
||||
local small_corpus_url="https://storage.googleapis.com/artifacts.jpegxl.appspot.com/corpora/jyrki-full.tar"
|
||||
mkdir -p "${BENCHMARK_CORPORA}"
|
||||
curl --show-error -o "${small_corpus_tar}" -z "${small_corpus_tar}" \
|
||||
"https://storage.googleapis.com/artifacts.jpegxl.appspot.com/corpora/jyrki-full.tar"
|
||||
if [ -f "${small_corpus_tar}" ]; then
|
||||
curl --show-error -o "${small_corpus_tar}" -z "${small_corpus_tar}" "${small_corpus_url}"
|
||||
else
|
||||
curl --show-error -o "${small_corpus_tar}" "${small_corpus_url}"
|
||||
fi
|
||||
|
||||
local tmpdir=$(mktemp -d)
|
||||
CLEANUP_FILES+=("${tmpdir}")
|
||||
|
@ -831,7 +843,7 @@ cmd_benchmark() {
|
|||
png_filename="${filename%.ppm}.png"
|
||||
png_filename=$(echo "${png_filename}" | tr '/' '_')
|
||||
sem --bg --id "${sem_id}" -j"${nprocs}" -- \
|
||||
"${BUILD_DIR}/tools/decode_and_encode" \
|
||||
"${TOOLS_DIR}/decode_and_encode" \
|
||||
"${tmpdir}/${filename}" "${mode}" "${tmpdir}/${png_filename}"
|
||||
images+=( "${png_filename}" )
|
||||
done < <(cd "${tmpdir}"; ${FIND_BIN} . -name '*.ppm' -type f)
|
||||
|
@ -844,6 +856,8 @@ cmd_benchmark() {
|
|||
get_mem_available() {
|
||||
if [[ "${OS}" == "Darwin" ]]; then
|
||||
echo $(vm_stat | grep -F 'Pages free:' | awk '{print $3 * 4}')
|
||||
elif [[ "${OS}" == MINGW* ]]; then
|
||||
echo $(vmstat | tail -n 1 | awk '{print $4 * 4}')
|
||||
else
|
||||
echo $(grep -F MemAvailable: /proc/meminfo | awk '{print $2}')
|
||||
fi
|
||||
|
@ -856,15 +870,24 @@ run_benchmark() {
|
|||
local output_dir="${BUILD_DIR}/benchmark_results"
|
||||
mkdir -p "${output_dir}"
|
||||
|
||||
# The memory available at the beginning of the benchmark run in kB. The number
|
||||
# of threads depends on the available memory, and the passed memory per
|
||||
# thread. We also add a 2 GiB of constant memory.
|
||||
local mem_available="$(get_mem_available)"
|
||||
# Check that we actually have a MemAvailable value.
|
||||
[[ -n "${mem_available}" ]]
|
||||
local num_threads=$(( (${mem_available} - 1048576) / ${mem_per_thread} ))
|
||||
if [[ ${num_threads} -le 0 ]]; then
|
||||
num_threads=1
|
||||
if [[ "${OS}" == MINGW* ]]; then
|
||||
src_img_dir=`cygpath -w "${src_img_dir}"`
|
||||
fi
|
||||
|
||||
local num_threads=1
|
||||
if [[ ${BENCHMARK_NUM_THREADS} -gt 0 ]]; then
|
||||
num_threads=${BENCHMARK_NUM_THREADS}
|
||||
else
|
||||
# The memory available at the beginning of the benchmark run in kB. The number
|
||||
# of threads depends on the available memory, and the passed memory per
|
||||
# thread. We also add a 2 GiB of constant memory.
|
||||
local mem_available="$(get_mem_available)"
|
||||
# Check that we actually have a MemAvailable value.
|
||||
[[ -n "${mem_available}" ]]
|
||||
num_threads=$(( (${mem_available} - 1048576) / ${mem_per_thread} ))
|
||||
if [[ ${num_threads} -le 0 ]]; then
|
||||
num_threads=1
|
||||
fi
|
||||
fi
|
||||
|
||||
local benchmark_args=(
|
||||
|
@ -873,20 +896,20 @@ run_benchmark() {
|
|||
--output_dir "${output_dir}"
|
||||
--show_progress
|
||||
--num_threads="${num_threads}"
|
||||
--decode_reps=11
|
||||
--encode_reps=11
|
||||
)
|
||||
if [[ "${STORE_IMAGES}" == "1" ]]; then
|
||||
benchmark_args+=(--save_decompressed --save_compressed)
|
||||
fi
|
||||
(
|
||||
[[ "${TEST_STACK_LIMIT}" == "none" ]] || ulimit -s "${TEST_STACK_LIMIT}"
|
||||
"${BUILD_DIR}/tools/benchmark_xl" "${benchmark_args[@]}" | \
|
||||
"${TOOLS_DIR}/benchmark_xl" "${benchmark_args[@]}" | \
|
||||
tee "${output_dir}/results.txt"
|
||||
|
||||
# Check error code for benckmark_xl command. This will exit if not.
|
||||
return ${PIPESTATUS[0]}
|
||||
)
|
||||
|
||||
|
||||
}
|
||||
|
||||
# Helper function to wait for the CPU temperature to cool down on ARM.
|
||||
|
@ -1027,7 +1050,7 @@ cmd_arm_benchmark() {
|
|||
local src_img
|
||||
for src_img in "${jpg_images[@]}" "${images[@]}"; do
|
||||
local src_img_hash=$(sha1sum "${src_img}" | cut -f 1 -d ' ')
|
||||
local enc_binaries=("${BUILD_DIR}/tools/cjxl")
|
||||
local enc_binaries=("${TOOLS_DIR}/cjxl")
|
||||
local src_ext="${src_img##*.}"
|
||||
for enc_binary in "${enc_binaries[@]}"; do
|
||||
local enc_binary_base=$(basename "${enc_binary}")
|
||||
|
@ -1076,7 +1099,7 @@ cmd_arm_benchmark() {
|
|||
|
||||
local dec_output
|
||||
wait_for_temp
|
||||
dec_output=$("${BUILD_DIR}/tools/djxl" "${enc_file}" \
|
||||
dec_output=$("${TOOLS_DIR}/djxl" "${enc_file}" \
|
||||
--num_reps=5 --num_threads="${num_threads}" 2>&1 | tee /dev/stderr |
|
||||
grep -E "M[BP]/s \[")
|
||||
local img_size=$(echo "${dec_output}" | cut -f 1 -d ',')
|
||||
|
@ -1092,7 +1115,7 @@ cmd_arm_benchmark() {
|
|||
if [[ "${src_ext}" == "jpg" ]]; then
|
||||
wait_for_temp
|
||||
local dec_file="${BUILD_DIR}/arm_benchmark/${enc_file_hash}.jpg"
|
||||
dec_output=$("${BUILD_DIR}/tools/djxl" "${enc_file}" \
|
||||
dec_output=$("${TOOLS_DIR}/djxl" "${enc_file}" \
|
||||
"${dec_file}" --num_reps=5 --num_threads="${num_threads}" 2>&1 | \
|
||||
tee /dev/stderr | grep -E "M[BP]/s \[")
|
||||
local jpeg_dec_mps_speed=$(_speed_from_output "${dec_output}")
|
||||
|
@ -1122,12 +1145,12 @@ cmd_fuzz() {
|
|||
local fuzzer_crash_dir=$(realpath "${BUILD_DIR}/fuzzer_crash")
|
||||
mkdir -p "${corpus_dir}" "${fuzzer_crash_dir}"
|
||||
# Generate step.
|
||||
"${BUILD_DIR}/tools/fuzzer_corpus" "${corpus_dir}"
|
||||
"${TOOLS_DIR}/fuzzer_corpus" "${corpus_dir}"
|
||||
# Run step:
|
||||
local nprocs=$(nproc --all || echo 1)
|
||||
(
|
||||
cd "${BUILD_DIR}"
|
||||
"tools/djxl_fuzzer" "${fuzzer_crash_dir}" "${corpus_dir}" \
|
||||
cd "${TOOLS_DIR}"
|
||||
djxl_fuzzer "${fuzzer_crash_dir}" "${corpus_dir}" \
|
||||
-max_total_time="${FUZZER_MAX_TIME}" -jobs=${nprocs} \
|
||||
-artifact_prefix="${fuzzer_crash_dir}/"
|
||||
)
|
||||
|
|
|
@ -11,7 +11,6 @@ Build-Depends:
|
|||
libgdk-pixbuf-2.0-dev | libgdk-pixbuf2.0-dev,
|
||||
libgif-dev,
|
||||
libgimp2.0-dev,
|
||||
libgmock-dev,
|
||||
libgoogle-perftools-dev,
|
||||
libgtest-dev,
|
||||
libhwy-dev (>= 1.0.0),
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
usr/lib/*/gdk-pixbuf-*/*/loaders/*
|
||||
usr/share/mime/packages/image-jxl.xml
|
||||
usr/share/thumbnailers/jxl.thumbnailer
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <jxl/decode_cxx.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <vector>
|
||||
|
@ -55,8 +56,9 @@ bool DecodeJpegXlExif(const uint8_t* jxl, size_t size,
|
|||
return true;
|
||||
}
|
||||
JxlBoxType type;
|
||||
if (JXL_DEC_SUCCESS !=
|
||||
JxlDecoderGetBoxType(dec.get(), type, support_decompression)) {
|
||||
status = JxlDecoderGetBoxType(dec.get(), type,
|
||||
TO_JXL_BOOL(support_decompression));
|
||||
if (JXL_DEC_SUCCESS != status) {
|
||||
fprintf(stderr, "Error, failed to get box type\n");
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -7,11 +7,6 @@
|
|||
// available at once). The example outputs the pixels and color information to a
|
||||
// floating point image and an ICC profile on disk.
|
||||
|
||||
#ifndef __STDC_FORMAT_MACROS
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <jxl/codestream_header.h>
|
||||
#include <jxl/decode.h>
|
||||
#include <jxl/decode_cxx.h>
|
||||
|
@ -102,13 +97,13 @@ bool DecodeJpegXlOneShot(const uint8_t* jxl, size_t size,
|
|||
return false;
|
||||
}
|
||||
if (buffer_size != *xsize * *ysize * 16) {
|
||||
fprintf(stderr, "Invalid out buffer size %" PRIu64 " %" PRIu64 "\n",
|
||||
static_cast<uint64_t>(buffer_size),
|
||||
static_cast<uint64_t>(*xsize * *ysize * 16));
|
||||
fprintf(stderr, "Invalid out buffer size %d %d\n",
|
||||
static_cast<int>(buffer_size),
|
||||
static_cast<int>(*xsize * *ysize * 16));
|
||||
return false;
|
||||
}
|
||||
pixels->resize(*xsize * *ysize * 4);
|
||||
void* pixels_buffer = (void*)pixels->data();
|
||||
void* pixels_buffer = static_cast<void*>(pixels->data());
|
||||
size_t pixels_buffer_size = pixels->size() * sizeof(float);
|
||||
if (JXL_DEC_SUCCESS != JxlDecoderSetImageOutBuffer(dec.get(), &format,
|
||||
pixels_buffer,
|
||||
|
@ -147,8 +142,8 @@ bool WritePFM(const char* filename, const float* pixels, size_t xsize,
|
|||
uint8_t little_endian[4];
|
||||
memcpy(little_endian, &endian_test, 4);
|
||||
|
||||
fprintf(file, "PF\n%d %d\n%s\n", (int)xsize, (int)ysize,
|
||||
little_endian[0] ? "-1.0" : "1.0");
|
||||
fprintf(file, "PF\n%d %d\n%s\n", static_cast<int>(xsize),
|
||||
static_cast<int>(ysize), little_endian[0] ? "-1.0" : "1.0");
|
||||
for (int y = ysize - 1; y >= 0; y--) {
|
||||
for (size_t x = 0; x < xsize; x++) {
|
||||
for (size_t c = 0; c < 3; c++) {
|
||||
|
@ -233,7 +228,8 @@ int main(int argc, char* argv[]) {
|
|||
|
||||
std::vector<float> pixels;
|
||||
std::vector<uint8_t> icc_profile;
|
||||
size_t xsize = 0, ysize = 0;
|
||||
size_t xsize = 0;
|
||||
size_t ysize = 0;
|
||||
if (!DecodeJpegXlOneShot(jxl.data(), jxl.size(), &pixels, &xsize, &ysize,
|
||||
&icc_profile)) {
|
||||
fprintf(stderr, "Error while decoding the jxl file\n");
|
||||
|
|
|
@ -6,10 +6,6 @@
|
|||
// This C++ example decodes a JPEG XL image progressively (input bytes are
|
||||
// passed in chunks). The example outputs the intermediate steps to PAM files.
|
||||
|
||||
#ifndef __STDC_FORMAT_MACROS
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <jxl/decode.h>
|
||||
#include <jxl/decode_cxx.h>
|
||||
|
@ -29,10 +25,9 @@ bool WritePAM(const char* filename, const uint8_t* buffer, size_t w, size_t h) {
|
|||
return false;
|
||||
}
|
||||
fprintf(fp,
|
||||
"P7\nWIDTH %" PRIu64 "\nHEIGHT %" PRIu64
|
||||
"\nDEPTH 4\nMAXVAL 255\nTUPLTYPE "
|
||||
"P7\nWIDTH %d\nHEIGHT %d\nDEPTH 4\nMAXVAL 255\nTUPLTYPE "
|
||||
"RGB_ALPHA\nENDHDR\n",
|
||||
static_cast<uint64_t>(w), static_cast<uint64_t>(h));
|
||||
static_cast<int>(w), static_cast<int>(h));
|
||||
size_t num_bytes = w * h * 4;
|
||||
if (fwrite(buffer, 1, num_bytes, fp) != num_bytes) {
|
||||
fclose(fp);
|
||||
|
@ -51,7 +46,8 @@ bool DecodeJpegXlProgressive(const uint8_t* jxl, size_t size,
|
|||
const char* filename, size_t chunksize) {
|
||||
std::vector<uint8_t> pixels;
|
||||
std::vector<uint8_t> icc_profile;
|
||||
size_t xsize = 0, ysize = 0;
|
||||
size_t xsize = 0;
|
||||
size_t ysize = 0;
|
||||
|
||||
// Multi-threaded parallel runner.
|
||||
auto runner = JxlResizableParallelRunnerMake(nullptr);
|
||||
|
|
|
@ -39,8 +39,9 @@ bool ReadPFM(const char* filename, std::vector<float>* pixels, uint32_t* xsize,
|
|||
return false;
|
||||
}
|
||||
uint32_t endian_test = 1;
|
||||
uint8_t little_endian[4];
|
||||
memcpy(little_endian, &endian_test, 4);
|
||||
uint8_t little_endian_check[4];
|
||||
memcpy(little_endian_check, &endian_test, 4);
|
||||
bool little_endian = (little_endian_check[0] == 1);
|
||||
|
||||
if (fseek(file, 0, SEEK_END) != 0) {
|
||||
fclose(file);
|
||||
|
@ -63,7 +64,7 @@ bool ReadPFM(const char* filename, std::vector<float>* pixels, uint32_t* xsize,
|
|||
data.resize(size);
|
||||
|
||||
size_t readsize = fread(data.data(), 1, size, file);
|
||||
if ((long)readsize != size) {
|
||||
if (static_cast<long>(readsize) != size) {
|
||||
fclose(file);
|
||||
return false;
|
||||
}
|
||||
|
@ -116,12 +117,13 @@ bool ReadPFM(const char* filename, std::vector<float>* pixels, uint32_t* xsize,
|
|||
fprintf(stderr,
|
||||
"%s doesn't seem to be a Portable FloatMap file (pixel data bytes "
|
||||
"are %d, but expected %d * %d * 3 * 4 + %d (%d).\n",
|
||||
filename, (int)data.size(), (int)*ysize, (int)*xsize, (int)offset,
|
||||
(int)(*ysize * *xsize * 3 * 4 + offset));
|
||||
filename, static_cast<int>(data.size()), static_cast<int>(*ysize),
|
||||
static_cast<int>(*xsize), static_cast<int>(offset),
|
||||
static_cast<int>(*ysize * *xsize * 3 * 4 + offset));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!!little_endian[0] != input_little_endian) {
|
||||
if (little_endian != input_little_endian) {
|
||||
fprintf(stderr,
|
||||
"%s has a different endianness than we do, conversion is not "
|
||||
"supported.\n",
|
||||
|
@ -132,7 +134,7 @@ bool ReadPFM(const char* filename, std::vector<float>* pixels, uint32_t* xsize,
|
|||
pixels->resize(*ysize * *xsize * 3);
|
||||
|
||||
for (int y = *ysize - 1; y >= 0; y--) {
|
||||
for (int x = 0; x < (int)*xsize; x++) {
|
||||
for (int x = 0; x < static_cast<int>(*xsize); x++) {
|
||||
for (int c = 0; c < 3; c++) {
|
||||
memcpy(pixels->data() + (y * *xsize + x) * 3 + c, data.data() + offset,
|
||||
sizeof(float));
|
||||
|
@ -180,8 +182,8 @@ bool EncodeJxlOneshot(const std::vector<float>& pixels, const uint32_t xsize,
|
|||
}
|
||||
|
||||
JxlColorEncoding color_encoding = {};
|
||||
JxlColorEncodingSetToSRGB(&color_encoding,
|
||||
/*is_gray=*/pixel_format.num_channels < 3);
|
||||
JXL_BOOL is_gray = TO_JXL_BOOL(pixel_format.num_channels < 3);
|
||||
JxlColorEncodingSetToSRGB(&color_encoding, is_gray);
|
||||
if (JXL_ENC_SUCCESS !=
|
||||
JxlEncoderSetColorEncoding(enc.get(), &color_encoding)) {
|
||||
fprintf(stderr, "JxlEncoderSetColorEncoding failed\n");
|
||||
|
@ -193,7 +195,7 @@ bool EncodeJxlOneshot(const std::vector<float>& pixels, const uint32_t xsize,
|
|||
|
||||
if (JXL_ENC_SUCCESS !=
|
||||
JxlEncoderAddImageFrame(frame_settings, &pixel_format,
|
||||
(void*)pixels.data(),
|
||||
static_cast<const void*>(pixels.data()),
|
||||
sizeof(float) * pixels.size())) {
|
||||
fprintf(stderr, "JxlEncoderAddImageFrame failed\n");
|
||||
return false;
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
cmake
|
||||
pkg-config
|
||||
gtest
|
||||
gmock
|
||||
doxygen
|
||||
graphviz
|
||||
python3
|
||||
|
|
|
@ -23,8 +23,8 @@ load(
|
|||
"libjxl_enc_sources",
|
||||
"libjxl_extras_for_tools_sources",
|
||||
"libjxl_extras_sources",
|
||||
#'libjxl_gbench_sources',
|
||||
"libjxl_jpegli_lib_version",
|
||||
# "libjxl_gbench_sources",
|
||||
# "libjxl_jpegli_lib_version",
|
||||
"libjxl_jpegli_libjpeg_helper_files",
|
||||
"libjxl_jpegli_sources",
|
||||
"libjxl_jpegli_testlib_files",
|
||||
|
@ -51,13 +51,14 @@ load(
|
|||
"libjxl_deps_png",
|
||||
"libjxl_deps_runfiles",
|
||||
"libjxl_deps_skcms",
|
||||
"libjxl_deps_testdata",
|
||||
# "libjxl_deps_testdata",
|
||||
# "libjxl_deps_webp",
|
||||
"libjxl_root_package",
|
||||
"libjxl_test_shards",
|
||||
"libjxl_test_timeouts",
|
||||
)
|
||||
load("@bazel_skylib//rules:expand_template.bzl", "expand_template")
|
||||
load("@bazel_skylib//rules:copy_file.bzl", "copy_file")
|
||||
load("@bazel_skylib//rules:expand_template.bzl", "expand_template")
|
||||
|
||||
DEFAULT_VISIBILITY = ["//:__subpackages__"]
|
||||
|
||||
|
@ -66,7 +67,7 @@ DEFAULT_COMPATIBILITY = []
|
|||
INCLUDES_DIR = "include"
|
||||
|
||||
package(
|
||||
default_visibility = ["//:__subpackages__"],
|
||||
default_visibility = DEFAULT_VISIBILITY,
|
||||
)
|
||||
|
||||
licenses(["notice"])
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace extras {
|
|||
|
||||
namespace {
|
||||
|
||||
void AlphaBlend(PackedFrame* frame, float background[3]) {
|
||||
void AlphaBlend(PackedFrame* frame, const float background[3]) {
|
||||
if (!frame) return;
|
||||
const PackedImage& im = frame->color;
|
||||
JxlPixelFormat format = im.format;
|
||||
|
@ -20,7 +20,8 @@ void AlphaBlend(PackedFrame* frame, float background[3]) {
|
|||
return;
|
||||
}
|
||||
--format.num_channels;
|
||||
PackedImage blended(im.xsize, im.ysize, format);
|
||||
JXL_ASSIGN_OR_DIE(PackedImage blended,
|
||||
PackedImage::Create(im.xsize, im.ysize, format));
|
||||
// TODO(szabadka) SIMDify this and make it work for float16.
|
||||
for (size_t y = 0; y < im.ysize; ++y) {
|
||||
for (size_t x = 0; x < im.xsize; ++x) {
|
||||
|
@ -48,7 +49,7 @@ void AlphaBlend(PackedFrame* frame, float background[3]) {
|
|||
|
||||
} // namespace
|
||||
|
||||
void AlphaBlend(PackedPixelFile* ppf, float background[3]) {
|
||||
void AlphaBlend(PackedPixelFile* ppf, const float background[3]) {
|
||||
if (!ppf || ppf->info.alpha_bits == 0) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
namespace jxl {
|
||||
namespace extras {
|
||||
|
||||
void AlphaBlend(PackedPixelFile* ppf, float background[3]);
|
||||
void AlphaBlend(PackedPixelFile* ppf, const float background[3]);
|
||||
|
||||
} // namespace extras
|
||||
} // namespace jxl
|
||||
|
|
|
@ -43,7 +43,7 @@ JXL_INLINE Status SetFromBytes(const Span<const uint8_t> bytes, CodecInOut* io,
|
|||
orig_codec);
|
||||
}
|
||||
|
||||
Status Encode(const extras::PackedPixelFile& ppf, const extras::Codec codec,
|
||||
Status Encode(const extras::PackedPixelFile& ppf, extras::Codec codec,
|
||||
std::vector<uint8_t>* bytes, ThreadPool* pool);
|
||||
|
||||
Status Encode(const extras::PackedPixelFile& ppf, const std::string& pathname,
|
||||
|
|
|
@ -40,12 +40,6 @@ using test::ThreadPoolForTests;
|
|||
namespace extras {
|
||||
namespace {
|
||||
|
||||
using ::testing::AllOf;
|
||||
using ::testing::Contains;
|
||||
using ::testing::Field;
|
||||
using ::testing::IsEmpty;
|
||||
using ::testing::SizeIs;
|
||||
|
||||
std::string ExtensionFromCodec(Codec codec, const bool is_gray,
|
||||
const bool has_alpha,
|
||||
const size_t bits_per_sample) {
|
||||
|
@ -78,8 +72,8 @@ void VerifySameImage(const PackedImage& im0, size_t bits_per_sample0,
|
|||
};
|
||||
double factor0 = get_factor(im0.format, bits_per_sample0);
|
||||
double factor1 = get_factor(im1.format, bits_per_sample1);
|
||||
auto pixels0 = static_cast<const uint8_t*>(im0.pixels());
|
||||
auto pixels1 = static_cast<const uint8_t*>(im1.pixels());
|
||||
const auto* pixels0 = static_cast<const uint8_t*>(im0.pixels());
|
||||
const auto* pixels1 = static_cast<const uint8_t*>(im1.pixels());
|
||||
auto rgba0 =
|
||||
test::ConvertToRGBA32(pixels0, im0.xsize, im0.ysize, im0.format, factor0);
|
||||
auto rgba1 =
|
||||
|
@ -227,19 +221,23 @@ void CreateTestImage(const TestImageParams& params, PackedPixelFile* ppf) {
|
|||
ppf->info.exponent_bits_per_sample = params.bits_per_sample == 32 ? 8 : 0;
|
||||
ppf->info.num_color_channels = params.is_gray ? 1 : 3;
|
||||
ppf->info.alpha_bits = params.add_alpha ? params.bits_per_sample : 0;
|
||||
ppf->info.alpha_premultiplied = (params.codec == Codec::kEXR);
|
||||
ppf->info.alpha_premultiplied = TO_JXL_BOOL(params.codec == Codec::kEXR);
|
||||
|
||||
JxlColorEncoding color_encoding = CreateTestColorEncoding(params.is_gray);
|
||||
ppf->icc = GenerateICC(color_encoding);
|
||||
ppf->color_encoding = color_encoding;
|
||||
|
||||
PackedFrame frame(params.xsize, params.ysize, params.PixelFormat());
|
||||
JXL_ASSIGN_OR_DIE(
|
||||
PackedFrame frame,
|
||||
PackedFrame::Create(params.xsize, params.ysize, params.PixelFormat()));
|
||||
FillPackedImage(params.bits_per_sample, &frame.color);
|
||||
if (params.add_extra_channels) {
|
||||
for (size_t i = 0; i < 7; ++i) {
|
||||
JxlPixelFormat ec_format = params.PixelFormat();
|
||||
ec_format.num_channels = 1;
|
||||
PackedImage ec(params.xsize, params.ysize, ec_format);
|
||||
JXL_ASSIGN_OR_DIE(
|
||||
PackedImage ec,
|
||||
PackedImage::Create(params.xsize, params.ysize, ec_format));
|
||||
FillPackedImage(params.bits_per_sample, &ec);
|
||||
frame.extra_channels.emplace_back(std::move(ec));
|
||||
PackedExtraChannel pec;
|
||||
|
@ -432,15 +430,17 @@ TEST(CodecTest, EncodeToPNG) {
|
|||
ASSERT_TRUE(extras::DecodeBytes(Bytes(original_png), ColorHints(), &ppf));
|
||||
|
||||
const JxlPixelFormat& format = ppf.frames.front().color.format;
|
||||
ASSERT_THAT(
|
||||
png_encoder->AcceptedFormats(),
|
||||
Contains(AllOf(Field(&JxlPixelFormat::num_channels, format.num_channels),
|
||||
Field(&JxlPixelFormat::data_type, format.data_type),
|
||||
Field(&JxlPixelFormat::endianness, format.endianness))));
|
||||
const auto& format_matcher = [&format](const JxlPixelFormat& candidate) {
|
||||
return (candidate.num_channels == format.num_channels) &&
|
||||
(candidate.data_type == format.data_type) &&
|
||||
(candidate.endianness == format.endianness);
|
||||
};
|
||||
const auto formats = png_encoder->AcceptedFormats();
|
||||
ASSERT_TRUE(std::any_of(formats.begin(), formats.end(), format_matcher));
|
||||
EncodedImage encoded_png;
|
||||
ASSERT_TRUE(png_encoder->Encode(ppf, &encoded_png, pool));
|
||||
EXPECT_THAT(encoded_png.icc, IsEmpty());
|
||||
ASSERT_THAT(encoded_png.bitstreams, SizeIs(1));
|
||||
EXPECT_TRUE(encoded_png.icc.empty());
|
||||
ASSERT_EQ(encoded_png.bitstreams.size(), 1);
|
||||
|
||||
PackedPixelFile decoded_ppf;
|
||||
ASSERT_TRUE(extras::DecodeBytes(Bytes(encoded_png.bitstreams.front()),
|
||||
|
|
|
@ -71,9 +71,7 @@ const png_byte kIgnoredPngChunks[] = {
|
|||
};
|
||||
|
||||
// Returns floating-point value from the PNG encoding (times 10^5).
|
||||
static double F64FromU32(const uint32_t x) {
|
||||
return static_cast<int32_t>(x) * 1E-5;
|
||||
}
|
||||
double F64FromU32(const uint32_t x) { return static_cast<int32_t>(x) * 1E-5; }
|
||||
|
||||
Status DecodeSRGB(const unsigned char* payload, const size_t payload_size,
|
||||
JxlColorEncoding* color_encoding) {
|
||||
|
@ -402,7 +400,8 @@ class BlobsReaderPNG {
|
|||
}
|
||||
|
||||
if (pos + 2 >= encoded_end) return false; // Truncated base16 2;
|
||||
uint32_t nibble0, nibble1;
|
||||
uint32_t nibble0;
|
||||
uint32_t nibble1;
|
||||
JXL_RETURN_IF_ERROR(DecodeNibble(pos[0], &nibble0));
|
||||
JXL_RETURN_IF_ERROR(DecodeNibble(pos[1], &nibble1));
|
||||
bytes->push_back(static_cast<uint8_t>((nibble0 << 4) + nibble1));
|
||||
|
@ -432,9 +431,22 @@ constexpr uint32_t kId_cHRM = 0x4D524863;
|
|||
constexpr uint32_t kId_eXIf = 0x66495865;
|
||||
|
||||
struct APNGFrame {
|
||||
std::vector<uint8_t> pixels;
|
||||
APNGFrame() : pixels(nullptr, free) {}
|
||||
std::unique_ptr<void, decltype(free)*> pixels;
|
||||
size_t pixels_size = 0;
|
||||
std::vector<uint8_t*> rows;
|
||||
unsigned int w, h, delay_num, delay_den;
|
||||
Status Resize(size_t new_size) {
|
||||
if (new_size > pixels_size) {
|
||||
pixels.reset(malloc(new_size));
|
||||
if (!pixels.get()) {
|
||||
// TODO(szabadka): use specialized OOM error code
|
||||
return JXL_FAILURE("Failed to allocate memory for image buffer");
|
||||
}
|
||||
pixels_size = new_size;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct Reader {
|
||||
|
@ -447,7 +459,7 @@ struct Reader {
|
|||
next += to_copy;
|
||||
return (len == to_copy);
|
||||
}
|
||||
bool Eof() { return next == last; }
|
||||
bool Eof() const { return next == last; }
|
||||
};
|
||||
|
||||
const unsigned long cMaxPNGSize = 1000000UL;
|
||||
|
@ -463,10 +475,11 @@ void info_fn(png_structp png_ptr, png_infop info_ptr) {
|
|||
|
||||
void row_fn(png_structp png_ptr, png_bytep new_row, png_uint_32 row_num,
|
||||
int pass) {
|
||||
APNGFrame* frame = (APNGFrame*)png_get_progressive_ptr(png_ptr);
|
||||
APNGFrame* frame =
|
||||
reinterpret_cast<APNGFrame*>(png_get_progressive_ptr(png_ptr));
|
||||
JXL_CHECK(frame);
|
||||
JXL_CHECK(row_num < frame->rows.size());
|
||||
JXL_CHECK(frame->rows[row_num] < frame->pixels.data() + frame->pixels.size());
|
||||
JXL_CHECK(frame->rows[row_num] < frame->rows[0] + frame->pixels_size);
|
||||
png_progressive_combine_row(png_ptr, frame->rows[row_num], new_row);
|
||||
}
|
||||
|
||||
|
@ -494,12 +507,13 @@ int processing_start(png_structp& png_ptr, png_infop& info_ptr, void* frame_ptr,
|
|||
unsigned char header[8] = {137, 80, 78, 71, 13, 10, 26, 10};
|
||||
|
||||
// Cleanup prior decoder, if any.
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, 0);
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
|
||||
// Just in case. Not all versions on libpng wipe-out the pointers.
|
||||
png_ptr = nullptr;
|
||||
info_ptr = nullptr;
|
||||
|
||||
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
png_ptr =
|
||||
png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
|
||||
info_ptr = png_create_info_struct(png_ptr);
|
||||
if (!png_ptr || !info_ptr) return 1;
|
||||
|
||||
|
@ -508,18 +522,17 @@ int processing_start(png_structp& png_ptr, png_infop& info_ptr, void* frame_ptr,
|
|||
}
|
||||
|
||||
png_set_keep_unknown_chunks(png_ptr, 1, kIgnoredPngChunks,
|
||||
(int)sizeof(kIgnoredPngChunks) / 5);
|
||||
static_cast<int>(sizeof(kIgnoredPngChunks) / 5));
|
||||
|
||||
png_set_crc_action(png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);
|
||||
png_set_progressive_read_fn(png_ptr, frame_ptr, info_fn, row_fn, NULL);
|
||||
png_set_progressive_read_fn(png_ptr, frame_ptr, info_fn, row_fn, nullptr);
|
||||
|
||||
png_process_data(png_ptr, info_ptr, header, 8);
|
||||
png_process_data(png_ptr, info_ptr, chunkIHDR.data(), chunkIHDR.size());
|
||||
|
||||
if (hasInfo) {
|
||||
for (unsigned int i = 0; i < chunksInfo.size(); i++) {
|
||||
png_process_data(png_ptr, info_ptr, chunksInfo[i].data(),
|
||||
chunksInfo[i].size());
|
||||
for (auto& chunk : chunksInfo) {
|
||||
png_process_data(png_ptr, info_ptr, chunk.data(), chunk.size());
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -575,8 +588,6 @@ Status DecodeImageAPNG(const Span<const uint8_t> bytes,
|
|||
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;
|
||||
unsigned char sig[8];
|
||||
png_structp png_ptr = nullptr;
|
||||
png_infop info_ptr = nullptr;
|
||||
|
@ -588,7 +599,7 @@ Status DecodeImageAPNG(const Span<const uint8_t> bytes,
|
|||
bool seenFctl = false;
|
||||
APNGFrame frameRaw = {};
|
||||
uint32_t num_channels;
|
||||
JxlPixelFormat format;
|
||||
JxlPixelFormat format = {};
|
||||
unsigned int bytes_per_pixel = 0;
|
||||
|
||||
struct FrameInfo {
|
||||
|
@ -604,7 +615,7 @@ Status DecodeImageAPNG(const Span<const uint8_t> bytes,
|
|||
|
||||
// Make sure png memory is released in any case.
|
||||
auto scope_guard = MakeScopeGuard([&]() {
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, 0);
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
|
||||
// Just in case. Not all versions on libpng wipe-out the pointers.
|
||||
png_ptr = nullptr;
|
||||
info_ptr = nullptr;
|
||||
|
@ -616,7 +627,7 @@ Status DecodeImageAPNG(const Span<const uint8_t> bytes,
|
|||
if (!r.Read(sig, 8) || memcmp(sig, png_signature, 8) != 0) {
|
||||
return false;
|
||||
}
|
||||
id = read_chunk(&r, &chunkIHDR);
|
||||
unsigned int id = read_chunk(&r, &chunkIHDR);
|
||||
|
||||
ppf->info.exponent_bits_per_sample = 0;
|
||||
ppf->info.alpha_exponent_bits = 0;
|
||||
|
@ -625,18 +636,22 @@ Status DecodeImageAPNG(const Span<const uint8_t> bytes,
|
|||
ppf->frames.clear();
|
||||
|
||||
bool have_color = false;
|
||||
bool have_cicp = false, have_iccp = false, have_srgb = false;
|
||||
bool have_cicp = false;
|
||||
bool have_iccp = false;
|
||||
bool have_srgb = false;
|
||||
bool errorstate = true;
|
||||
if (id == kId_IHDR && chunkIHDR.size() == 25) {
|
||||
x0 = 0;
|
||||
y0 = 0;
|
||||
delay_num = 1;
|
||||
delay_den = 10;
|
||||
dop = 0;
|
||||
bop = 0;
|
||||
unsigned int x0 = 0;
|
||||
unsigned int y0 = 0;
|
||||
unsigned int delay_num = 1;
|
||||
unsigned int delay_den = 10;
|
||||
unsigned int dop = 0;
|
||||
unsigned int bop = 0;
|
||||
|
||||
w0 = w = png_get_uint_32(chunkIHDR.data() + 8);
|
||||
h0 = h = png_get_uint_32(chunkIHDR.data() + 12);
|
||||
unsigned int w = png_get_uint_32(chunkIHDR.data() + 8);
|
||||
unsigned int h = png_get_uint_32(chunkIHDR.data() + 12);
|
||||
unsigned int w0 = w;
|
||||
unsigned int h0 = h;
|
||||
if (w > cMaxPNGSize || h > cMaxPNGSize) {
|
||||
return false;
|
||||
}
|
||||
|
@ -648,8 +663,8 @@ Status DecodeImageAPNG(const Span<const uint8_t> bytes,
|
|||
ppf->color_encoding.transfer_function = JXL_TRANSFER_FUNCTION_SRGB;
|
||||
ppf->color_encoding.rendering_intent = JXL_RENDERING_INTENT_RELATIVE;
|
||||
|
||||
if (!processing_start(png_ptr, info_ptr, (void*)&frameRaw, hasInfo,
|
||||
chunkIHDR, chunksInfo)) {
|
||||
if (!processing_start(png_ptr, info_ptr, static_cast<void*>(&frameRaw),
|
||||
hasInfo, chunkIHDR, chunksInfo)) {
|
||||
while (!r.Eof()) {
|
||||
id = read_chunk(&r, &chunk);
|
||||
if (!id) break;
|
||||
|
@ -657,7 +672,7 @@ Status DecodeImageAPNG(const Span<const uint8_t> bytes,
|
|||
|
||||
if (id == kId_acTL && !hasInfo && !isAnimated) {
|
||||
isAnimated = true;
|
||||
ppf->info.have_animation = true;
|
||||
ppf->info.have_animation = JXL_TRUE;
|
||||
ppf->info.animation.tps_numerator = 1000;
|
||||
ppf->info.animation.tps_denominator = 1;
|
||||
} else if (id == kId_IEND ||
|
||||
|
@ -666,8 +681,10 @@ Status DecodeImageAPNG(const Span<const uint8_t> bytes,
|
|||
if (!processing_finish(png_ptr, info_ptr, &ppf->metadata)) {
|
||||
// Allocates the frame buffer.
|
||||
uint32_t duration = delay_num * 1000 / delay_den;
|
||||
frames.push_back(FrameInfo{PackedImage(w0, h0, format), duration,
|
||||
x0, w0, y0, h0, dop, bop});
|
||||
JXL_ASSIGN_OR_RETURN(PackedImage image,
|
||||
PackedImage::Create(w0, h0, format));
|
||||
frames.push_back(FrameInfo{std::move(image), duration, x0, w0, y0,
|
||||
h0, dop, bop});
|
||||
auto& frame = frames.back().data;
|
||||
for (size_t y = 0; y < h0; ++y) {
|
||||
memcpy(static_cast<uint8_t*>(frame.pixels()) + frame.stride * y,
|
||||
|
@ -707,7 +724,8 @@ Status DecodeImageAPNG(const Span<const uint8_t> bytes,
|
|||
|
||||
if (hasInfo) {
|
||||
memcpy(chunkIHDR.data() + 8, chunk.data() + 12, 8);
|
||||
if (processing_start(png_ptr, info_ptr, (void*)&frameRaw, hasInfo,
|
||||
if (processing_start(png_ptr, info_ptr,
|
||||
static_cast<void*>(&frameRaw), hasInfo,
|
||||
chunkIHDR, chunksInfo)) {
|
||||
break;
|
||||
}
|
||||
|
@ -724,7 +742,7 @@ Status DecodeImageAPNG(const Span<const uint8_t> bytes,
|
|||
int colortype = png_get_color_type(png_ptr, info_ptr);
|
||||
int png_bit_depth = png_get_bit_depth(png_ptr, info_ptr);
|
||||
ppf->info.bits_per_sample = png_bit_depth;
|
||||
png_color_8p sigbits = NULL;
|
||||
png_color_8p sigbits = nullptr;
|
||||
png_get_sBIT(png_ptr, info_ptr, &sigbits);
|
||||
if (colortype & 1) {
|
||||
// palette will actually be 8-bit regardless of the index bitdepth
|
||||
|
@ -784,12 +802,18 @@ Status DecodeImageAPNG(const Span<const uint8_t> bytes,
|
|||
}
|
||||
bytes_per_pixel =
|
||||
num_channels * (format.data_type == JXL_TYPE_UINT16 ? 2 : 1);
|
||||
rowbytes = w * bytes_per_pixel;
|
||||
imagesize = h * rowbytes;
|
||||
frameRaw.pixels.resize(imagesize);
|
||||
size_t rowbytes = w * bytes_per_pixel;
|
||||
if (h > std::numeric_limits<size_t>::max() / rowbytes) {
|
||||
return JXL_FAILURE("Image too big.");
|
||||
}
|
||||
size_t imagesize = h * rowbytes;
|
||||
JXL_RETURN_IF_ERROR(frameRaw.Resize(imagesize));
|
||||
frameRaw.rows.resize(h);
|
||||
for (j = 0; j < h; j++)
|
||||
frameRaw.rows[j] = frameRaw.pixels.data() + j * rowbytes;
|
||||
for (size_t j = 0; j < h; j++) {
|
||||
frameRaw.rows[j] =
|
||||
reinterpret_cast<uint8_t*>(frameRaw.pixels.get()) +
|
||||
j * rowbytes;
|
||||
}
|
||||
|
||||
if (processing_data(png_ptr, info_ptr, chunk.data(), chunk.size())) {
|
||||
break;
|
||||
|
@ -925,7 +949,8 @@ Status DecodeImageAPNG(const Span<const uint8_t> bytes,
|
|||
py0 + pys >= y0 + ysize && use_for_next_frame) {
|
||||
// If the new frame is contained within the old frame, we can pad the
|
||||
// new frame with zeros and not blend.
|
||||
PackedImage new_data(pxs, pys, frame.data.format);
|
||||
JXL_ASSIGN_OR_RETURN(PackedImage new_data,
|
||||
PackedImage::Create(pxs, pys, frame.data.format));
|
||||
memset(new_data.pixels(), 0, new_data.pixels_size);
|
||||
for (size_t y = 0; y < ysize; y++) {
|
||||
size_t bytes_per_pixel =
|
||||
|
@ -947,7 +972,8 @@ Status DecodeImageAPNG(const Span<const uint8_t> bytes,
|
|||
ppf->frames.emplace_back(std::move(new_data));
|
||||
} else {
|
||||
// If all else fails, insert a placeholder blank frame with kReplace.
|
||||
PackedImage blank(pxs, pys, frame.data.format);
|
||||
JXL_ASSIGN_OR_RETURN(PackedImage blank,
|
||||
PackedImage::Create(pxs, pys, frame.data.format));
|
||||
memset(blank.pixels(), 0, blank.pixels_size);
|
||||
ppf->frames.emplace_back(std::move(blank));
|
||||
auto& pframe = ppf->frames.back();
|
||||
|
@ -987,7 +1013,7 @@ Status DecodeImageAPNG(const Span<const uint8_t> bytes,
|
|||
has_nontrivial_background && frame.dispose_op == DISPOSE_OP_BACKGROUND;
|
||||
}
|
||||
if (ppf->frames.empty()) return JXL_FAILURE("No frames decoded");
|
||||
ppf->frames.back().frame_info.is_last = true;
|
||||
ppf->frames.back().frame_info.is_last = JXL_TRUE;
|
||||
|
||||
return true;
|
||||
#else
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
#include <cmath>
|
||||
|
||||
#include "lib/jxl/base/common.h"
|
||||
|
||||
namespace jxl {
|
||||
|
||||
namespace {
|
||||
|
@ -19,49 +21,46 @@ struct EnumName {
|
|||
T value;
|
||||
};
|
||||
|
||||
const EnumName<JxlColorSpace> kJxlColorSpaceNames[] = {
|
||||
{"RGB", JXL_COLOR_SPACE_RGB},
|
||||
{"Gra", JXL_COLOR_SPACE_GRAY},
|
||||
{"XYB", JXL_COLOR_SPACE_XYB},
|
||||
{"CS?", JXL_COLOR_SPACE_UNKNOWN},
|
||||
};
|
||||
constexpr auto kJxlColorSpaceNames =
|
||||
to_array<EnumName<JxlColorSpace>>({{"RGB", JXL_COLOR_SPACE_RGB},
|
||||
{"Gra", JXL_COLOR_SPACE_GRAY},
|
||||
{"XYB", JXL_COLOR_SPACE_XYB},
|
||||
{"CS?", JXL_COLOR_SPACE_UNKNOWN}});
|
||||
|
||||
const EnumName<JxlWhitePoint> kJxlWhitePointNames[] = {
|
||||
{"D65", JXL_WHITE_POINT_D65},
|
||||
{"Cst", JXL_WHITE_POINT_CUSTOM},
|
||||
{"EER", JXL_WHITE_POINT_E},
|
||||
{"DCI", JXL_WHITE_POINT_DCI},
|
||||
};
|
||||
constexpr auto kJxlWhitePointNames =
|
||||
to_array<EnumName<JxlWhitePoint>>({{"D65", JXL_WHITE_POINT_D65},
|
||||
{"Cst", JXL_WHITE_POINT_CUSTOM},
|
||||
{"EER", JXL_WHITE_POINT_E},
|
||||
{"DCI", JXL_WHITE_POINT_DCI}});
|
||||
|
||||
const EnumName<JxlPrimaries> kJxlPrimariesNames[] = {
|
||||
{"SRG", JXL_PRIMARIES_SRGB},
|
||||
{"Cst", JXL_PRIMARIES_CUSTOM},
|
||||
{"202", JXL_PRIMARIES_2100},
|
||||
{"DCI", JXL_PRIMARIES_P3},
|
||||
};
|
||||
constexpr auto kJxlPrimariesNames =
|
||||
to_array<EnumName<JxlPrimaries>>({{"SRG", JXL_PRIMARIES_SRGB},
|
||||
{"Cst", JXL_PRIMARIES_CUSTOM},
|
||||
{"202", JXL_PRIMARIES_2100},
|
||||
{"DCI", JXL_PRIMARIES_P3}});
|
||||
|
||||
const EnumName<JxlTransferFunction> kJxlTransferFunctionNames[] = {
|
||||
{"709", JXL_TRANSFER_FUNCTION_709},
|
||||
{"TF?", JXL_TRANSFER_FUNCTION_UNKNOWN},
|
||||
{"Lin", JXL_TRANSFER_FUNCTION_LINEAR},
|
||||
{"SRG", JXL_TRANSFER_FUNCTION_SRGB},
|
||||
{"PeQ", JXL_TRANSFER_FUNCTION_PQ},
|
||||
{"DCI", JXL_TRANSFER_FUNCTION_DCI},
|
||||
{"HLG", JXL_TRANSFER_FUNCTION_HLG},
|
||||
{"", JXL_TRANSFER_FUNCTION_GAMMA},
|
||||
};
|
||||
constexpr auto kJxlTransferFunctionNames =
|
||||
to_array<EnumName<JxlTransferFunction>>(
|
||||
{{"709", JXL_TRANSFER_FUNCTION_709},
|
||||
{"TF?", JXL_TRANSFER_FUNCTION_UNKNOWN},
|
||||
{"Lin", JXL_TRANSFER_FUNCTION_LINEAR},
|
||||
{"SRG", JXL_TRANSFER_FUNCTION_SRGB},
|
||||
{"PeQ", JXL_TRANSFER_FUNCTION_PQ},
|
||||
{"DCI", JXL_TRANSFER_FUNCTION_DCI},
|
||||
{"HLG", JXL_TRANSFER_FUNCTION_HLG},
|
||||
{"", JXL_TRANSFER_FUNCTION_GAMMA}});
|
||||
|
||||
const EnumName<JxlRenderingIntent> kJxlRenderingIntentNames[] = {
|
||||
{"Per", JXL_RENDERING_INTENT_PERCEPTUAL},
|
||||
{"Rel", JXL_RENDERING_INTENT_RELATIVE},
|
||||
{"Sat", JXL_RENDERING_INTENT_SATURATION},
|
||||
{"Abs", JXL_RENDERING_INTENT_ABSOLUTE},
|
||||
};
|
||||
constexpr auto kJxlRenderingIntentNames =
|
||||
to_array<EnumName<JxlRenderingIntent>>(
|
||||
{{"Per", JXL_RENDERING_INTENT_PERCEPTUAL},
|
||||
{"Rel", JXL_RENDERING_INTENT_RELATIVE},
|
||||
{"Sat", JXL_RENDERING_INTENT_SATURATION},
|
||||
{"Abs", JXL_RENDERING_INTENT_ABSOLUTE}});
|
||||
|
||||
template <typename T>
|
||||
Status ParseEnum(const std::string& token, const EnumName<T>* enum_values,
|
||||
size_t enum_len, T* value) {
|
||||
for (size_t i = 0; i < enum_len; i++) {
|
||||
template <typename T, size_t N>
|
||||
Status ParseEnum(const std::string& token,
|
||||
const std::array<EnumName<T>, N>& enum_values, T* value) {
|
||||
for (size_t i = 0; i < enum_values.size(); i++) {
|
||||
if (enum_values[i].name == token) {
|
||||
*value = enum_values[i].value;
|
||||
return true;
|
||||
|
@ -69,9 +68,6 @@ Status ParseEnum(const std::string& token, const EnumName<T>* enum_values,
|
|||
}
|
||||
return false;
|
||||
}
|
||||
#define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0]))
|
||||
#define PARSE_ENUM(type, token, value) \
|
||||
ParseEnum<type>(token, k##type##Names, ARRAY_SIZE(k##type##Names), value)
|
||||
|
||||
class Tokenizer {
|
||||
public:
|
||||
|
@ -122,7 +118,7 @@ Status ParseColorSpace(Tokenizer* tokenizer, JxlColorEncoding* c) {
|
|||
std::string str;
|
||||
JXL_RETURN_IF_ERROR(tokenizer->Next(&str));
|
||||
JxlColorSpace cs;
|
||||
if (PARSE_ENUM(JxlColorSpace, str, &cs)) {
|
||||
if (ParseEnum(str, kJxlColorSpaceNames, &cs)) {
|
||||
c->color_space = cs;
|
||||
return true;
|
||||
}
|
||||
|
@ -139,7 +135,7 @@ Status ParseWhitePoint(Tokenizer* tokenizer, JxlColorEncoding* c) {
|
|||
|
||||
std::string str;
|
||||
JXL_RETURN_IF_ERROR(tokenizer->Next(&str));
|
||||
if (PARSE_ENUM(JxlWhitePoint, str, &c->white_point)) return true;
|
||||
if (ParseEnum(str, kJxlWhitePointNames, &c->white_point)) return true;
|
||||
|
||||
Tokenizer xy_tokenizer(&str, ';');
|
||||
c->white_point = JXL_WHITE_POINT_CUSTOM;
|
||||
|
@ -157,7 +153,7 @@ Status ParsePrimaries(Tokenizer* tokenizer, JxlColorEncoding* c) {
|
|||
|
||||
std::string str;
|
||||
JXL_RETURN_IF_ERROR(tokenizer->Next(&str));
|
||||
if (PARSE_ENUM(JxlPrimaries, str, &c->primaries)) return true;
|
||||
if (ParseEnum(str, kJxlPrimariesNames, &c->primaries)) return true;
|
||||
|
||||
Tokenizer xy_tokenizer(&str, ';');
|
||||
JXL_RETURN_IF_ERROR(ParseDouble(&xy_tokenizer, c->primaries_red_xy + 0));
|
||||
|
@ -174,7 +170,8 @@ Status ParsePrimaries(Tokenizer* tokenizer, JxlColorEncoding* c) {
|
|||
Status ParseRenderingIntent(Tokenizer* tokenizer, JxlColorEncoding* c) {
|
||||
std::string str;
|
||||
JXL_RETURN_IF_ERROR(tokenizer->Next(&str));
|
||||
if (PARSE_ENUM(JxlRenderingIntent, str, &c->rendering_intent)) return true;
|
||||
if (ParseEnum(str, kJxlRenderingIntentNames, &c->rendering_intent))
|
||||
return true;
|
||||
|
||||
return JXL_FAILURE("Invalid RenderingIntent %s\n", str.c_str());
|
||||
}
|
||||
|
@ -189,7 +186,7 @@ Status ParseTransferFunction(Tokenizer* tokenizer, JxlColorEncoding* c) {
|
|||
|
||||
std::string str;
|
||||
JXL_RETURN_IF_ERROR(tokenizer->Next(&str));
|
||||
if (PARSE_ENUM(JxlTransferFunction, str, &c->transfer_function)) {
|
||||
if (ParseEnum(str, kJxlTransferFunctionNames, &c->transfer_function)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,8 @@ std::string GetExtension(const std::string& path) {
|
|||
|
||||
} // namespace
|
||||
|
||||
Codec CodecFromPath(std::string path, size_t* JXL_RESTRICT bits_per_sample,
|
||||
Codec CodecFromPath(const std::string& path,
|
||||
size_t* JXL_RESTRICT bits_per_sample,
|
||||
std::string* extension) {
|
||||
std::string ext = GetExtension(path);
|
||||
if (extension) {
|
||||
|
@ -98,7 +99,7 @@ Status DecodeBytes(const Span<const uint8_t> bytes,
|
|||
*ppf = extras::PackedPixelFile();
|
||||
|
||||
// Default values when not set by decoders.
|
||||
ppf->info.uses_original_profile = true;
|
||||
ppf->info.uses_original_profile = JXL_TRUE;
|
||||
ppf->info.orientation = JXL_ORIENT_IDENTITY;
|
||||
|
||||
const auto choose_codec = [&]() -> Codec {
|
||||
|
@ -116,6 +117,7 @@ Status DecodeBytes(const Span<const uint8_t> bytes,
|
|||
dparams.accepted_formats.push_back(
|
||||
{num_channels, JXL_TYPE_FLOAT, JXL_LITTLE_ENDIAN, /*align=*/0});
|
||||
}
|
||||
dparams.output_bitdepth.type = JXL_BIT_DEPTH_FROM_CODESTREAM;
|
||||
size_t decoded_bytes;
|
||||
if (DecodeImageJXL(bytes.data(), bytes.size(), dparams, &decoded_bytes,
|
||||
ppf) &&
|
||||
|
|
|
@ -40,7 +40,7 @@ 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.
|
||||
Codec CodecFromPath(std::string path,
|
||||
Codec CodecFromPath(const std::string& path,
|
||||
size_t* JXL_RESTRICT bits_per_sample = nullptr,
|
||||
std::string* extension = nullptr);
|
||||
|
||||
|
|
|
@ -121,7 +121,12 @@ Status DecodeImageEXR(Span<const uint8_t> bytes, const ColorHints& color_hints,
|
|||
};
|
||||
ppf->frames.clear();
|
||||
// Allocates the frame buffer.
|
||||
ppf->frames.emplace_back(image_size.x, image_size.y, format);
|
||||
{
|
||||
JXL_ASSIGN_OR_RETURN(
|
||||
PackedFrame frame,
|
||||
PackedFrame::Create(image_size.x, image_size.y, format));
|
||||
ppf->frames.emplace_back(std::move(frame));
|
||||
}
|
||||
const auto& frame = ppf->frames.back();
|
||||
|
||||
const int row_size = input.dataWindow().size().x + 1;
|
||||
|
@ -188,7 +193,7 @@ Status DecodeImageEXR(Span<const uint8_t> bytes, const ColorHints& color_hints,
|
|||
if (has_alpha) {
|
||||
ppf->info.alpha_bits = kExrAlphaBits;
|
||||
ppf->info.alpha_exponent_bits = ppf->info.exponent_bits_per_sample;
|
||||
ppf->info.alpha_premultiplied = true;
|
||||
ppf->info.alpha_premultiplied = JXL_TRUE;
|
||||
}
|
||||
ppf->info.intensity_target = intensity_target;
|
||||
return true;
|
||||
|
|
|
@ -50,8 +50,10 @@ void ensure_have_alpha(PackedFrame* frame) {
|
|||
/*endianness=*/JXL_NATIVE_ENDIAN,
|
||||
/*align=*/0,
|
||||
};
|
||||
frame->extra_channels.emplace_back(frame->color.xsize, frame->color.ysize,
|
||||
alpha_format);
|
||||
JXL_ASSIGN_OR_DIE(PackedImage image,
|
||||
PackedImage::Create(frame->color.xsize, frame->color.ysize,
|
||||
alpha_format));
|
||||
frame->extra_channels.emplace_back(std::move(image));
|
||||
// We need to set opaque-by-default.
|
||||
std::fill_n(static_cast<uint8_t*>(frame->extra_channels[0].pixels()),
|
||||
frame->color.xsize * frame->color.ysize, 255u);
|
||||
|
@ -136,7 +138,7 @@ Status DecodeImageGIF(Span<const uint8_t> bytes, const ColorHints& color_hints,
|
|||
}
|
||||
|
||||
if (gif->ImageCount > 1) {
|
||||
ppf->info.have_animation = true;
|
||||
ppf->info.have_animation = JXL_TRUE;
|
||||
// Delays in GIF are specified in 100ths of a second.
|
||||
ppf->info.animation.tps_numerator = 100;
|
||||
ppf->info.animation.tps_denominator = 1;
|
||||
|
@ -186,7 +188,9 @@ Status DecodeImageGIF(Span<const uint8_t> bytes, const ColorHints& color_hints,
|
|||
}
|
||||
const PackedRgba background_rgba{background_color.Red, background_color.Green,
|
||||
background_color.Blue, 0};
|
||||
PackedFrame canvas(gif->SWidth, gif->SHeight, canvas_format);
|
||||
JXL_ASSIGN_OR_RETURN(
|
||||
PackedFrame canvas,
|
||||
PackedFrame::Create(gif->SWidth, gif->SHeight, canvas_format));
|
||||
std::fill_n(static_cast<PackedRgba*>(canvas.color.pixels()),
|
||||
canvas.color.xsize * canvas.color.ysize, background_rgba);
|
||||
Rect canvas_rect{0, 0, canvas.color.xsize, canvas.color.ysize};
|
||||
|
@ -230,8 +234,14 @@ Status DecodeImageGIF(Span<const uint8_t> bytes, const ColorHints& color_hints,
|
|||
}
|
||||
|
||||
// Allocates the frame buffer.
|
||||
ppf->frames.emplace_back(total_rect.xsize(), total_rect.ysize(),
|
||||
packed_frame_format);
|
||||
{
|
||||
JXL_ASSIGN_OR_RETURN(
|
||||
PackedFrame frame,
|
||||
PackedFrame::Create(total_rect.xsize(), total_rect.ysize(),
|
||||
packed_frame_format));
|
||||
ppf->frames.emplace_back(std::move(frame));
|
||||
}
|
||||
|
||||
PackedFrame* frame = &ppf->frames.back();
|
||||
|
||||
// We cannot tell right from the start whether there will be a
|
||||
|
@ -301,8 +311,10 @@ Status DecodeImageGIF(Span<const uint8_t> bytes, const ColorHints& color_hints,
|
|||
}
|
||||
|
||||
// Update the canvas by creating a copy first.
|
||||
PackedImage new_canvas_image(canvas.color.xsize, canvas.color.ysize,
|
||||
canvas.color.format);
|
||||
JXL_ASSIGN_OR_RETURN(
|
||||
PackedImage new_canvas_image,
|
||||
PackedImage::Create(canvas.color.xsize, canvas.color.ysize,
|
||||
canvas.color.format));
|
||||
memcpy(new_canvas_image.pixels(), canvas.color.pixels(),
|
||||
new_canvas_image.pixels_size);
|
||||
for (size_t y = 0, byte_index = 0; y < image_rect.ysize(); ++y) {
|
||||
|
|
|
@ -27,7 +27,7 @@ constexpr unsigned char kExifSignature[6] = {0x45, 0x78, 0x69,
|
|||
constexpr int kExifMarker = JPEG_APP0 + 1;
|
||||
constexpr int kICCMarker = JPEG_APP0 + 2;
|
||||
|
||||
static inline bool IsJPG(const std::vector<uint8_t>& bytes) {
|
||||
inline bool IsJPG(const std::vector<uint8_t>& bytes) {
|
||||
if (bytes.size() < 2) return false;
|
||||
if (bytes[0] != 0xFF || bytes[1] != 0xD8) return false;
|
||||
return true;
|
||||
|
@ -218,7 +218,7 @@ Status DecodeJpeg(const std::vector<uint8_t>& compressed,
|
|||
} else {
|
||||
return failure("unsupported data type");
|
||||
}
|
||||
ppf->info.uses_original_profile = true;
|
||||
ppf->info.uses_original_profile = JXL_TRUE;
|
||||
|
||||
// No alpha in JPG
|
||||
ppf->info.alpha_bits = 0;
|
||||
|
@ -232,7 +232,7 @@ Status DecodeJpeg(const std::vector<uint8_t>& compressed,
|
|||
cinfo.quantize_colors = TRUE;
|
||||
cinfo.desired_number_of_colors = dparams.num_colors;
|
||||
cinfo.two_pass_quantize = static_cast<boolean>(dparams.two_pass_quant);
|
||||
cinfo.dither_mode = (J_DITHER_MODE)dparams.dither_mode;
|
||||
cinfo.dither_mode = static_cast<J_DITHER_MODE>(dparams.dither_mode);
|
||||
}
|
||||
|
||||
jpegli_start_decompress(&cinfo);
|
||||
|
@ -246,7 +246,12 @@ Status DecodeJpeg(const std::vector<uint8_t>& compressed,
|
|||
};
|
||||
ppf->frames.clear();
|
||||
// Allocates the frame buffer.
|
||||
ppf->frames.emplace_back(cinfo.image_width, cinfo.image_height, format);
|
||||
{
|
||||
JXL_ASSIGN_OR_RETURN(
|
||||
PackedFrame frame,
|
||||
PackedFrame::Create(cinfo.image_width, cinfo.image_height, format));
|
||||
ppf->frames.emplace_back(std::move(frame));
|
||||
}
|
||||
const auto& frame = ppf->frames.back();
|
||||
JXL_ASSERT(sizeof(JSAMPLE) * cinfo.out_color_components *
|
||||
cinfo.image_width <=
|
||||
|
|
|
@ -34,7 +34,7 @@ constexpr unsigned char kExifSignature[6] = {0x45, 0x78, 0x69,
|
|||
0x66, 0x00, 0x00};
|
||||
constexpr int kExifMarker = JPEG_APP0 + 1;
|
||||
|
||||
static inline bool IsJPG(const Span<const uint8_t> bytes) {
|
||||
inline bool IsJPG(const Span<const uint8_t> bytes) {
|
||||
if (bytes.size() < 2) return false;
|
||||
if (bytes[0] != 0xFF || bytes[1] != 0xD8) return false;
|
||||
return true;
|
||||
|
@ -270,7 +270,7 @@ Status DecodeImageJPG(const Span<const uint8_t> bytes,
|
|||
ppf->info.bits_per_sample = BITS_IN_JSAMPLE;
|
||||
JXL_ASSERT(BITS_IN_JSAMPLE == 8 || BITS_IN_JSAMPLE == 16);
|
||||
ppf->info.exponent_bits_per_sample = 0;
|
||||
ppf->info.uses_original_profile = true;
|
||||
ppf->info.uses_original_profile = JXL_TRUE;
|
||||
|
||||
// No alpha in JPG
|
||||
ppf->info.alpha_bits = 0;
|
||||
|
@ -283,7 +283,7 @@ Status DecodeImageJPG(const Span<const uint8_t> bytes,
|
|||
cinfo.quantize_colors = TRUE;
|
||||
cinfo.desired_number_of_colors = dparams->num_colors;
|
||||
cinfo.two_pass_quantize = static_cast<boolean>(dparams->two_pass_quant);
|
||||
cinfo.dither_mode = (J_DITHER_MODE)dparams->dither_mode;
|
||||
cinfo.dither_mode = static_cast<J_DITHER_MODE>(dparams->dither_mode);
|
||||
}
|
||||
|
||||
jpeg_start_decompress(&cinfo);
|
||||
|
@ -299,19 +299,25 @@ Status DecodeImageJPG(const Span<const uint8_t> bytes,
|
|||
};
|
||||
ppf->frames.clear();
|
||||
// Allocates the frame buffer.
|
||||
ppf->frames.emplace_back(cinfo.image_width, cinfo.image_height, format);
|
||||
{
|
||||
JXL_ASSIGN_OR_RETURN(
|
||||
PackedFrame frame,
|
||||
PackedFrame::Create(cinfo.image_width, cinfo.image_height, format));
|
||||
ppf->frames.emplace_back(std::move(frame));
|
||||
}
|
||||
const auto& frame = ppf->frames.back();
|
||||
JXL_ASSERT(sizeof(JSAMPLE) * cinfo.out_color_components *
|
||||
cinfo.image_width <=
|
||||
frame.color.stride);
|
||||
|
||||
if (cinfo.quantize_colors) {
|
||||
jxl::msan::UnpoisonMemory(cinfo.colormap, cinfo.out_color_components *
|
||||
sizeof(cinfo.colormap[0]));
|
||||
JSAMPLE** colormap = cinfo.colormap;
|
||||
jxl::msan::UnpoisonMemory(reinterpret_cast<void*>(colormap),
|
||||
cinfo.out_color_components * sizeof(JSAMPLE*));
|
||||
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]));
|
||||
reinterpret_cast<void*>(colormap[c]),
|
||||
cinfo.actual_number_of_colors * sizeof(JSAMPLE));
|
||||
}
|
||||
}
|
||||
for (size_t y = 0; y < cinfo.image_height; ++y) {
|
||||
|
|
|
@ -16,20 +16,23 @@
|
|||
#include "lib/extras/dec/color_description.h"
|
||||
#include "lib/jxl/base/exif.h"
|
||||
#include "lib/jxl/base/printf_macros.h"
|
||||
#include "lib/jxl/base/status.h"
|
||||
|
||||
namespace jxl {
|
||||
namespace extras {
|
||||
namespace {
|
||||
|
||||
struct BoxProcessor {
|
||||
BoxProcessor(JxlDecoder* dec) : dec_(dec) { Reset(); }
|
||||
explicit BoxProcessor(JxlDecoder* dec) : dec_(dec) { Reset(); }
|
||||
|
||||
void InitializeOutput(std::vector<uint8_t>* out) {
|
||||
JXL_ASSERT(out != nullptr);
|
||||
box_data_ = out;
|
||||
AddMoreOutput();
|
||||
}
|
||||
|
||||
bool AddMoreOutput() {
|
||||
JXL_ASSERT(box_data_ != nullptr);
|
||||
Flush();
|
||||
static const size_t kBoxOutputChunkSize = 1 << 16;
|
||||
box_data_->resize(box_data_->size() + kBoxOutputChunkSize);
|
||||
|
@ -126,7 +129,7 @@ bool DecodeImageJXL(const uint8_t* bytes, size_t bytes_size,
|
|||
return false;
|
||||
}
|
||||
|
||||
JxlPixelFormat format;
|
||||
JxlPixelFormat format = {}; // Initialize to calm down clang-tidy.
|
||||
std::vector<JxlPixelFormat> accepted_formats = dparams.accepted_formats;
|
||||
|
||||
JxlColorEncoding color_encoding;
|
||||
|
@ -177,18 +180,18 @@ bool DecodeImageJXL(const uint8_t* bytes, size_t bytes_size,
|
|||
return false;
|
||||
}
|
||||
if (jpeg_bytes == nullptr) {
|
||||
if (JXL_DEC_SUCCESS !=
|
||||
JxlDecoderSetRenderSpotcolors(dec, dparams.render_spotcolors)) {
|
||||
if (JXL_DEC_SUCCESS != JxlDecoderSetRenderSpotcolors(
|
||||
dec, TO_JXL_BOOL(dparams.render_spotcolors))) {
|
||||
fprintf(stderr, "JxlDecoderSetRenderSpotColors failed\n");
|
||||
return false;
|
||||
}
|
||||
if (JXL_DEC_SUCCESS !=
|
||||
JxlDecoderSetKeepOrientation(dec, dparams.keep_orientation)) {
|
||||
if (JXL_DEC_SUCCESS != JxlDecoderSetKeepOrientation(
|
||||
dec, TO_JXL_BOOL(dparams.keep_orientation))) {
|
||||
fprintf(stderr, "JxlDecoderSetKeepOrientation failed\n");
|
||||
return false;
|
||||
}
|
||||
if (JXL_DEC_SUCCESS !=
|
||||
JxlDecoderSetUnpremultiplyAlpha(dec, dparams.unpremultiply_alpha)) {
|
||||
if (JXL_DEC_SUCCESS != JxlDecoderSetUnpremultiplyAlpha(
|
||||
dec, TO_JXL_BOOL(dparams.unpremultiply_alpha))) {
|
||||
fprintf(stderr, "JxlDecoderSetUnpremultiplyAlpha failed\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -267,6 +270,7 @@ bool DecodeImageJXL(const uint8_t* bytes, size_t bytes_size,
|
|||
return false;
|
||||
}
|
||||
} else if (status == JXL_DEC_JPEG_NEED_MORE_OUTPUT) {
|
||||
JXL_ASSERT(jpeg_bytes != nullptr); // Help clang-tidy.
|
||||
// Decoded a chunk to JPEG.
|
||||
size_t used_jpeg_output =
|
||||
jpeg_data_chunk.size() - JxlDecoderReleaseJPEGBuffer(dec);
|
||||
|
@ -309,7 +313,7 @@ bool DecodeImageJXL(const uint8_t* bytes, size_t bytes_size,
|
|||
} else {
|
||||
if (dparams.unpremultiply_alpha) {
|
||||
// Mark in the basic info that alpha was unpremultiplied.
|
||||
ppf->info.alpha_premultiplied = false;
|
||||
ppf->info.alpha_premultiplied = JXL_FALSE;
|
||||
}
|
||||
}
|
||||
bool alpha_found = false;
|
||||
|
@ -327,7 +331,8 @@ bool DecodeImageJXL(const uint8_t* bytes, size_t bytes_size,
|
|||
}
|
||||
std::string name(eci.name_length + 1, 0);
|
||||
if (JXL_DEC_SUCCESS !=
|
||||
JxlDecoderGetExtraChannelName(dec, i, &name[0], name.size())) {
|
||||
JxlDecoderGetExtraChannelName(
|
||||
dec, i, const_cast<char*>(name.data()), name.size())) {
|
||||
fprintf(stderr, "JxlDecoderGetExtraChannelName failed\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -387,14 +392,21 @@ bool DecodeImageJXL(const uint8_t* bytes, size_t bytes_size,
|
|||
}
|
||||
}
|
||||
} else if (status == JXL_DEC_FRAME) {
|
||||
jxl::extras::PackedFrame frame(ppf->info.xsize, ppf->info.ysize, format);
|
||||
auto frame_or = jxl::extras::PackedFrame::Create(ppf->info.xsize,
|
||||
ppf->info.ysize, format);
|
||||
if (!frame_or.status()) {
|
||||
fprintf(stderr, "Failed to create image frame.");
|
||||
return false;
|
||||
}
|
||||
jxl::extras::PackedFrame frame = std::move(frame_or).value();
|
||||
if (JXL_DEC_SUCCESS != JxlDecoderGetFrameHeader(dec, &frame.frame_info)) {
|
||||
fprintf(stderr, "JxlDecoderGetFrameHeader failed\n");
|
||||
return false;
|
||||
}
|
||||
frame.name.resize(frame.frame_info.name_length + 1, 0);
|
||||
if (JXL_DEC_SUCCESS !=
|
||||
JxlDecoderGetFrameName(dec, &frame.name[0], frame.name.size())) {
|
||||
JxlDecoderGetFrameName(dec, const_cast<char*>(frame.name.data()),
|
||||
frame.name.size())) {
|
||||
fprintf(stderr, "JxlDecoderGetFrameName failed\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -425,9 +437,16 @@ bool DecodeImageJXL(const uint8_t* bytes, size_t bytes_size,
|
|||
fprintf(stderr, "JxlDecoderPreviewOutBufferSize failed\n");
|
||||
return false;
|
||||
}
|
||||
auto preview_image_or = jxl::extras::PackedImage::Create(
|
||||
ppf->info.preview.xsize, ppf->info.preview.ysize, format);
|
||||
if (!preview_image_or.status()) {
|
||||
fprintf(stderr, "Failed to create preview image\n");
|
||||
return false;
|
||||
}
|
||||
jxl::extras::PackedImage preview_image =
|
||||
std::move(preview_image_or).value();
|
||||
ppf->preview_frame = std::unique_ptr<jxl::extras::PackedFrame>(
|
||||
new jxl::extras::PackedFrame(ppf->info.preview.xsize,
|
||||
ppf->info.preview.ysize, format));
|
||||
new jxl::extras::PackedFrame(std::move(preview_image)));
|
||||
if (buffer_size != ppf->preview_frame->color.pixels_size) {
|
||||
fprintf(stderr, "Invalid out buffer size %" PRIuS " %" PRIuS "\n",
|
||||
buffer_size, ppf->preview_frame->color.pixels_size);
|
||||
|
@ -494,8 +513,13 @@ bool DecodeImageJXL(const uint8_t* bytes, size_t bytes_size,
|
|||
JxlPixelFormat ec_format = format;
|
||||
ec_format.num_channels = 1;
|
||||
for (auto& eci : ppf->extra_channels_info) {
|
||||
frame.extra_channels.emplace_back(jxl::extras::PackedImage(
|
||||
ppf->info.xsize, ppf->info.ysize, ec_format));
|
||||
auto image = jxl::extras::PackedImage::Create(
|
||||
ppf->info.xsize, ppf->info.ysize, ec_format);
|
||||
if (!image.status()) {
|
||||
fprintf(stderr, "Failed to create extra channel image\n");
|
||||
return false;
|
||||
}
|
||||
frame.extra_channels.emplace_back(std::move(image).value());
|
||||
auto& ec = frame.extra_channels.back();
|
||||
size_t buffer_size;
|
||||
if (JXL_DEC_SUCCESS != JxlDecoderExtraChannelBufferSize(
|
||||
|
|
|
@ -150,7 +150,7 @@ Status DecodeImagePGX(const Span<const uint8_t> bytes,
|
|||
const SizeConstraints* constraints) {
|
||||
Parser parser(bytes);
|
||||
HeaderPGX header = {};
|
||||
const uint8_t* pos;
|
||||
const uint8_t* pos = nullptr;
|
||||
if (!parser.ParseHeader(&header, &pos)) return false;
|
||||
JXL_RETURN_IF_ERROR(
|
||||
VerifyDimensions(constraints, header.xsize, header.ysize));
|
||||
|
@ -165,7 +165,7 @@ Status DecodeImagePGX(const Span<const uint8_t> bytes,
|
|||
// Original data is uint, so exponent_bits_per_sample = 0.
|
||||
ppf->info.bits_per_sample = header.bits_per_sample;
|
||||
ppf->info.exponent_bits_per_sample = 0;
|
||||
ppf->info.uses_original_profile = true;
|
||||
ppf->info.uses_original_profile = JXL_TRUE;
|
||||
|
||||
// No alpha in PGX
|
||||
ppf->info.alpha_bits = 0;
|
||||
|
@ -188,7 +188,12 @@ Status DecodeImagePGX(const Span<const uint8_t> bytes,
|
|||
};
|
||||
ppf->frames.clear();
|
||||
// Allocates the frame buffer.
|
||||
ppf->frames.emplace_back(header.xsize, header.ysize, format);
|
||||
{
|
||||
JXL_ASSIGN_OR_RETURN(
|
||||
PackedFrame frame,
|
||||
PackedFrame::Create(header.xsize, header.ysize, format));
|
||||
ppf->frames.emplace_back(std::move(frame));
|
||||
}
|
||||
const auto& frame = ppf->frames.back();
|
||||
size_t pgx_remaining_size = bytes.data() + bytes.size() - pos;
|
||||
if (pgx_remaining_size < frame.color.pixels_size) {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
|
||||
#include "jxl/encode.h"
|
||||
|
@ -55,8 +56,10 @@ class Parser {
|
|||
case 'f':
|
||||
header->is_gray = true;
|
||||
return ParseHeaderPFM(header, pos);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Exposed for testing
|
||||
|
@ -160,11 +163,12 @@ class Parser {
|
|||
|
||||
Status MatchString(const char* keyword, bool skipws = true) {
|
||||
const uint8_t* ppos = pos_;
|
||||
while (*keyword) {
|
||||
const uint8_t* kw = reinterpret_cast<const uint8_t*>(keyword);
|
||||
while (*kw) {
|
||||
if (ppos >= end_) return JXL_FAILURE("PAM: unexpected end of input");
|
||||
if (*keyword != *ppos) return false;
|
||||
if (*kw != *ppos) return false;
|
||||
ppos++;
|
||||
keyword++;
|
||||
kw++;
|
||||
}
|
||||
pos_ = ppos;
|
||||
if (skipws) {
|
||||
|
@ -387,8 +391,8 @@ StatusOr<ChunkedPNMDecoder> ChunkedPNMDecoder::Init(const char* path) {
|
|||
const size_t num_channels = dec.header_.is_gray ? 1 : 3;
|
||||
const size_t bytes_per_pixel = num_channels * bytes_per_channel;
|
||||
size_t row_size = dec.header_.xsize * bytes_per_pixel;
|
||||
if (header.ysize * row_size + dec.data_start_ < size) {
|
||||
return JXL_FAILURE("Invalid ppm");
|
||||
if (size < header.ysize * row_size + dec.data_start_) {
|
||||
return JXL_FAILURE("PNM file too small");
|
||||
}
|
||||
return dec;
|
||||
}
|
||||
|
@ -495,10 +499,18 @@ Status DecodeImagePNM(const Span<const uint8_t> bytes,
|
|||
};
|
||||
const JxlPixelFormat ec_format{1, format.data_type, format.endianness, 0};
|
||||
ppf->frames.clear();
|
||||
ppf->frames.emplace_back(header.xsize, header.ysize, format);
|
||||
{
|
||||
JXL_ASSIGN_OR_RETURN(
|
||||
PackedFrame frame,
|
||||
PackedFrame::Create(header.xsize, header.ysize, format));
|
||||
ppf->frames.emplace_back(std::move(frame));
|
||||
}
|
||||
auto* frame = &ppf->frames.back();
|
||||
for (size_t i = 0; i < header.ec_types.size(); ++i) {
|
||||
frame->extra_channels.emplace_back(header.xsize, header.ysize, ec_format);
|
||||
JXL_ASSIGN_OR_RETURN(
|
||||
PackedImage ec,
|
||||
PackedImage::Create(header.xsize, header.ysize, ec_format));
|
||||
frame->extra_channels.emplace_back(std::move(ec));
|
||||
}
|
||||
size_t pnm_remaining_size = bytes.data() + bytes.size() - pos;
|
||||
if (pnm_remaining_size < frame->color.pixels_size) {
|
||||
|
@ -533,6 +545,9 @@ Status DecodeImagePNM(const Span<const uint8_t> bytes,
|
|||
}
|
||||
}
|
||||
}
|
||||
if (ppf->info.exponent_bits_per_sample == 0) {
|
||||
ppf->input_bitdepth.type = JXL_BIT_DEPTH_FROM_CODESTREAM;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ class APNGEncoder : public Encoder {
|
|||
std::vector<uint8_t>* bytes) const;
|
||||
};
|
||||
|
||||
static void PngWrite(png_structp png_ptr, png_bytep data, png_size_t length) {
|
||||
void PngWrite(png_structp png_ptr, png_bytep data, png_size_t length) {
|
||||
std::vector<uint8_t>* bytes =
|
||||
static_cast<std::vector<uint8_t>*>(png_get_io_ptr(png_ptr));
|
||||
bytes->insert(bytes->end(), data, data + length);
|
||||
|
@ -137,7 +137,7 @@ class BlobsWriterPNG {
|
|||
std::vector<std::string>* strings) {
|
||||
// Encoding: base16 with newline after 72 chars.
|
||||
const size_t base16_size =
|
||||
2 * bytes.size() + DivCeil(bytes.size(), size_t(36)) + 1;
|
||||
2 * bytes.size() + DivCeil(bytes.size(), static_cast<size_t>(36)) + 1;
|
||||
std::string base16;
|
||||
base16.reserve(base16_size);
|
||||
for (size_t i = 0; i < bytes.size(); ++i) {
|
||||
|
@ -155,7 +155,7 @@ class BlobsWriterPNG {
|
|||
snprintf(header, sizeof(header), "\n%s\n%8" PRIuS, type.c_str(),
|
||||
bytes.size());
|
||||
|
||||
strings->push_back(std::string(key));
|
||||
strings->emplace_back(key);
|
||||
strings->push_back(std::string(header) + base16);
|
||||
return true;
|
||||
}
|
||||
|
@ -303,7 +303,7 @@ Status APNGEncoder::EncodePackedPixelFileToAPNG(
|
|||
out[i] = static_cast<uint8_t>(in[i] * mul + 0.5);
|
||||
}
|
||||
} else {
|
||||
memcpy(&out[0], in, out_size);
|
||||
memcpy(out.data(), in, out_size);
|
||||
}
|
||||
} else if (format.data_type == JXL_TYPE_UINT16) {
|
||||
if (ppf.info.bits_per_sample < 16 ||
|
||||
|
@ -317,20 +317,21 @@ Status APNGEncoder::EncodePackedPixelFileToAPNG(
|
|||
StoreBE16(static_cast<uint32_t>(val * mul + 0.5), p_out);
|
||||
}
|
||||
} else {
|
||||
memcpy(&out[0], in, out_size);
|
||||
memcpy(out.data(), in, out_size);
|
||||
}
|
||||
}
|
||||
png_structp png_ptr;
|
||||
png_infop info_ptr;
|
||||
|
||||
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr,
|
||||
nullptr);
|
||||
|
||||
if (!png_ptr) return JXL_FAILURE("Could not init png encoder");
|
||||
|
||||
info_ptr = png_create_info_struct(png_ptr);
|
||||
if (!info_ptr) return JXL_FAILURE("Could not init png info struct");
|
||||
|
||||
png_set_write_fn(png_ptr, bytes, PngWrite, NULL);
|
||||
png_set_write_fn(png_ptr, bytes, PngWrite, nullptr);
|
||||
png_set_flush(png_ptr, 0);
|
||||
|
||||
int width = xsize;
|
||||
|
@ -406,7 +407,7 @@ Status APNGEncoder::EncodePackedPixelFileToAPNG(
|
|||
|
||||
png_write_flush(png_ptr);
|
||||
const size_t pos = bytes->size();
|
||||
png_write_image(png_ptr, &rows[0]);
|
||||
png_write_image(png_ptr, rows.data());
|
||||
png_write_flush(png_ptr);
|
||||
if (count > 0) {
|
||||
std::vector<uint8_t> fdata(4);
|
||||
|
@ -430,7 +431,7 @@ Status APNGEncoder::EncodePackedPixelFileToAPNG(
|
|||
|
||||
count++;
|
||||
if (count == ppf.frames.size() || !ppf.info.have_animation) {
|
||||
png_write_end(png_ptr, NULL);
|
||||
png_write_end(png_ptr, nullptr);
|
||||
}
|
||||
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
|
|
|
@ -54,7 +54,7 @@ Status Encoder::VerifyBitDepth(JxlDataType data_type, uint32_t bits_per_sample,
|
|||
(bits_per_sample > 16 || exponent_bits > 5))) {
|
||||
return JXL_FAILURE(
|
||||
"Incompatible data_type %d and bit depth %u with exponent bits %u",
|
||||
(int)data_type, bits_per_sample, exponent_bits);
|
||||
static_cast<int>(data_type), bits_per_sample, exponent_bits);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ class Encoder {
|
|||
|
||||
// Any existing data in encoded_image is discarded.
|
||||
virtual Status Encode(const PackedPixelFile& ppf, EncodedImage* encoded_image,
|
||||
ThreadPool* pool = nullptr) const = 0;
|
||||
ThreadPool* pool) const = 0;
|
||||
|
||||
void SetOption(std::string name, std::string value) {
|
||||
options_[std::move(name)] = std::move(value);
|
||||
|
|
|
@ -84,7 +84,7 @@ Status EncodeImageEXR(const PackedImage& image, const JxlBasicInfo& info,
|
|||
const size_t xsize = info.xsize;
|
||||
const size_t ysize = info.ysize;
|
||||
const bool has_alpha = info.alpha_bits > 0;
|
||||
const bool alpha_is_premultiplied = info.alpha_premultiplied;
|
||||
const bool alpha_is_premultiplied = FROM_JXL_BOOL(info.alpha_premultiplied);
|
||||
|
||||
if (info.num_color_channels != 3 ||
|
||||
c_enc.color_space != JXL_COLOR_SPACE_RGB ||
|
||||
|
@ -177,7 +177,7 @@ class EXREncoder : public Encoder {
|
|||
return formats;
|
||||
}
|
||||
Status Encode(const PackedPixelFile& ppf, EncodedImage* encoded_image,
|
||||
ThreadPool* pool = nullptr) const override {
|
||||
ThreadPool* pool) const override {
|
||||
JXL_RETURN_IF_ERROR(VerifyBasicInfo(ppf.info));
|
||||
encoded_image->icc.clear();
|
||||
encoded_image->bitstreams.clear();
|
||||
|
|
|
@ -54,6 +54,10 @@ Status VerifyInput(const PackedPixelFile& ppf) {
|
|||
if (ppf.frames.size() != 1) {
|
||||
return JXL_FAILURE("JPEG input must have exactly one frame.");
|
||||
}
|
||||
if (info.num_color_channels != 1 && info.num_color_channels != 3) {
|
||||
return JXL_FAILURE("Invalid number of color channels %d",
|
||||
info.num_color_channels);
|
||||
}
|
||||
const PackedImage& image = ppf.frames[0].color;
|
||||
JXL_RETURN_IF_ERROR(Encoder::VerifyImageSize(image, info));
|
||||
if (image.format.data_type == JXL_TYPE_FLOAT16) {
|
||||
|
@ -123,12 +127,12 @@ Status WriteAppData(j_compress_ptr cinfo,
|
|||
return true;
|
||||
}
|
||||
|
||||
static constexpr int kICCMarker = 0xe2;
|
||||
constexpr int kICCMarker = 0xe2;
|
||||
constexpr unsigned char kICCSignature[12] = {
|
||||
0x49, 0x43, 0x43, 0x5F, 0x50, 0x52, 0x4F, 0x46, 0x49, 0x4C, 0x45, 0x00};
|
||||
static constexpr uint8_t kUnknownTf = 2;
|
||||
static constexpr unsigned char kCICPTagSignature[4] = {0x63, 0x69, 0x63, 0x70};
|
||||
static constexpr size_t kCICPTagSize = 12;
|
||||
constexpr uint8_t kUnknownTf = 2;
|
||||
constexpr unsigned char kCICPTagSignature[4] = {0x63, 0x69, 0x63, 0x70};
|
||||
constexpr size_t kCICPTagSize = 12;
|
||||
|
||||
bool FindCICPTag(const uint8_t* icc_data, size_t len, bool is_first_chunk,
|
||||
size_t* cicp_offset, size_t* cicp_length, uint8_t* cicp_tag,
|
||||
|
@ -249,32 +253,48 @@ JpegliEndianness ConvertEndianness(JxlEndianness endianness) {
|
|||
}
|
||||
}
|
||||
|
||||
void ToFloatRow(const uint8_t* row_in, JxlPixelFormat format, size_t len,
|
||||
float* row_out) {
|
||||
void ToFloatRow(const uint8_t* row_in, JxlPixelFormat format, size_t xsize,
|
||||
size_t c_out, float* row_out) {
|
||||
bool is_little_endian =
|
||||
(format.endianness == JXL_LITTLE_ENDIAN ||
|
||||
(format.endianness == JXL_NATIVE_ENDIAN && IsLittleEndian()));
|
||||
static constexpr double kMul8 = 1.0 / 255.0;
|
||||
static constexpr double kMul16 = 1.0 / 65535.0;
|
||||
const size_t c_in = format.num_channels;
|
||||
if (format.data_type == JXL_TYPE_UINT8) {
|
||||
for (size_t x = 0; x < len; ++x) {
|
||||
row_out[x] = row_in[x] * kMul8;
|
||||
for (size_t x = 0; x < xsize; ++x) {
|
||||
for (size_t c = 0; c < c_out; ++c) {
|
||||
const size_t ix = c_in * x + c;
|
||||
row_out[c_out * x + c] = row_in[ix] * kMul8;
|
||||
}
|
||||
}
|
||||
} else if (format.data_type == JXL_TYPE_UINT16 && is_little_endian) {
|
||||
for (size_t x = 0; x < len; ++x) {
|
||||
row_out[x] = LoadLE16(&row_in[2 * x]) * kMul16;
|
||||
for (size_t x = 0; x < xsize; ++x) {
|
||||
for (size_t c = 0; c < c_out; ++c) {
|
||||
const size_t ix = c_in * x + c;
|
||||
row_out[c_out * x + c] = LoadLE16(&row_in[2 * ix]) * kMul16;
|
||||
}
|
||||
}
|
||||
} else if (format.data_type == JXL_TYPE_UINT16 && !is_little_endian) {
|
||||
for (size_t x = 0; x < len; ++x) {
|
||||
row_out[x] = LoadBE16(&row_in[2 * x]) * kMul16;
|
||||
for (size_t x = 0; x < xsize; ++x) {
|
||||
for (size_t c = 0; c < c_out; ++c) {
|
||||
const size_t ix = c_in * x + c;
|
||||
row_out[c_out * x + c] = LoadBE16(&row_in[2 * ix]) * kMul16;
|
||||
}
|
||||
}
|
||||
} else if (format.data_type == JXL_TYPE_FLOAT && is_little_endian) {
|
||||
for (size_t x = 0; x < len; ++x) {
|
||||
row_out[x] = LoadLEFloat(&row_in[4 * x]);
|
||||
for (size_t x = 0; x < xsize; ++x) {
|
||||
for (size_t c = 0; c < c_out; ++c) {
|
||||
const size_t ix = c_in * x + c;
|
||||
row_out[c_out * x + c] = LoadLEFloat(&row_in[4 * ix]);
|
||||
}
|
||||
}
|
||||
} else if (format.data_type == JXL_TYPE_FLOAT && !is_little_endian) {
|
||||
for (size_t x = 0; x < len; ++x) {
|
||||
row_out[x] = LoadBEFloat(&row_in[4 * x]);
|
||||
for (size_t x = 0; x < xsize; ++x) {
|
||||
for (size_t c = 0; c < c_out; ++c) {
|
||||
const size_t ix = c_in * x + c;
|
||||
row_out[c_out * x + c] = LoadBEFloat(&row_in[4 * ix]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -353,9 +373,6 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings,
|
|||
ColorSpaceTransform c_transform(*JxlGetDefaultCms());
|
||||
ColorEncoding xyb_encoding;
|
||||
if (jpeg_settings.xyb) {
|
||||
if (ppf.info.num_color_channels != 3) {
|
||||
return JXL_FAILURE("Only RGB input is supported in XYB mode.");
|
||||
}
|
||||
if (HasICCProfile(jpeg_settings.app_data)) {
|
||||
return JXL_FAILURE("APP data ICC profile is not supported in XYB mode.");
|
||||
}
|
||||
|
@ -402,6 +419,8 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings,
|
|||
cinfo.input_components == 1 ? JCS_GRAYSCALE : JCS_RGB;
|
||||
if (jpeg_settings.xyb) {
|
||||
jpegli_set_xyb_mode(&cinfo);
|
||||
cinfo.input_components = 3;
|
||||
cinfo.in_color_space = JCS_RGB;
|
||||
} else if (jpeg_settings.use_std_quant_tables) {
|
||||
jpegli_use_standard_quant_tables(&cinfo);
|
||||
}
|
||||
|
@ -437,7 +456,7 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings,
|
|||
}
|
||||
}
|
||||
jpegli_enable_adaptive_quantization(
|
||||
&cinfo, jpeg_settings.use_adaptive_quantization);
|
||||
&cinfo, TO_JXL_BOOL(jpeg_settings.use_adaptive_quantization));
|
||||
if (jpeg_settings.psnr_target > 0.0) {
|
||||
jpegli_set_psnr(&cinfo, jpeg_settings.psnr_target,
|
||||
jpeg_settings.search_tolerance,
|
||||
|
@ -449,11 +468,11 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings,
|
|||
jpegli_set_distance(&cinfo, jpeg_settings.distance, TRUE);
|
||||
}
|
||||
jpegli_set_progressive_level(&cinfo, jpeg_settings.progressive_level);
|
||||
cinfo.optimize_coding = jpeg_settings.optimize_coding;
|
||||
cinfo.optimize_coding = TO_JXL_BOOL(jpeg_settings.optimize_coding);
|
||||
if (!jpeg_settings.app_data.empty()) {
|
||||
// Make sure jpegli_start_compress() does not write any APP markers.
|
||||
cinfo.write_JFIF_header = false;
|
||||
cinfo.write_Adobe_marker = false;
|
||||
cinfo.write_JFIF_header = JXL_FALSE;
|
||||
cinfo.write_Adobe_marker = JXL_FALSE;
|
||||
}
|
||||
const PackedImage& image = ppf.frames[0].color;
|
||||
if (jpeg_settings.xyb) {
|
||||
|
@ -477,10 +496,10 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings,
|
|||
float* dst_buf = c_transform.BufDst(0);
|
||||
for (size_t y = 0; y < image.ysize; ++y) {
|
||||
// convert to float
|
||||
ToFloatRow(&pixels[y * image.stride], image.format, 3 * image.xsize,
|
||||
src_buf);
|
||||
ToFloatRow(&pixels[y * image.stride], image.format, image.xsize,
|
||||
info.num_color_channels, src_buf);
|
||||
// convert to linear srgb
|
||||
if (!c_transform.Run(0, src_buf, dst_buf)) {
|
||||
if (!c_transform.Run(0, src_buf, dst_buf, image.xsize)) {
|
||||
return false;
|
||||
}
|
||||
// deinterleave channels
|
||||
|
@ -509,9 +528,9 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings,
|
|||
}
|
||||
} else {
|
||||
row_bytes.resize(image.stride);
|
||||
if (cinfo.num_components == (int)image.format.num_channels) {
|
||||
if (cinfo.num_components == static_cast<int>(image.format.num_channels)) {
|
||||
for (size_t y = 0; y < info.ysize; ++y) {
|
||||
memcpy(&row_bytes[0], pixels + y * image.stride, image.stride);
|
||||
memcpy(row_bytes.data(), pixels + y * image.stride, image.stride);
|
||||
JSAMPROW row[] = {row_bytes.data()};
|
||||
jpegli_write_scanlines(&cinfo, row, 1);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "lib/extras/exif.h"
|
||||
#include "lib/jxl/base/common.h"
|
||||
#include "lib/jxl/base/status.h"
|
||||
#include "lib/jxl/sanitizers.h"
|
||||
#if JPEGXL_ENABLE_SJPEG
|
||||
|
@ -50,23 +51,21 @@ enum class JpegEncoder {
|
|||
kSJpeg,
|
||||
};
|
||||
|
||||
#define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0]))
|
||||
|
||||
// Popular jpeg scan scripts
|
||||
// The fields of the individual scans are:
|
||||
// comps_in_scan, component_index[], Ss, Se, Ah, Al
|
||||
static constexpr jpeg_scan_info kScanScript1[] = {
|
||||
constexpr auto kScanScript1 = to_array<jpeg_scan_info>({
|
||||
{1, {0}, 0, 0, 0, 0}, //
|
||||
{1, {1}, 0, 0, 0, 0}, //
|
||||
{1, {2}, 0, 0, 0, 0}, //
|
||||
{1, {0}, 1, 8, 0, 0}, //
|
||||
{1, {0}, 9, 63, 0, 0}, //
|
||||
{1, {1}, 1, 63, 0, 0}, //
|
||||
{1, {2}, 1, 63, 0, 0}, //
|
||||
};
|
||||
static constexpr size_t kNumScans1 = ARRAY_SIZE(kScanScript1);
|
||||
{1, {2}, 1, 63, 0, 0} //
|
||||
});
|
||||
constexpr size_t kNumScans1 = kScanScript1.size();
|
||||
|
||||
static constexpr jpeg_scan_info kScanScript2[] = {
|
||||
constexpr auto kScanScript2 = to_array<jpeg_scan_info>({
|
||||
{1, {0}, 0, 0, 0, 0}, //
|
||||
{1, {1}, 0, 0, 0, 0}, //
|
||||
{1, {2}, 0, 0, 0, 0}, //
|
||||
|
@ -74,11 +73,11 @@ static constexpr jpeg_scan_info kScanScript2[] = {
|
|||
{1, {0}, 3, 63, 0, 1}, //
|
||||
{1, {0}, 1, 63, 1, 0}, //
|
||||
{1, {1}, 1, 63, 0, 0}, //
|
||||
{1, {2}, 1, 63, 0, 0}, //
|
||||
};
|
||||
static constexpr size_t kNumScans2 = ARRAY_SIZE(kScanScript2);
|
||||
{1, {2}, 1, 63, 0, 0} //
|
||||
});
|
||||
constexpr size_t kNumScans2 = kScanScript2.size();
|
||||
|
||||
static constexpr jpeg_scan_info kScanScript3[] = {
|
||||
constexpr auto kScanScript3 = to_array<jpeg_scan_info>({
|
||||
{1, {0}, 0, 0, 0, 0}, //
|
||||
{1, {1}, 0, 0, 0, 0}, //
|
||||
{1, {2}, 0, 0, 0, 0}, //
|
||||
|
@ -86,11 +85,11 @@ static constexpr jpeg_scan_info kScanScript3[] = {
|
|||
{1, {0}, 1, 63, 2, 1}, //
|
||||
{1, {0}, 1, 63, 1, 0}, //
|
||||
{1, {1}, 1, 63, 0, 0}, //
|
||||
{1, {2}, 1, 63, 0, 0}, //
|
||||
};
|
||||
static constexpr size_t kNumScans3 = ARRAY_SIZE(kScanScript3);
|
||||
{1, {2}, 1, 63, 0, 0} //
|
||||
});
|
||||
constexpr size_t kNumScans3 = kScanScript3.size();
|
||||
|
||||
static constexpr jpeg_scan_info kScanScript4[] = {
|
||||
constexpr auto kScanScript4 = to_array<jpeg_scan_info>({
|
||||
{3, {0, 1, 2}, 0, 0, 0, 1}, //
|
||||
{1, {0}, 1, 5, 0, 2}, //
|
||||
{1, {2}, 1, 63, 0, 1}, //
|
||||
|
@ -100,11 +99,11 @@ static constexpr jpeg_scan_info kScanScript4[] = {
|
|||
{3, {0, 1, 2}, 0, 0, 1, 0}, //
|
||||
{1, {2}, 1, 63, 1, 0}, //
|
||||
{1, {1}, 1, 63, 1, 0}, //
|
||||
{1, {0}, 1, 63, 1, 0}, //
|
||||
};
|
||||
static constexpr size_t kNumScans4 = ARRAY_SIZE(kScanScript4);
|
||||
{1, {0}, 1, 63, 1, 0} //
|
||||
});
|
||||
constexpr size_t kNumScans4 = kScanScript4.size();
|
||||
|
||||
static constexpr jpeg_scan_info kScanScript5[] = {
|
||||
constexpr auto kScanScript5 = to_array<jpeg_scan_info>({
|
||||
{3, {0, 1, 2}, 0, 0, 0, 1}, //
|
||||
{1, {0}, 1, 5, 0, 2}, //
|
||||
{1, {1}, 1, 5, 0, 2}, //
|
||||
|
@ -118,12 +117,12 @@ static constexpr jpeg_scan_info kScanScript5[] = {
|
|||
{3, {0, 1, 2}, 0, 0, 1, 0}, //
|
||||
{1, {0}, 1, 63, 1, 0}, //
|
||||
{1, {1}, 1, 63, 1, 0}, //
|
||||
{1, {2}, 1, 63, 1, 0}, //
|
||||
};
|
||||
static constexpr size_t kNumScans5 = ARRAY_SIZE(kScanScript5);
|
||||
{1, {2}, 1, 63, 1, 0} //
|
||||
});
|
||||
constexpr size_t kNumScans5 = kScanScript5.size();
|
||||
|
||||
// default progressive mode of jpegli
|
||||
static constexpr jpeg_scan_info kScanScript6[] = {
|
||||
constexpr auto kScanScript6 = to_array<jpeg_scan_info>({
|
||||
{3, {0, 1, 2}, 0, 0, 0, 0}, //
|
||||
{1, {0}, 1, 2, 0, 0}, //
|
||||
{1, {1}, 1, 2, 0, 0}, //
|
||||
|
@ -137,8 +136,8 @@ static constexpr jpeg_scan_info kScanScript6[] = {
|
|||
{1, {0}, 3, 63, 1, 0}, //
|
||||
{1, {1}, 3, 63, 1, 0}, //
|
||||
{1, {2}, 3, 63, 1, 0}, //
|
||||
};
|
||||
static constexpr size_t kNumScans6 = ARRAY_SIZE(kScanScript6);
|
||||
});
|
||||
constexpr size_t kNumScans6 = kScanScript6.size();
|
||||
|
||||
// Adapt RGB scan info to grayscale jpegs.
|
||||
void FilterScanComponents(const jpeg_compress_struct* cinfo,
|
||||
|
@ -163,12 +162,12 @@ Status SetJpegProgression(int progressive_id,
|
|||
jpeg_simple_progression(cinfo);
|
||||
return true;
|
||||
}
|
||||
constexpr const jpeg_scan_info* kScanScripts[] = {kScanScript1, kScanScript2,
|
||||
kScanScript3, kScanScript4,
|
||||
kScanScript5, kScanScript6};
|
||||
constexpr size_t kNumScans[] = {kNumScans1, kNumScans2, kNumScans3,
|
||||
kNumScans4, kNumScans5, kNumScans6};
|
||||
if (progressive_id > static_cast<int>(ARRAY_SIZE(kNumScans))) {
|
||||
const jpeg_scan_info* kScanScripts[] = {
|
||||
kScanScript1.data(), kScanScript2.data(), kScanScript3.data(),
|
||||
kScanScript4.data(), kScanScript5.data(), kScanScript6.data()};
|
||||
constexpr auto kNumScans = to_array<size_t>(
|
||||
{kNumScans1, kNumScans2, kNumScans3, kNumScans4, kNumScans5, kNumScans6});
|
||||
if (progressive_id > static_cast<int>(kNumScans.size())) {
|
||||
return JXL_FAILURE("Unknown jpeg scan script id %d", progressive_id);
|
||||
}
|
||||
const jpeg_scan_info* scan_script = kScanScripts[progressive_id - 1];
|
||||
|
@ -178,7 +177,7 @@ Status SetJpegProgression(int progressive_id,
|
|||
jpeg_scan_info scan_info = scan_script[i];
|
||||
FilterScanComponents(cinfo, &scan_info);
|
||||
if (scan_info.comps_in_scan > 0) {
|
||||
scan_infos->emplace_back(std::move(scan_info));
|
||||
scan_infos->emplace_back(scan_info);
|
||||
}
|
||||
}
|
||||
cinfo->scan_info = scan_infos->data();
|
||||
|
@ -217,8 +216,8 @@ void WriteExif(jpeg_compress_struct* const cinfo,
|
|||
for (const unsigned char c : kExifSignature) {
|
||||
jpeg_write_m_byte(cinfo, c);
|
||||
}
|
||||
for (size_t i = 0; i < exif.size(); ++i) {
|
||||
jpeg_write_m_byte(cinfo, exif[i]);
|
||||
for (uint8_t c : exif) {
|
||||
jpeg_write_m_byte(cinfo, c);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -310,10 +309,10 @@ Status EncodeWithLibJpeg(const PackedImage& image, const JxlBasicInfo& info,
|
|||
|
||||
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 &&
|
||||
if (cinfo.num_components == static_cast<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);
|
||||
memcpy(row_bytes.data(), pixels + y * image.stride, image.stride);
|
||||
JSAMPROW row[] = {row_bytes.data()};
|
||||
jpeg_write_scanlines(&cinfo, row, 1);
|
||||
}
|
||||
|
@ -401,7 +400,7 @@ struct MySearchHook : public sjpeg::SearchHook {
|
|||
}
|
||||
bool Update(float result) override {
|
||||
value = result;
|
||||
if (fabs(value - target) < tolerance * target) {
|
||||
if (std::fabs(value - target) < tolerance * target) {
|
||||
return true;
|
||||
}
|
||||
if (value > target) {
|
||||
|
@ -420,9 +419,9 @@ struct MySearchHook : public sjpeg::SearchHook {
|
|||
} else {
|
||||
q = (qmin + qmax) / 2.;
|
||||
}
|
||||
return (pass > 0 && fabs(q - last_q) < q_precision);
|
||||
return (pass > 0 && std::fabs(q - last_q) < q_precision);
|
||||
}
|
||||
~MySearchHook() override {}
|
||||
~MySearchHook() override = default;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -539,7 +538,7 @@ class JPEGEncoder : public Encoder {
|
|||
return formats;
|
||||
}
|
||||
Status Encode(const PackedPixelFile& ppf, EncodedImage* encoded_image,
|
||||
ThreadPool* pool = nullptr) const override {
|
||||
ThreadPool* pool) const override {
|
||||
JXL_RETURN_IF_ERROR(VerifyBasicInfo(ppf.info));
|
||||
JpegEncoder jpeg_encoder = JpegEncoder::kLibJpeg;
|
||||
JpegParams params;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <jxl/encode.h>
|
||||
#include <jxl/encode_cxx.h>
|
||||
#include <jxl/types.h>
|
||||
|
||||
#include "lib/jxl/base/exif.h"
|
||||
|
||||
|
@ -132,7 +133,7 @@ bool EncodeImageJXL(const JXLCompressParams& params, const PackedPixelFile& ppf,
|
|||
return false;
|
||||
}
|
||||
|
||||
auto settings = JxlEncoderFrameSettingsCreate(enc, nullptr);
|
||||
auto* settings = JxlEncoderFrameSettingsCreate(enc, nullptr);
|
||||
size_t option_idx = 0;
|
||||
if (!SetFrameOptions(params.options, 0, &option_idx, settings)) {
|
||||
return false;
|
||||
|
@ -150,10 +151,11 @@ bool EncodeImageJXL(const JXLCompressParams& params, const PackedPixelFile& ppf,
|
|||
JxlEncoderCollectStats(settings, params.stats);
|
||||
}
|
||||
|
||||
bool has_jpeg_bytes = (jpeg_bytes != nullptr);
|
||||
bool use_boxes = !ppf.metadata.exif.empty() || !ppf.metadata.xmp.empty() ||
|
||||
!ppf.metadata.jumbf.empty() || !ppf.metadata.iptc.empty();
|
||||
bool use_container = params.use_container || use_boxes ||
|
||||
(jpeg_bytes && params.jpeg_store_metadata);
|
||||
(has_jpeg_bytes && params.jpeg_store_metadata);
|
||||
|
||||
if (JXL_ENC_SUCCESS !=
|
||||
JxlEncoderUseContainer(enc, static_cast<int>(use_container))) {
|
||||
|
@ -161,7 +163,7 @@ bool EncodeImageJXL(const JXLCompressParams& params, const PackedPixelFile& ppf,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (jpeg_bytes) {
|
||||
if (has_jpeg_bytes) {
|
||||
if (params.jpeg_store_metadata &&
|
||||
JXL_ENC_SUCCESS != JxlEncoderStoreJPEGMetadata(enc, JXL_TRUE)) {
|
||||
fprintf(stderr, "Storing JPEG metadata failed.\n");
|
||||
|
@ -220,8 +222,8 @@ bool EncodeImageJXL(const JXLCompressParams& params, const PackedPixelFile& ppf,
|
|||
basic_info.num_extra_channels =
|
||||
std::max<uint32_t>(num_alpha_channels, ppf.info.num_extra_channels);
|
||||
basic_info.num_color_channels = ppf.info.num_color_channels;
|
||||
const bool lossless = params.distance == 0;
|
||||
basic_info.uses_original_profile = lossless;
|
||||
const bool lossless = (params.distance == 0);
|
||||
basic_info.uses_original_profile = TO_JXL_BOOL(lossless);
|
||||
if (params.override_bitdepth != 0) {
|
||||
basic_info.bits_per_sample = params.override_bitdepth;
|
||||
basic_info.exponent_bits_per_sample =
|
||||
|
@ -243,7 +245,7 @@ bool EncodeImageJXL(const JXLCompressParams& params, const PackedPixelFile& ppf,
|
|||
return false;
|
||||
}
|
||||
if (JXL_ENC_SUCCESS !=
|
||||
JxlEncoderSetFrameBitDepth(settings, ¶ms.input_bitdepth)) {
|
||||
JxlEncoderSetFrameBitDepth(settings, &ppf.input_bitdepth)) {
|
||||
fprintf(stderr, "JxlEncoderSetFrameBitDepth() failed.\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -294,14 +296,15 @@ bool EncodeImageJXL(const JXLCompressParams& params, const PackedPixelFile& ppf,
|
|||
{"jumb", ppf.metadata.jumbf},
|
||||
{"xml ", ppf.metadata.iptc},
|
||||
};
|
||||
for (size_t i = 0; i < sizeof boxes / sizeof *boxes; ++i) {
|
||||
const BoxInfo& box = boxes[i];
|
||||
if (!box.bytes.empty() &&
|
||||
JXL_ENC_SUCCESS != JxlEncoderAddBox(enc, box.type, box.bytes.data(),
|
||||
box.bytes.size(),
|
||||
params.compress_boxes)) {
|
||||
fprintf(stderr, "JxlEncoderAddBox() failed (%s).\n", box.type);
|
||||
return false;
|
||||
for (auto box : boxes) {
|
||||
if (!box.bytes.empty()) {
|
||||
if (JXL_ENC_SUCCESS !=
|
||||
JxlEncoderAddBox(enc, box.type, box.bytes.data(),
|
||||
box.bytes.size(),
|
||||
TO_JXL_BOOL(params.compress_boxes))) {
|
||||
fprintf(stderr, "JxlEncoderAddBox() failed (%s).\n", box.type);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
JxlEncoderCloseBoxes(enc);
|
||||
|
@ -346,7 +349,7 @@ bool EncodeImageJXL(const JXLCompressParams& params, const PackedPixelFile& ppf,
|
|||
}
|
||||
const bool last_frame = fi + 1 == ppf.chunked_frames.size();
|
||||
if (JXL_ENC_SUCCESS !=
|
||||
JxlEncoderAddChunkedFrame(settings, last_frame,
|
||||
JxlEncoderAddChunkedFrame(settings, TO_JXL_BOOL(last_frame),
|
||||
chunked_frame.GetInputSource())) {
|
||||
fprintf(stderr, "JxlEncoderAddChunkedFrame() failed.\n");
|
||||
return false;
|
||||
|
|
|
@ -57,8 +57,6 @@ struct JXLCompressParams {
|
|||
size_t override_bitdepth = 0;
|
||||
int32_t codestream_level = -1;
|
||||
int32_t premultiply = -1;
|
||||
// Override input buffer interpretation.
|
||||
JxlBitDepth input_bitdepth = {JXL_BIT_DEPTH_FROM_PIXEL_FORMAT, 0, 0};
|
||||
// If runner_opaque is set, the decoder uses this parallel runner.
|
||||
JxlParallelRunner runner = JxlThreadParallelRunner;
|
||||
void* runner_opaque = nullptr;
|
||||
|
@ -69,10 +67,10 @@ struct JXLCompressParams {
|
|||
bool allow_expert_options = false;
|
||||
|
||||
void AddOption(JxlEncoderFrameSettingId id, int64_t val) {
|
||||
options.emplace_back(JXLOption(id, val, 0));
|
||||
options.emplace_back(id, val, 0);
|
||||
}
|
||||
void AddFloatOption(JxlEncoderFrameSettingId id, float val) {
|
||||
options.emplace_back(JXLOption(id, val, 0));
|
||||
options.emplace_back(id, val, 0);
|
||||
}
|
||||
bool HasOutputProcessor() const {
|
||||
return (output_processor.get_buffer != nullptr &&
|
||||
|
|
|
@ -7,11 +7,13 @@
|
|||
|
||||
#include <jxl/types.h>
|
||||
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "lib/extras/packed_image.h"
|
||||
#include "lib/jxl/base/common.h"
|
||||
|
||||
namespace jxl {
|
||||
namespace extras {
|
||||
|
@ -52,14 +54,17 @@ class JSONDict : public JSONField {
|
|||
static_assert(std::is_convertible<T*, JSONField*>::value,
|
||||
"T must be a JSONField");
|
||||
T* ret = new T();
|
||||
values_.emplace_back(
|
||||
key, std::unique_ptr<JSONField>(static_cast<JSONField*>(ret)));
|
||||
JSONField* field = static_cast<JSONField*>(ret);
|
||||
auto handle = std::unique_ptr<JSONField>(field);
|
||||
values_.emplace_back(key, std::move(handle));
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Add(const std::string& key, const T& value) {
|
||||
values_.emplace_back(key, std::unique_ptr<JSONField>(new JSONValue(value)));
|
||||
JSONField* field = static_cast<JSONField*>(new JSONValue(value));
|
||||
auto handle = std::unique_ptr<JSONField>(field);
|
||||
values_.emplace_back(key, std::move(handle));
|
||||
}
|
||||
|
||||
void Write(std::ostream& o, uint32_t indent) const override {
|
||||
|
@ -71,11 +76,11 @@ class JSONDict : public JSONField {
|
|||
o << ",";
|
||||
}
|
||||
is_first = false;
|
||||
o << std::endl << indent_str << " \"" << key_value.first << "\": ";
|
||||
o << "\n" << indent_str << " \"" << key_value.first << "\": ";
|
||||
key_value.second->Write(o, indent + 2);
|
||||
}
|
||||
if (!values_.empty()) {
|
||||
o << std::endl << indent_str;
|
||||
o << "\n" << indent_str;
|
||||
}
|
||||
o << "}";
|
||||
}
|
||||
|
@ -112,11 +117,11 @@ class JSONArray : public JSONField {
|
|||
o << ",";
|
||||
}
|
||||
is_first = false;
|
||||
o << std::endl << indent_str << " ";
|
||||
o << "\n" << indent_str << " ";
|
||||
value->Write(o, indent + 2);
|
||||
}
|
||||
if (!values_.empty()) {
|
||||
o << std::endl << indent_str;
|
||||
o << "\n" << indent_str;
|
||||
}
|
||||
o << "]";
|
||||
}
|
||||
|
@ -160,13 +165,13 @@ void GenerateMetadata(const PackedPixelFile& ppf, std::vector<uint8_t>* out) {
|
|||
}
|
||||
|
||||
{
|
||||
auto ectype = meta.AddEmpty<JSONArray>("extra_channel_type");
|
||||
auto bps = meta.AddEmpty<JSONArray>("bits_per_sample");
|
||||
auto ebps = meta.AddEmpty<JSONArray>("exp_bits_per_sample");
|
||||
auto* ectype = meta.AddEmpty<JSONArray>("extra_channel_type");
|
||||
auto* bps = meta.AddEmpty<JSONArray>("bits_per_sample");
|
||||
auto* ebps = meta.AddEmpty<JSONArray>("exp_bits_per_sample");
|
||||
bps->Add(ppf.info.bits_per_sample);
|
||||
ebps->Add(ppf.info.exponent_bits_per_sample);
|
||||
for (size_t i = 0; i < ppf.extra_channels_info.size(); i++) {
|
||||
switch (ppf.extra_channels_info[i].ec_info.type) {
|
||||
for (const auto& eci : ppf.extra_channels_info) {
|
||||
switch (eci.ec_info.type) {
|
||||
case JXL_CHANNEL_ALPHA: {
|
||||
ectype->Add(std::string("Alpha"));
|
||||
break;
|
||||
|
@ -200,8 +205,8 @@ void GenerateMetadata(const PackedPixelFile& ppf, std::vector<uint8_t>* out) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
bps->Add(ppf.extra_channels_info[i].ec_info.bits_per_sample);
|
||||
ebps->Add(ppf.extra_channels_info[i].ec_info.exponent_bits_per_sample);
|
||||
bps->Add(eci.ec_info.bits_per_sample);
|
||||
ebps->Add(eci.ec_info.exponent_bits_per_sample);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -282,7 +287,7 @@ bool WriteNPYArray(const PackedPixelFile& ppf, std::vector<uint8_t>* out) {
|
|||
class NumPyEncoder : public Encoder {
|
||||
public:
|
||||
Status Encode(const PackedPixelFile& ppf, EncodedImage* encoded_image,
|
||||
ThreadPool* pool = nullptr) const override {
|
||||
ThreadPool* pool) const override {
|
||||
JXL_RETURN_IF_ERROR(VerifyBasicInfo(ppf.info));
|
||||
GenerateMetadata(ppf, &encoded_image->metadata);
|
||||
encoded_image->bitstreams.emplace_back();
|
||||
|
|
|
@ -60,7 +60,7 @@ Status EncodeImagePGX(const PackedFrame& frame, const JxlBasicInfo& info,
|
|||
std::vector<uint8_t> pixels(num_samples * bytes_per_sample);
|
||||
|
||||
if (format.data_type == JXL_TYPE_UINT8) {
|
||||
memcpy(&pixels[0], in, num_samples * bytes_per_sample);
|
||||
memcpy(pixels.data(), in, num_samples * bytes_per_sample);
|
||||
} else if (format.data_type == JXL_TYPE_UINT16) {
|
||||
if (format.endianness != JXL_BIG_ENDIAN) {
|
||||
const uint8_t* p_in = in;
|
||||
|
@ -69,7 +69,7 @@ Status EncodeImagePGX(const PackedFrame& frame, const JxlBasicInfo& info,
|
|||
StoreBE16(LoadLE16(p_in), p_out);
|
||||
}
|
||||
} else {
|
||||
memcpy(&pixels[0], in, num_samples * bytes_per_sample);
|
||||
memcpy(pixels.data(), in, num_samples * bytes_per_sample);
|
||||
}
|
||||
} else {
|
||||
return JXL_FAILURE("Unsupported pixel data type");
|
||||
|
|
|
@ -31,7 +31,7 @@ constexpr size_t kMaxHeaderSize = 200;
|
|||
class BasePNMEncoder : public Encoder {
|
||||
public:
|
||||
Status Encode(const PackedPixelFile& ppf, EncodedImage* encoded_image,
|
||||
ThreadPool* pool = nullptr) const override {
|
||||
ThreadPool* pool) const override {
|
||||
JXL_RETURN_IF_ERROR(VerifyBasicInfo(ppf.info));
|
||||
if (!ppf.metadata.exif.empty() || !ppf.metadata.iptc.empty() ||
|
||||
!ppf.metadata.jumbf.empty() || !ppf.metadata.xmp.empty()) {
|
||||
|
|
|
@ -85,7 +85,7 @@ Status EncodeWithLibjpeg(const PackedPixelFile& ppf, int quality,
|
|||
std::unique_ptr<Encoder> encoder = GetJPEGEncoder();
|
||||
encoder->SetOption("q", std::to_string(quality));
|
||||
EncodedImage encoded;
|
||||
JXL_RETURN_IF_ERROR(encoder->Encode(ppf, &encoded));
|
||||
JXL_RETURN_IF_ERROR(encoder->Encode(ppf, &encoded, nullptr));
|
||||
JXL_RETURN_IF_ERROR(!encoded.bitstreams.empty());
|
||||
*compressed = std::move(encoded.bitstreams[0]);
|
||||
return true;
|
||||
|
@ -156,8 +156,8 @@ TEST(JpegliTest, JpegliXYBEncodeTest) {
|
|||
|
||||
PackedPixelFile ppf_out;
|
||||
ASSERT_TRUE(DecodeWithLibjpeg(compressed, &ppf_out));
|
||||
EXPECT_THAT(BitsPerPixel(ppf_in, compressed), IsSlightlyBelow(1.45f));
|
||||
EXPECT_THAT(ButteraugliDistance(ppf_in, ppf_out), IsSlightlyBelow(1.32f));
|
||||
EXPECT_SLIGHTLY_BELOW(BitsPerPixel(ppf_in, compressed), 1.45f);
|
||||
EXPECT_SLIGHTLY_BELOW(ButteraugliDistance(ppf_in, ppf_out), 1.32f);
|
||||
}
|
||||
|
||||
TEST(JpegliTest, JpegliDecodeTestLargeSmoothArea) {
|
||||
|
@ -205,8 +205,8 @@ TEST(JpegliTest, JpegliYUVEncodeTest) {
|
|||
|
||||
PackedPixelFile ppf_out;
|
||||
ASSERT_TRUE(DecodeWithLibjpeg(compressed, &ppf_out));
|
||||
EXPECT_THAT(BitsPerPixel(ppf_in, compressed), IsSlightlyBelow(1.7f));
|
||||
EXPECT_THAT(ButteraugliDistance(ppf_in, ppf_out), IsSlightlyBelow(1.32f));
|
||||
EXPECT_SLIGHTLY_BELOW(BitsPerPixel(ppf_in, compressed), 1.7f);
|
||||
EXPECT_SLIGHTLY_BELOW(ButteraugliDistance(ppf_in, ppf_out), 1.32f);
|
||||
}
|
||||
|
||||
TEST(JpegliTest, JpegliYUVChromaSubsamplingEncodeTest) {
|
||||
|
@ -247,8 +247,8 @@ TEST(JpegliTest, JpegliYUVEncodeTestNoAq) {
|
|||
|
||||
PackedPixelFile ppf_out;
|
||||
ASSERT_TRUE(DecodeWithLibjpeg(compressed, &ppf_out));
|
||||
EXPECT_THAT(BitsPerPixel(ppf_in, compressed), IsSlightlyBelow(1.85f));
|
||||
EXPECT_THAT(ButteraugliDistance(ppf_in, ppf_out), IsSlightlyBelow(1.25f));
|
||||
EXPECT_SLIGHTLY_BELOW(BitsPerPixel(ppf_in, compressed), 1.85f);
|
||||
EXPECT_SLIGHTLY_BELOW(ButteraugliDistance(ppf_in, ppf_out), 1.25f);
|
||||
}
|
||||
|
||||
TEST(JpegliTest, JpegliHDRRoundtripTest) {
|
||||
|
@ -267,8 +267,8 @@ TEST(JpegliTest, JpegliHDRRoundtripTest) {
|
|||
JpegDecompressParams dparams;
|
||||
dparams.output_data_type = JXL_TYPE_UINT16;
|
||||
ASSERT_TRUE(DecodeJpeg(compressed, dparams, nullptr, &ppf_out));
|
||||
EXPECT_THAT(BitsPerPixel(ppf_in, compressed), IsSlightlyBelow(2.95f));
|
||||
EXPECT_THAT(ButteraugliDistance(ppf_in, ppf_out), IsSlightlyBelow(1.05f));
|
||||
EXPECT_SLIGHTLY_BELOW(BitsPerPixel(ppf_in, compressed), 2.95f);
|
||||
EXPECT_SLIGHTLY_BELOW(ButteraugliDistance(ppf_in, ppf_out), 1.05f);
|
||||
}
|
||||
|
||||
TEST(JpegliTest, JpegliSetAppData) {
|
||||
|
|
|
@ -55,7 +55,7 @@ struct MemoryMappedFileImpl {
|
|||
|
||||
} // namespace jxl
|
||||
|
||||
#elif __WIN32__
|
||||
#elif defined(_WIN32)
|
||||
#include <string.h>
|
||||
#include <windows.h>
|
||||
|
||||
|
|
|
@ -37,11 +37,18 @@ namespace extras {
|
|||
// Class representing an interleaved image with a bunch of channels.
|
||||
class PackedImage {
|
||||
public:
|
||||
PackedImage(size_t xsize, size_t ysize, const JxlPixelFormat& format)
|
||||
: PackedImage(xsize, ysize, format, CalcStride(format, xsize)) {}
|
||||
static StatusOr<PackedImage> Create(size_t xsize, size_t ysize,
|
||||
const JxlPixelFormat& format) {
|
||||
PackedImage image(xsize, ysize, format, CalcStride(format, xsize));
|
||||
if (!image.pixels()) {
|
||||
// TODO(szabadka): use specialized OOM error code
|
||||
return JXL_FAILURE("Failed to allocate memory for image");
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
PackedImage Copy() const {
|
||||
PackedImage copy(xsize, ysize, format);
|
||||
PackedImage copy(xsize, ysize, format, CalcStride(format, xsize));
|
||||
memcpy(reinterpret_cast<uint8_t*>(copy.pixels()),
|
||||
reinterpret_cast<const uint8_t*>(pixels()), pixels_size);
|
||||
return copy;
|
||||
|
@ -108,7 +115,7 @@ class PackedImage {
|
|||
}
|
||||
}
|
||||
|
||||
void SetPixelValue(size_t y, size_t x, size_t c, float val) {
|
||||
void SetPixelValue(size_t y, size_t x, size_t c, float val) const {
|
||||
uint8_t* data = pixels(y, x, c);
|
||||
switch (format.data_type) {
|
||||
case JXL_TYPE_UINT8:
|
||||
|
@ -169,17 +176,25 @@ class PackedImage {
|
|||
// as all other frames in the same image.
|
||||
class PackedFrame {
|
||||
public:
|
||||
template <typename... Args>
|
||||
explicit PackedFrame(Args&&... args) : color(std::forward<Args>(args)...) {}
|
||||
explicit PackedFrame(PackedImage&& image) : color(std::move(image)) {}
|
||||
|
||||
PackedFrame Copy() const {
|
||||
PackedFrame copy(color.xsize, color.ysize, color.format);
|
||||
static StatusOr<PackedFrame> Create(size_t xsize, size_t ysize,
|
||||
const JxlPixelFormat& format) {
|
||||
JXL_ASSIGN_OR_RETURN(PackedImage image,
|
||||
PackedImage::Create(xsize, ysize, format));
|
||||
PackedFrame frame(std::move(image));
|
||||
return frame;
|
||||
}
|
||||
|
||||
StatusOr<PackedFrame> Copy() const {
|
||||
JXL_ASSIGN_OR_RETURN(
|
||||
PackedFrame copy,
|
||||
PackedFrame::Create(color.xsize, color.ysize, color.format));
|
||||
copy.frame_info = frame_info;
|
||||
copy.name = name;
|
||||
copy.color = color.Copy();
|
||||
for (size_t i = 0; i < extra_channels.size(); ++i) {
|
||||
PackedImage ec = extra_channels[i].Copy();
|
||||
copy.extra_channels.emplace_back(std::move(ec));
|
||||
for (const auto& ec : extra_channels) {
|
||||
copy.extra_channels.emplace_back(ec.Copy());
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
@ -262,6 +277,8 @@ class PackedPixelFile {
|
|||
// The icc profile of the original image.
|
||||
std::vector<uint8_t> orig_icc;
|
||||
|
||||
JxlBitDepth input_bitdepth = {JXL_BIT_DEPTH_FROM_PIXEL_FORMAT, 0, 0};
|
||||
|
||||
std::unique_ptr<PackedFrame> preview_frame;
|
||||
std::vector<PackedFrame> frames;
|
||||
mutable std::vector<ChunkedPackedFrame> chunked_frames;
|
||||
|
|
|
@ -22,15 +22,15 @@ namespace jxl {
|
|||
namespace extras {
|
||||
|
||||
Status ConvertPackedFrameToImageBundle(const JxlBasicInfo& info,
|
||||
const JxlBitDepth& input_bitdepth,
|
||||
const PackedFrame& frame,
|
||||
const CodecInOut& io, ThreadPool* pool,
|
||||
ImageBundle* bundle) {
|
||||
JXL_ASSERT(frame.color.pixels() != nullptr);
|
||||
const bool float_in = frame.color.format.data_type == JXL_TYPE_FLOAT16 ||
|
||||
frame.color.format.data_type == JXL_TYPE_FLOAT;
|
||||
size_t frame_bits_per_sample =
|
||||
float_in ? PackedImage::BitsPerChannel(frame.color.format.data_type)
|
||||
: info.bits_per_sample;
|
||||
input_bitdepth.type == JXL_BIT_DEPTH_FROM_PIXEL_FORMAT
|
||||
? PackedImage::BitsPerChannel(frame.color.format.data_type)
|
||||
: info.bits_per_sample;
|
||||
JXL_ASSERT(frame_bits_per_sample != 0);
|
||||
// It is ok for the frame.color.format.num_channels to not match the
|
||||
// number of channels on the image.
|
||||
|
@ -98,17 +98,17 @@ Status ConvertPackedPixelFileToCodecInOut(const PackedPixelFile& ppf,
|
|||
ppf.info.exponent_bits_per_sample == 0 && ppf.info.bits_per_sample <= 12;
|
||||
|
||||
io->metadata.m.SetAlphaBits(ppf.info.alpha_bits,
|
||||
ppf.info.alpha_premultiplied);
|
||||
FROM_JXL_BOOL(ppf.info.alpha_premultiplied));
|
||||
ExtraChannelInfo* alpha = io->metadata.m.Find(ExtraChannel::kAlpha);
|
||||
if (alpha) alpha->bit_depth = io->metadata.m.bit_depth;
|
||||
|
||||
io->metadata.m.xyb_encoded = !ppf.info.uses_original_profile;
|
||||
io->metadata.m.xyb_encoded = !FROM_JXL_BOOL(ppf.info.uses_original_profile);
|
||||
JXL_ASSERT(ppf.info.orientation > 0 && ppf.info.orientation <= 8);
|
||||
io->metadata.m.orientation = ppf.info.orientation;
|
||||
|
||||
// Convert animation metadata
|
||||
JXL_ASSERT(ppf.frames.size() == 1 || ppf.info.have_animation);
|
||||
io->metadata.m.have_animation = ppf.info.have_animation;
|
||||
io->metadata.m.have_animation = FROM_JXL_BOOL(ppf.info.have_animation);
|
||||
io->metadata.m.animation.tps_numerator = ppf.info.animation.tps_numerator;
|
||||
io->metadata.m.animation.tps_denominator = ppf.info.animation.tps_denominator;
|
||||
io->metadata.m.animation.num_loops = ppf.info.animation.num_loops;
|
||||
|
@ -171,15 +171,16 @@ Status ConvertPackedPixelFileToCodecInOut(const PackedPixelFile& ppf,
|
|||
JXL_RETURN_IF_ERROR(
|
||||
io->metadata.m.preview_size.Set(preview_xsize, preview_ysize));
|
||||
JXL_RETURN_IF_ERROR(ConvertPackedFrameToImageBundle(
|
||||
ppf.info, *ppf.preview_frame, *io, pool, &io->preview_frame));
|
||||
ppf.info, ppf.input_bitdepth, *ppf.preview_frame, *io, pool,
|
||||
&io->preview_frame));
|
||||
}
|
||||
|
||||
// Convert the pixels
|
||||
io->frames.clear();
|
||||
for (const auto& frame : ppf.frames) {
|
||||
ImageBundle bundle(&io->metadata.m);
|
||||
JXL_RETURN_IF_ERROR(
|
||||
ConvertPackedFrameToImageBundle(ppf.info, frame, *io, pool, &bundle));
|
||||
JXL_RETURN_IF_ERROR(ConvertPackedFrameToImageBundle(
|
||||
ppf.info, ppf.input_bitdepth, frame, *io, pool, &bundle));
|
||||
io->frames.push_back(std::move(bundle));
|
||||
}
|
||||
|
||||
|
@ -211,7 +212,8 @@ PackedPixelFile ConvertImage3FToPackedPixelFile(const Image3F& image,
|
|||
: 0;
|
||||
ppf.color_encoding = c_enc.ToExternal();
|
||||
ppf.frames.clear();
|
||||
PackedFrame frame(image.xsize(), image.ysize(), format);
|
||||
JXL_ASSIGN_OR_DIE(PackedFrame frame,
|
||||
PackedFrame::Create(image.xsize(), image.ysize(), format));
|
||||
const ImageF* channels[3];
|
||||
for (int c = 0; c < 3; ++c) {
|
||||
channels[c] = &image.Plane(c);
|
||||
|
@ -243,7 +245,8 @@ Status ConvertCodecInOutToPackedPixelFile(const CodecInOut& io,
|
|||
ppf->info.alpha_bits = alpha_channel->bit_depth.bits_per_sample;
|
||||
ppf->info.alpha_exponent_bits =
|
||||
alpha_channel->bit_depth.exponent_bits_per_sample;
|
||||
ppf->info.alpha_premultiplied = alpha_channel->alpha_associated;
|
||||
ppf->info.alpha_premultiplied =
|
||||
TO_JXL_BOOL(alpha_channel->alpha_associated);
|
||||
}
|
||||
|
||||
// Convert the image metadata
|
||||
|
@ -258,9 +261,9 @@ Status ConvertCodecInOutToPackedPixelFile(const CodecInOut& io,
|
|||
ppf->info.linear_below = io.metadata.m.tone_mapping.linear_below;
|
||||
ppf->info.min_nits = io.metadata.m.tone_mapping.min_nits;
|
||||
ppf->info.relative_to_max_display =
|
||||
io.metadata.m.tone_mapping.relative_to_max_display;
|
||||
TO_JXL_BOOL(io.metadata.m.tone_mapping.relative_to_max_display);
|
||||
|
||||
ppf->info.uses_original_profile = !io.metadata.m.xyb_encoded;
|
||||
ppf->info.uses_original_profile = TO_JXL_BOOL(!io.metadata.m.xyb_encoded);
|
||||
JXL_ASSERT(0 < io.metadata.m.orientation && io.metadata.m.orientation <= 8);
|
||||
ppf->info.orientation =
|
||||
static_cast<JxlOrientation>(io.metadata.m.orientation);
|
||||
|
@ -268,7 +271,7 @@ Status ConvertCodecInOutToPackedPixelFile(const CodecInOut& io,
|
|||
|
||||
// Convert animation metadata
|
||||
JXL_ASSERT(io.frames.size() == 1 || io.metadata.m.have_animation);
|
||||
ppf->info.have_animation = io.metadata.m.have_animation;
|
||||
ppf->info.have_animation = TO_JXL_BOOL(io.metadata.m.have_animation);
|
||||
ppf->info.animation.tps_numerator = io.metadata.m.animation.tps_numerator;
|
||||
ppf->info.animation.tps_denominator = io.metadata.m.animation.tps_denominator;
|
||||
ppf->info.animation.num_loops = io.metadata.m.animation.num_loops;
|
||||
|
@ -293,15 +296,17 @@ Status ConvertCodecInOutToPackedPixelFile(const CodecInOut& io,
|
|||
JXL_ASSERT(frame.metadata()->bit_depth.bits_per_sample != 0);
|
||||
// It is ok for the frame.color().kNumPlanes to not match the
|
||||
// number of channels on the image.
|
||||
const uint32_t alpha_channels = has_alpha ? 1 : 0;
|
||||
const uint32_t num_channels =
|
||||
frame.metadata()->color_encoding.Channels() + has_alpha;
|
||||
frame.metadata()->color_encoding.Channels() + alpha_channels;
|
||||
JxlPixelFormat format{/*num_channels=*/num_channels,
|
||||
/*data_type=*/pixel_format.data_type,
|
||||
/*endianness=*/pixel_format.endianness,
|
||||
/*align=*/pixel_format.align};
|
||||
|
||||
PackedFrame packed_frame(frame.oriented_xsize(), frame.oriented_ysize(),
|
||||
format);
|
||||
JXL_ASSIGN_OR_RETURN(PackedFrame packed_frame,
|
||||
PackedFrame::Create(frame.oriented_xsize(),
|
||||
frame.oriented_ysize(), format));
|
||||
const size_t bits_per_sample =
|
||||
float_out ? packed_frame.color.BitsPerChannel(pixel_format.data_type)
|
||||
: ppf->info.bits_per_sample;
|
||||
|
|
|
@ -19,7 +19,7 @@ HWY_BEFORE_NAMESPACE();
|
|||
namespace jxl {
|
||||
namespace HWY_NAMESPACE {
|
||||
|
||||
static constexpr float rec2020_luminances[3] = {0.2627f, 0.6780f, 0.0593f};
|
||||
static constexpr Vector3 rec2020_luminances{0.2627f, 0.6780f, 0.0593f};
|
||||
|
||||
Status ToneMapFrame(const std::pair<float, float> display_nits,
|
||||
ImageBundle* const ib, ThreadPool* const pool) {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "benchmark/benchmark.h"
|
||||
#include "lib/extras/codec.h"
|
||||
#include "lib/extras/tone_mapping.h"
|
||||
#include "lib/jxl/image.h"
|
||||
|
||||
namespace jxl {
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ typedef enum {
|
|||
typedef enum {
|
||||
/** Sets encoder effort/speed level without affecting decoding speed. Valid
|
||||
* values are, from faster to slower speed: 1:lightning 2:thunder 3:falcon
|
||||
* 4:cheetah 5:hare 6:wombat 7:squirrel 8:kitten 9:tortoise.
|
||||
* 4:cheetah 5:hare 6:wombat 7:squirrel 8:kitten 9:tortoise 10:glacier.
|
||||
* Default: squirrel (7).
|
||||
*/
|
||||
JXL_ENC_FRAME_SETTING_EFFORT = 0,
|
||||
|
@ -1530,7 +1530,7 @@ JXL_EXPORT void JxlColorEncodingSetToLinearSRGB(
|
|||
/**
|
||||
* Enables usage of expert options.
|
||||
*
|
||||
* At the moment, the only expert option is setting an effort value of 10,
|
||||
* At the moment, the only expert option is setting an effort value of 11,
|
||||
* which gives the best compression for pixel-lossless modes but is very slow.
|
||||
*
|
||||
* @param enc encoder object.
|
||||
|
|
|
@ -33,6 +33,8 @@ extern "C" {
|
|||
#define JXL_FALSE 0
|
||||
/** Converts of bool-like value to either ::JXL_TRUE or ::JXL_FALSE. */
|
||||
#define TO_JXL_BOOL(C) (!!(C) ? JXL_TRUE : JXL_FALSE)
|
||||
/** Converts JXL_BOOL to C++ bool. */
|
||||
#define FROM_JXL_BOOL(C) (static_cast<bool>(C))
|
||||
|
||||
/** Data type for the sample values per channel per pixel.
|
||||
*/
|
||||
|
|
|
@ -88,7 +88,6 @@ foreach (TESTFILE IN LISTS JPEGXL_INTERNAL_JPEGLI_TESTS)
|
|||
target_link_libraries(${TESTNAME}
|
||||
hwy
|
||||
jpegli-static
|
||||
gmock
|
||||
GTest::GTest
|
||||
GTest::Main
|
||||
${JPEG_LIBRARIES}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "lib/jpegli/adaptive_quantization.h"
|
||||
|
||||
#include <jxl/types.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
@ -46,7 +47,7 @@ using hwy::HWY_NAMESPACE::Sqrt;
|
|||
using hwy::HWY_NAMESPACE::Sub;
|
||||
using hwy::HWY_NAMESPACE::ZeroIfNegative;
|
||||
|
||||
static constexpr float kInputScaling = 1.0f / 255.0f;
|
||||
constexpr float kInputScaling = 1.0f / 255.0f;
|
||||
|
||||
// Primary template: default to actual division.
|
||||
template <typename T, class V>
|
||||
|
@ -65,7 +66,7 @@ struct FastDivision<float, V> {
|
|||
}
|
||||
|
||||
V operator()(const V n, const V d) const {
|
||||
#if 1 // Faster on SKX
|
||||
#if JXL_TRUE // Faster on SKX
|
||||
return Div(n, d);
|
||||
#else
|
||||
return n * ReciprocalNR(d);
|
||||
|
@ -191,12 +192,12 @@ V ComputeMask(const D d, const V out_val) {
|
|||
}
|
||||
|
||||
// mul and mul2 represent a scaling difference between jxl and butteraugli.
|
||||
static const float kSGmul = 226.0480446705883f;
|
||||
static const float kSGmul2 = 1.0f / 73.377132366608819f;
|
||||
static const float kLog2 = 0.693147181f;
|
||||
const float kSGmul = 226.0480446705883f;
|
||||
const float kSGmul2 = 1.0f / 73.377132366608819f;
|
||||
const float kLog2 = 0.693147181f;
|
||||
// Includes correction factor for std::log -> log2.
|
||||
static const float kSGRetMul = kSGmul2 * 18.6580932135f * kLog2;
|
||||
static const float kSGVOffset = 7.14672470003f;
|
||||
const float kSGRetMul = kSGmul2 * 18.6580932135f * kLog2;
|
||||
const float kSGVOffset = 7.14672470003f;
|
||||
|
||||
template <bool invert, typename D, typename V>
|
||||
V RatioOfDerivativesOfCubicRootToSimpleGamma(const D d, V v) {
|
||||
|
@ -226,7 +227,7 @@ V RatioOfDerivativesOfCubicRootToSimpleGamma(const D d, V v) {
|
|||
}
|
||||
|
||||
template <bool invert = false>
|
||||
static float RatioOfDerivativesOfCubicRootToSimpleGamma(float v) {
|
||||
float RatioOfDerivativesOfCubicRootToSimpleGamma(float v) {
|
||||
using DScalar = HWY_CAPPED(float, 1);
|
||||
auto vscalar = Load(DScalar(), &v);
|
||||
return GetLane(
|
||||
|
@ -503,7 +504,7 @@ HWY_EXPORT(PerBlockModulations);
|
|||
|
||||
namespace {
|
||||
|
||||
static constexpr int kPreErosionBorder = 1;
|
||||
constexpr int kPreErosionBorder = 1;
|
||||
|
||||
} // namespace
|
||||
|
||||
|
|
|
@ -90,8 +90,8 @@ bool EncodeDQT(j_compress_ptr cinfo, bool write_all_tables) {
|
|||
JPEGLI_ERROR("Missing quant table %d", i);
|
||||
}
|
||||
int precision = 0;
|
||||
for (size_t k = 0; k < DCTSIZE2; ++k) {
|
||||
if (quant_table->quantval[k] > 255) {
|
||||
for (UINT16 q : quant_table->quantval) {
|
||||
if (q > 255) {
|
||||
precision = 1;
|
||||
is_baseline = false;
|
||||
}
|
||||
|
@ -123,7 +123,6 @@ bool EncodeDQT(j_compress_ptr cinfo, bool write_all_tables) {
|
|||
|
||||
void EncodeSOF(j_compress_ptr cinfo, bool is_baseline) {
|
||||
if (cinfo->data_precision != kJpegPrecision) {
|
||||
is_baseline = false;
|
||||
JPEGLI_ERROR("Unsupported data precision %d", cinfo->data_precision);
|
||||
}
|
||||
const uint8_t marker = cinfo->progressive_mode ? 0xc2
|
||||
|
@ -302,7 +301,7 @@ void WriteBlock(const int32_t* JXL_RESTRICT symbols,
|
|||
|
||||
namespace {
|
||||
|
||||
static JXL_INLINE void EmitMarker(JpegBitWriter* bw, int marker) {
|
||||
JXL_INLINE void EmitMarker(JpegBitWriter* bw, int marker) {
|
||||
bw->data[bw->pos++] = 0xFF;
|
||||
bw->data[bw->pos++] = marker;
|
||||
}
|
||||
|
|
|
@ -32,9 +32,8 @@ void EncodeSOS(j_compress_ptr cinfo, int scan_index);
|
|||
void WriteScanHeader(j_compress_ptr cinfo, int scan_index);
|
||||
|
||||
void WriteBlock(const int32_t* JXL_RESTRICT symbols,
|
||||
const int32_t* JXL_RESTRICT extra_bits, const int num_nonzeros,
|
||||
const bool emit_eob,
|
||||
const HuffmanCodeTable* JXL_RESTRICT dc_code,
|
||||
const int32_t* JXL_RESTRICT extra_bits, int num_nonzeros,
|
||||
bool emit_eob, const HuffmanCodeTable* JXL_RESTRICT dc_code,
|
||||
const HuffmanCodeTable* JXL_RESTRICT ac_code,
|
||||
JpegBitWriter* JXL_RESTRICT bw);
|
||||
void WriteScanData(j_compress_ptr cinfo, int scan_index);
|
||||
|
|
|
@ -11,13 +11,14 @@
|
|||
|
||||
#include "lib/jpegli/decode_internal.h"
|
||||
#include "lib/jpegli/error.h"
|
||||
#include "lib/jxl/base/status.h"
|
||||
|
||||
namespace jpegli {
|
||||
|
||||
namespace {
|
||||
|
||||
static constexpr int kNumColorCellBits[kMaxComponents] = {3, 4, 3, 3};
|
||||
static constexpr int kCompW[kMaxComponents] = {2, 3, 1, 1};
|
||||
constexpr int kNumColorCellBits[kMaxComponents] = {3, 4, 3, 3};
|
||||
constexpr int kCompW[kMaxComponents] = {2, 3, 1, 1};
|
||||
|
||||
int Pow(int a, int b) {
|
||||
int r = 1;
|
||||
|
@ -102,8 +103,8 @@ namespace {
|
|||
|
||||
// 2^13 priority levels for the PQ seems to be a good compromise between
|
||||
// accuracy, running time and stack space usage.
|
||||
static const int kMaxPriority = 1 << 13;
|
||||
static const int kMaxLevel = 3;
|
||||
const int kMaxPriority = 1 << 13;
|
||||
const int kMaxLevel = 3;
|
||||
|
||||
// This function is used in the multi-resolution grid to be able to compute
|
||||
// the keys for the different resolutions by just shifting the first key.
|
||||
|
@ -153,7 +154,7 @@ inline int ColorIntQuadDistanceRGB(uint8_t r1, uint8_t g1, uint8_t b1,
|
|||
}
|
||||
|
||||
inline int ScaleQuadDistanceRGB(int d) {
|
||||
return static_cast<int>(sqrt(d * 0.25) + 0.5);
|
||||
return static_cast<int>(std::lround(sqrt(d * 0.25)));
|
||||
}
|
||||
|
||||
// The function updates the minimal distances, the clustering and the
|
||||
|
@ -216,9 +217,9 @@ struct WangHasher {
|
|||
// to a unique integer index assigned to the different colors in order of
|
||||
// appearance in the image. Return the number of unique colors found.
|
||||
// The colors are pre-quantized to 3 * 6 bits precision.
|
||||
static int BuildRGBColorIndex(const uint8_t* const image, int const num_pixels,
|
||||
int* const count, uint8_t* const red,
|
||||
uint8_t* const green, uint8_t* const blue) {
|
||||
int BuildRGBColorIndex(const uint8_t* const image, int const num_pixels,
|
||||
int* const count, uint8_t* const red,
|
||||
uint8_t* const green, uint8_t* const blue) {
|
||||
// Impossible because rgb are in the low 24 bits, and the upper 8 bits is 0.
|
||||
const uint32_t impossible_pixel_value = 0x10000000;
|
||||
std::unordered_map<uint32_t, int, RGBPixelHasher> index_map(1 << 12);
|
||||
|
@ -264,7 +265,7 @@ void ChooseColorMap2Pass(j_decompress_ptr cinfo) {
|
|||
std::unique_ptr<uint8_t[]> blue(new uint8_t[max_color_count]);
|
||||
std::vector<int> count(max_color_count, 0);
|
||||
// number of colors
|
||||
int n = BuildRGBColorIndex(m->pixels_, num_pixels, &count[0], &red[0],
|
||||
int n = BuildRGBColorIndex(m->pixels_, num_pixels, count.data(), &red[0],
|
||||
&green[0], &blue[0]);
|
||||
|
||||
std::vector<int> dist(n, std::numeric_limits<int>::max());
|
||||
|
@ -285,14 +286,14 @@ void ChooseColorMap2Pass(j_decompress_ptr cinfo) {
|
|||
winner = i;
|
||||
}
|
||||
if (!in_palette[i] && count[i] > count_threshold) {
|
||||
AddToRGBPalette(&red[0], &green[0], &blue[0], &count[0], i, k++, n,
|
||||
&dist[0], &cluster[0], ¢er[0], &error);
|
||||
AddToRGBPalette(&red[0], &green[0], &blue[0], count.data(), i, k++, n,
|
||||
dist.data(), cluster.data(), ¢er[0], &error);
|
||||
in_palette[i] = true;
|
||||
}
|
||||
}
|
||||
if (k == 0) {
|
||||
AddToRGBPalette(&red[0], &green[0], &blue[0], &count[0], winner, k++, n,
|
||||
&dist[0], &cluster[0], ¢er[0], &error);
|
||||
AddToRGBPalette(&red[0], &green[0], &blue[0], count.data(), winner, k++, n,
|
||||
dist.data(), cluster.data(), ¢er[0], &error);
|
||||
in_palette[winner] = true;
|
||||
}
|
||||
|
||||
|
@ -365,8 +366,8 @@ void ChooseColorMap2Pass(j_decompress_ptr cinfo) {
|
|||
if (priority < top_priority) {
|
||||
bucket_array[priority].push_back(i);
|
||||
} else {
|
||||
AddToRGBPalette(&red[0], &green[0], &blue[0], &count[0], i, k++, n,
|
||||
&dist[0], &cluster[0], ¢er[0], &error);
|
||||
AddToRGBPalette(&red[0], &green[0], &blue[0], count.data(), i, k++, n,
|
||||
dist.data(), cluster.data(), ¢er[0], &error);
|
||||
}
|
||||
bucket_array[top_priority].pop_back();
|
||||
while (top_priority >= 0 && bucket_array[top_priority].empty()) {
|
||||
|
@ -387,7 +388,7 @@ void ChooseColorMap2Pass(j_decompress_ptr cinfo) {
|
|||
|
||||
namespace {
|
||||
|
||||
void FindCandidatesForCell(j_decompress_ptr cinfo, int ncomp, int cell[],
|
||||
void FindCandidatesForCell(j_decompress_ptr cinfo, int ncomp, const int cell[],
|
||||
std::vector<uint8_t>* candidates) {
|
||||
int cell_min[kMaxComponents];
|
||||
int cell_max[kMaxComponents];
|
||||
|
@ -404,7 +405,8 @@ void FindCandidatesForCell(j_decompress_ptr cinfo, int ncomp, int cell[],
|
|||
int dmax = 0;
|
||||
for (int c = 0; c < ncomp; ++c) {
|
||||
int palette_c = cinfo->colormap[c][i];
|
||||
int dminc = 0, dmaxc;
|
||||
int dminc = 0;
|
||||
int dmaxc;
|
||||
if (palette_c < cell_min[c]) {
|
||||
dminc = cell_min[c] - palette_c;
|
||||
dmaxc = cell_max[c] - palette_c;
|
||||
|
@ -436,6 +438,8 @@ void FindCandidatesForCell(j_decompress_ptr cinfo, int ncomp, int cell[],
|
|||
void CreateInverseColorMap(j_decompress_ptr cinfo) {
|
||||
jpeg_decomp_master* m = cinfo->master;
|
||||
int ncomp = cinfo->out_color_components;
|
||||
JXL_ASSERT(ncomp > 0);
|
||||
JXL_ASSERT(ncomp <= kMaxComponents);
|
||||
int num_cells = 1;
|
||||
for (int c = 0; c < ncomp; ++c) {
|
||||
num_cells *= (1 << kNumColorCellBits[c]);
|
||||
|
@ -455,7 +459,7 @@ void CreateInverseColorMap(j_decompress_ptr cinfo) {
|
|||
m->regenerate_inverse_colormap_ = false;
|
||||
}
|
||||
|
||||
int LookupColorIndex(j_decompress_ptr cinfo, JSAMPLE* pixel) {
|
||||
int LookupColorIndex(j_decompress_ptr cinfo, const JSAMPLE* pixel) {
|
||||
jpeg_decomp_master* m = cinfo->master;
|
||||
int num_channels = cinfo->out_color_components;
|
||||
int index = 0;
|
||||
|
|
|
@ -20,7 +20,7 @@ void CreateOrderedDitherTables(j_decompress_ptr cinfo);
|
|||
|
||||
void InitFSDitherState(j_decompress_ptr cinfo);
|
||||
|
||||
int LookupColorIndex(j_decompress_ptr cinfo, JSAMPLE* pixel);
|
||||
int LookupColorIndex(j_decompress_ptr cinfo, const JSAMPLE* pixel);
|
||||
|
||||
} // namespace jpegli
|
||||
|
||||
|
|
|
@ -187,7 +187,7 @@ void DCT1D(const float* JXL_RESTRICT pixels, size_t pixels_stride,
|
|||
}
|
||||
}
|
||||
|
||||
static JXL_INLINE JXL_MAYBE_UNUSED void TransformFromPixels(
|
||||
JXL_INLINE JXL_MAYBE_UNUSED void TransformFromPixels(
|
||||
const float* JXL_RESTRICT pixels, size_t pixels_stride,
|
||||
float* JXL_RESTRICT coefficients, float* JXL_RESTRICT scratch_space) {
|
||||
DCT1D(pixels, pixels_stride, scratch_space);
|
||||
|
@ -196,14 +196,14 @@ static JXL_INLINE JXL_MAYBE_UNUSED void TransformFromPixels(
|
|||
Transpose8x8Block(scratch_space, coefficients);
|
||||
}
|
||||
|
||||
static JXL_INLINE JXL_MAYBE_UNUSED void StoreQuantizedValue(const Vec<DI>& ival,
|
||||
int16_t* out) {
|
||||
JXL_INLINE JXL_MAYBE_UNUSED void StoreQuantizedValue(const Vec<DI>& ival,
|
||||
int16_t* out) {
|
||||
Rebind<int16_t, DI> di16;
|
||||
Store(DemoteTo(di16, ival), di16, out);
|
||||
}
|
||||
|
||||
static JXL_INLINE JXL_MAYBE_UNUSED void StoreQuantizedValue(const Vec<DI>& ival,
|
||||
int32_t* out) {
|
||||
JXL_INLINE JXL_MAYBE_UNUSED void StoreQuantizedValue(const Vec<DI>& ival,
|
||||
int32_t* out) {
|
||||
DI di;
|
||||
Store(ival, di, out);
|
||||
}
|
||||
|
|
|
@ -115,8 +115,10 @@ void InitProgressMonitor(j_decompress_ptr cinfo, bool coef_only) {
|
|||
cinfo->progress->total_passes = 1;
|
||||
} else {
|
||||
int input_passes = !cinfo->buffered_image && m->is_multiscan_ ? 1 : 0;
|
||||
bool two_pass_quant = cinfo->quantize_colors && !cinfo->colormap &&
|
||||
cinfo->two_pass_quantize && cinfo->enable_2pass_quant;
|
||||
bool two_pass_quant = FROM_JXL_BOOL(cinfo->quantize_colors) &&
|
||||
(cinfo->colormap != nullptr) &&
|
||||
FROM_JXL_BOOL(cinfo->two_pass_quantize) &&
|
||||
FROM_JXL_BOOL(cinfo->enable_2pass_quant);
|
||||
cinfo->progress->total_passes = input_passes + (two_pass_quant ? 2 : 1);
|
||||
}
|
||||
cinfo->progress->completed_passes = 0;
|
||||
|
@ -175,7 +177,7 @@ void BuildHuffmanLookupTable(j_decompress_ptr cinfo, JHUFF_TBL* table,
|
|||
for (int i = 0; i < total_count; ++i) {
|
||||
int value = table->huffval[i];
|
||||
if (values_seen[value]) {
|
||||
return JPEGLI_ERROR("Duplicate Huffman code value %d", value);
|
||||
JPEGLI_ERROR("Duplicate Huffman code value %d", value);
|
||||
}
|
||||
values_seen[value] = 1;
|
||||
values[i] = value;
|
||||
|
@ -223,7 +225,7 @@ void PrepareForScan(j_decompress_ptr cinfo) {
|
|||
HuffmanTableEntry* huff_lut =
|
||||
&m->dc_huff_lut_[dc_tbl_idx * kJpegHuffmanLutSize];
|
||||
if (!table) {
|
||||
return JPEGLI_ERROR("DC Huffman table %d not found", dc_tbl_idx);
|
||||
JPEGLI_ERROR("DC Huffman table %d not found", dc_tbl_idx);
|
||||
}
|
||||
BuildHuffmanLookupTable(cinfo, table, huff_lut);
|
||||
}
|
||||
|
@ -233,7 +235,7 @@ void PrepareForScan(j_decompress_ptr cinfo) {
|
|||
HuffmanTableEntry* huff_lut =
|
||||
&m->ac_huff_lut_[ac_tbl_idx * kJpegHuffmanLutSize];
|
||||
if (!table) {
|
||||
return JPEGLI_ERROR("AC Huffman table %d not found", ac_tbl_idx);
|
||||
JPEGLI_ERROR("AC Huffman table %d not found", ac_tbl_idx);
|
||||
}
|
||||
BuildHuffmanLookupTable(cinfo, table, huff_lut);
|
||||
}
|
||||
|
@ -543,8 +545,8 @@ void jpegli_CreateDecompress(j_decompress_ptr cinfo, int version,
|
|||
cinfo->is_decompressor = TRUE;
|
||||
cinfo->progress = nullptr;
|
||||
cinfo->src = nullptr;
|
||||
for (int i = 0; i < NUM_QUANT_TBLS; i++) {
|
||||
cinfo->quant_tbl_ptrs[i] = nullptr;
|
||||
for (auto& quant_tbl_ptr : cinfo->quant_tbl_ptrs) {
|
||||
quant_tbl_ptr = nullptr;
|
||||
}
|
||||
for (int i = 0; i < NUM_HUFF_TBLS; i++) {
|
||||
cinfo->dc_huff_tbl_ptrs[i] = nullptr;
|
||||
|
@ -555,8 +557,8 @@ void jpegli_CreateDecompress(j_decompress_ptr cinfo, int version,
|
|||
cinfo->rec_outbuf_height = 1; // output works with any buffer height
|
||||
cinfo->master = new jpeg_decomp_master;
|
||||
jpeg_decomp_master* m = cinfo->master;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
m->app_marker_parsers[i] = nullptr;
|
||||
for (auto& app_marker_parser : m->app_marker_parsers) {
|
||||
app_marker_parser = nullptr;
|
||||
}
|
||||
m->com_marker_parser = nullptr;
|
||||
memset(m->markers_to_save_, 0, sizeof(m->markers_to_save_));
|
||||
|
@ -661,7 +663,7 @@ boolean jpegli_read_icc_profile(j_decompress_ptr cinfo, JOCTET** icc_data_ptr,
|
|||
return FALSE;
|
||||
}
|
||||
*icc_data_len = m->icc_profile_.size();
|
||||
*icc_data_ptr = (JOCTET*)malloc(*icc_data_len);
|
||||
*icc_data_ptr = static_cast<JOCTET*>(malloc(*icc_data_len));
|
||||
if (*icc_data_ptr == nullptr) {
|
||||
JPEGLI_ERROR("jpegli_read_icc_profile: Out of memory");
|
||||
}
|
||||
|
@ -738,21 +740,26 @@ void jpegli_calc_output_dimensions(j_decompress_ptr cinfo) {
|
|||
}
|
||||
|
||||
boolean jpegli_has_multiple_scans(j_decompress_ptr cinfo) {
|
||||
if (cinfo->input_scan_number == 0) {
|
||||
JPEGLI_ERROR("No SOS marker found.");
|
||||
if (cinfo->global_state != jpegli::kDecHeaderDone &&
|
||||
cinfo->global_state != jpegli::kDecProcessScan &&
|
||||
cinfo->global_state != jpegli::kDecProcessMarkers) {
|
||||
JPEGLI_ERROR("jpegli_has_multiple_scans: unexpected state %d",
|
||||
cinfo->global_state);
|
||||
}
|
||||
return cinfo->master->is_multiscan_;
|
||||
return TO_JXL_BOOL(cinfo->master->is_multiscan_);
|
||||
}
|
||||
|
||||
boolean jpegli_input_complete(j_decompress_ptr cinfo) {
|
||||
return cinfo->master->found_eoi_;
|
||||
return TO_JXL_BOOL(cinfo->master->found_eoi_);
|
||||
}
|
||||
|
||||
boolean jpegli_start_decompress(j_decompress_ptr cinfo) {
|
||||
jpeg_decomp_master* m = cinfo->master;
|
||||
if (cinfo->global_state == jpegli::kDecHeaderDone) {
|
||||
m->streaming_mode_ = !m->is_multiscan_ && !cinfo->buffered_image &&
|
||||
(!cinfo->quantize_colors || !cinfo->two_pass_quantize);
|
||||
m->streaming_mode_ = !m->is_multiscan_ &&
|
||||
!FROM_JXL_BOOL(cinfo->buffered_image) &&
|
||||
(!FROM_JXL_BOOL(cinfo->quantize_colors) ||
|
||||
!FROM_JXL_BOOL(cinfo->two_pass_quantize));
|
||||
jpegli::AllocateCoefficientBuffer(cinfo);
|
||||
jpegli_calc_output_dimensions(cinfo);
|
||||
jpegli::PrepareForScan(cinfo);
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
namespace jpegli {
|
||||
namespace {
|
||||
|
||||
static constexpr uint8_t kFakeEoiMarker[2] = {0xff, 0xd9};
|
||||
static constexpr size_t kNumSourceBuffers = 4;
|
||||
constexpr uint8_t kFakeEoiMarker[2] = {0xff, 0xd9};
|
||||
constexpr size_t kNumSourceBuffers = 4;
|
||||
|
||||
// Custom source manager that refills the input buffer in chunks, simulating
|
||||
// a file reader with a fixed buffer size.
|
||||
|
@ -61,7 +61,7 @@ class SourceManager {
|
|||
static void init_source(j_decompress_ptr cinfo) {}
|
||||
|
||||
static boolean fill_input_buffer(j_decompress_ptr cinfo) {
|
||||
auto src = reinterpret_cast<SourceManager*>(cinfo->src);
|
||||
auto* src = reinterpret_cast<SourceManager*>(cinfo->src);
|
||||
if (src->pos_ < src->len_) {
|
||||
size_t chunk_size = std::min(src->len_ - src->pos_, src->max_chunk_size_);
|
||||
size_t next_idx = ++src->chunk_idx_ % kNumSourceBuffers;
|
||||
|
@ -79,7 +79,7 @@ class SourceManager {
|
|||
}
|
||||
|
||||
static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
|
||||
auto src = reinterpret_cast<SourceManager*>(cinfo->src);
|
||||
auto* src = reinterpret_cast<SourceManager*>(cinfo->src);
|
||||
if (num_bytes <= 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -166,9 +166,9 @@ void ReadOutputImage(const DecompressParams& dparams, j_decompress_ptr cinfo,
|
|||
rowdata[c][i] =
|
||||
y0 + i < ysize ? &output->raw_data[c][(y0 + i) * xsize] : nullptr;
|
||||
}
|
||||
data[c] = &rowdata[c][0];
|
||||
data[c] = rowdata[c].data();
|
||||
}
|
||||
num_output_lines = jpegli_read_raw_data(cinfo, &data[0], max_lines);
|
||||
num_output_lines = jpegli_read_raw_data(cinfo, data.data(), max_lines);
|
||||
} else {
|
||||
size_t max_output_lines = dparams.max_output_lines;
|
||||
if (max_output_lines == 0) max_output_lines = cinfo->output_height;
|
||||
|
@ -189,7 +189,7 @@ void ReadOutputImage(const DecompressParams& dparams, j_decompress_ptr cinfo,
|
|||
scanlines[i] = &output->pixels[yidx * stride];
|
||||
}
|
||||
num_output_lines =
|
||||
jpegli_read_scanlines(cinfo, &scanlines[0], max_lines);
|
||||
jpegli_read_scanlines(cinfo, scanlines.data(), max_lines);
|
||||
if (cinfo->quantize_colors) {
|
||||
for (size_t i = 0; i < num_output_lines; ++i) {
|
||||
UnmapColors(scanlines[i], cinfo->output_width,
|
||||
|
@ -222,7 +222,7 @@ struct TestConfig {
|
|||
std::vector<uint8_t> GetTestJpegData(TestConfig& config) {
|
||||
std::vector<uint8_t> compressed;
|
||||
if (!config.fn.empty()) {
|
||||
compressed = ReadTestData(config.fn.c_str());
|
||||
compressed = ReadTestData(config.fn);
|
||||
} else {
|
||||
GeneratePixels(&config.input);
|
||||
JXL_CHECK(EncodeWithJpegli(config.input, config.jparams, &compressed));
|
||||
|
@ -297,10 +297,10 @@ void TestAPIBuffered(const CompressParams& jparams,
|
|||
SetDecompressParams(dparams, cinfo);
|
||||
jpegli_set_output_format(cinfo, dparams.data_type, dparams.endianness);
|
||||
VerifyHeader(jparams, cinfo);
|
||||
bool has_multiple_scans = FROM_JXL_BOOL(jpegli_has_multiple_scans(cinfo));
|
||||
EXPECT_TRUE(jpegli_start_decompress(cinfo));
|
||||
// start decompress should not read the whole input in buffered image mode
|
||||
EXPECT_FALSE(jpegli_input_complete(cinfo));
|
||||
bool has_multiple_scans = jpegli_has_multiple_scans(cinfo);
|
||||
EXPECT_EQ(0, cinfo->output_scan_number);
|
||||
int sos_marker_cnt = 1; // read_header reads the first SOS marker
|
||||
while (!jpegli_input_complete(cinfo)) {
|
||||
|
@ -341,8 +341,11 @@ void TestAPIBuffered(const CompressParams& jparams,
|
|||
}
|
||||
|
||||
TEST(DecodeAPITest, ReuseCinfo) {
|
||||
TestImage input, output, expected;
|
||||
std::vector<TestImage> output_progression, expected_output_progression;
|
||||
TestImage input;
|
||||
TestImage output;
|
||||
TestImage expected;
|
||||
std::vector<TestImage> output_progression;
|
||||
std::vector<TestImage> expected_output_progression;
|
||||
CompressParams jparams;
|
||||
DecompressParams dparams;
|
||||
std::vector<uint8_t> compressed;
|
||||
|
@ -383,8 +386,8 @@ TEST(DecodeAPITest, ReuseCinfo) {
|
|||
expected.Clear();
|
||||
DecodeWithLibjpeg(jparams, dparams, compressed, &expected);
|
||||
output.Clear();
|
||||
cinfo.buffered_image = false;
|
||||
cinfo.raw_data_out = false;
|
||||
cinfo.buffered_image = JXL_FALSE;
|
||||
cinfo.raw_data_out = JXL_FALSE;
|
||||
cinfo.scale_num = cinfo.scale_denom = 1;
|
||||
SourceManager src(compressed.data(), compressed.size(),
|
||||
1u << 12);
|
||||
|
@ -1245,7 +1248,8 @@ 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((J_COLOR_SPACE)dparams.out_color_space);
|
||||
os << "OutColor"
|
||||
<< ColorSpaceName(static_cast<J_COLOR_SPACE>(dparams.out_color_space));
|
||||
}
|
||||
if (dparams.crop_output) {
|
||||
os << "Crop";
|
||||
|
@ -1265,7 +1269,8 @@ 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((J_DITHER_MODE)sparam.dither_mode) << "Dither";
|
||||
os << DitherMode(static_cast<J_DITHER_MODE>(sparam.dither_mode))
|
||||
<< "Dither";
|
||||
}
|
||||
}
|
||||
if (dparams.skip_scans) {
|
||||
|
|
|
@ -45,12 +45,13 @@ struct jpeg_decomp_master {
|
|||
size_t input_buffer_pos_;
|
||||
// Number of bits after codestream_pos_ that were already processed.
|
||||
size_t codestream_bits_ahead_;
|
||||
bool streaming_mode_;
|
||||
|
||||
// Coefficient buffers
|
||||
jvirt_barray_ptr* coef_arrays;
|
||||
JBLOCKARRAY coeff_rows[jpegli::kMaxComponents];
|
||||
|
||||
bool streaming_mode_;
|
||||
|
||||
//
|
||||
// Marker data processing state.
|
||||
//
|
||||
|
@ -58,6 +59,11 @@ struct jpeg_decomp_master {
|
|||
bool found_dri_;
|
||||
bool found_sof_;
|
||||
bool found_eoi_;
|
||||
|
||||
// Whether this jpeg has multiple scans (progressive or non-interleaved
|
||||
// sequential).
|
||||
bool is_multiscan_;
|
||||
|
||||
size_t icc_index_;
|
||||
size_t icc_total_;
|
||||
std::vector<uint8_t> icc_profile_;
|
||||
|
@ -66,9 +72,6 @@ struct jpeg_decomp_master {
|
|||
uint8_t markers_to_save_[32];
|
||||
jpeg_marker_parser_method app_marker_parsers[16];
|
||||
jpeg_marker_parser_method com_marker_parser;
|
||||
// Whether this jpeg has multiple scans (progressive or non-interleaved
|
||||
// sequential).
|
||||
bool is_multiscan_;
|
||||
|
||||
// Fields defined by SOF marker.
|
||||
size_t iMCU_cols_;
|
||||
|
@ -96,9 +99,11 @@ struct jpeg_decomp_master {
|
|||
//
|
||||
int output_passes_done_;
|
||||
JpegliDataType output_data_type_ = JPEGLI_TYPE_UINT8;
|
||||
bool swap_endianness_ = false;
|
||||
size_t xoffset_;
|
||||
bool swap_endianness_ = false;
|
||||
bool need_context_rows_;
|
||||
bool regenerate_inverse_colormap_;
|
||||
bool apply_smoothing;
|
||||
|
||||
int min_scaled_dct_size;
|
||||
int scaled_dct_size[jpegli::kMaxComponents];
|
||||
|
@ -127,7 +132,6 @@ struct jpeg_decomp_master {
|
|||
uint8_t* pixels_;
|
||||
JSAMPARRAY scanlines_;
|
||||
std::vector<std::vector<uint8_t>> candidate_lists_;
|
||||
bool regenerate_inverse_colormap_;
|
||||
float* dither_[jpegli::kMaxComponents];
|
||||
float* error_row_[2 * jpegli::kMaxComponents];
|
||||
size_t dither_size_;
|
||||
|
@ -145,7 +149,6 @@ struct jpeg_decomp_master {
|
|||
// i.e. the bottom half when rendering incomplete scans.
|
||||
int (*coef_bits_latch)[SAVED_COEFS];
|
||||
int (*prev_coef_bits_latch)[SAVED_COEFS];
|
||||
bool apply_smoothing;
|
||||
};
|
||||
|
||||
#endif // LIB_JPEGLI_DECODE_INTERNAL_H_
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "lib/jpegli/decode_marker.h"
|
||||
|
||||
#include <jxl/types.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lib/jpegli/common.h"
|
||||
|
@ -22,23 +23,22 @@ constexpr uint8_t kIccProfileTag[12] = "ICC_PROFILE";
|
|||
|
||||
// Macros for commonly used error conditions.
|
||||
|
||||
#define JPEG_VERIFY_LEN(n) \
|
||||
if (pos + (n) > len) { \
|
||||
return JPEGLI_ERROR("Unexpected end of marker: pos=%" PRIuS \
|
||||
" need=%d len=%" PRIuS, \
|
||||
pos, static_cast<int>(n), len); \
|
||||
#define JPEG_VERIFY_LEN(n) \
|
||||
if (pos + (n) > len) { \
|
||||
JPEGLI_ERROR("Unexpected end of marker: pos=%" PRIuS \
|
||||
" need=%d len=%" PRIuS, \
|
||||
pos, static_cast<int>(n), len); \
|
||||
}
|
||||
|
||||
#define JPEG_VERIFY_INPUT(var, low, high) \
|
||||
if ((var) < (low) || (var) > (high)) { \
|
||||
return JPEGLI_ERROR("Invalid " #var ": %d", static_cast<int>(var)); \
|
||||
#define JPEG_VERIFY_INPUT(var, low, high) \
|
||||
if ((var) < (low) || (var) > (high)) { \
|
||||
JPEGLI_ERROR("Invalid " #var ": %d", static_cast<int>(var)); \
|
||||
}
|
||||
|
||||
#define JPEG_VERIFY_MARKER_END() \
|
||||
if (pos != len) { \
|
||||
return JPEGLI_ERROR("Invalid marker length: declared=%" PRIuS \
|
||||
" actual=%" PRIuS, \
|
||||
len, pos); \
|
||||
#define JPEG_VERIFY_MARKER_END() \
|
||||
if (pos != len) { \
|
||||
JPEGLI_ERROR("Invalid marker length: declared=%" PRIuS " actual=%" PRIuS, \
|
||||
len, pos); \
|
||||
}
|
||||
|
||||
inline int ReadUint8(const uint8_t* data, size_t* pos) {
|
||||
|
@ -60,7 +60,7 @@ void ProcessSOF(j_decompress_ptr cinfo, const uint8_t* data, size_t len) {
|
|||
JPEGLI_ERROR("Duplicate SOF marker.");
|
||||
}
|
||||
m->found_sof_ = true;
|
||||
cinfo->progressive_mode = (cinfo->unread_marker == 0xc2);
|
||||
cinfo->progressive_mode = TO_JXL_BOOL(cinfo->unread_marker == 0xc2);
|
||||
cinfo->arith_code = 0;
|
||||
size_t pos = 2;
|
||||
JPEG_VERIFY_LEN(6);
|
||||
|
@ -181,7 +181,7 @@ void ProcessSOS(j_decompress_ptr cinfo, const uint8_t* data, size_t len) {
|
|||
for (int i = 0; i < cinfo->comps_in_scan; ++i) {
|
||||
int id = ReadUint8(data, &pos);
|
||||
if (ids_seen[id]) { // (cf. section B.2.3, regarding CSj)
|
||||
return JPEGLI_ERROR("Duplicate ID %d in SOS.", id);
|
||||
JPEGLI_ERROR("Duplicate ID %d in SOS.", id);
|
||||
}
|
||||
ids_seen[id] = 1;
|
||||
jpeg_component_info* comp = nullptr;
|
||||
|
@ -192,8 +192,7 @@ void ProcessSOS(j_decompress_ptr cinfo, const uint8_t* data, size_t len) {
|
|||
}
|
||||
}
|
||||
if (!comp) {
|
||||
return JPEGLI_ERROR("SOS marker: Could not find component with id %d",
|
||||
id);
|
||||
JPEGLI_ERROR("SOS marker: Could not find component with id %d", id);
|
||||
}
|
||||
int c = ReadUint8(data, &pos);
|
||||
comp->dc_tbl_no = c >> 4;
|
||||
|
@ -222,7 +221,7 @@ void ProcessSOS(j_decompress_ptr cinfo, const uint8_t* data, size_t len) {
|
|||
|
||||
if (cinfo->input_scan_number == 0) {
|
||||
m->is_multiscan_ = (cinfo->comps_in_scan < cinfo->num_components ||
|
||||
cinfo->progressive_mode);
|
||||
FROM_JXL_BOOL(cinfo->progressive_mode));
|
||||
}
|
||||
if (cinfo->Ah != 0 && cinfo->Al != cinfo->Ah - 1) {
|
||||
// section G.1.1.1.2 : Successive approximation control only improves
|
||||
|
@ -261,12 +260,12 @@ void ProcessSOS(j_decompress_ptr cinfo, const uint8_t* data, size_t len) {
|
|||
int comp_idx = cinfo->cur_comp_info[i]->component_index;
|
||||
for (int k = cinfo->Ss; k <= cinfo->Se; ++k) {
|
||||
if (m->scan_progression_[comp_idx][k] & scan_bitmask) {
|
||||
return JPEGLI_ERROR(
|
||||
JPEGLI_ERROR(
|
||||
"Overlapping scans: component=%d k=%d prev_mask: %u cur_mask %u",
|
||||
comp_idx, k, m->scan_progression_[i][k], scan_bitmask);
|
||||
}
|
||||
if (m->scan_progression_[comp_idx][k] & refinement_bitmask) {
|
||||
return JPEGLI_ERROR(
|
||||
JPEGLI_ERROR(
|
||||
"Invalid scan order, a more refined scan was already done: "
|
||||
"component=%d k=%d prev_mask=%u cur_mask=%u",
|
||||
comp_idx, k, m->scan_progression_[i][k], scan_bitmask);
|
||||
|
@ -275,7 +274,7 @@ void ProcessSOS(j_decompress_ptr cinfo, const uint8_t* data, size_t len) {
|
|||
}
|
||||
}
|
||||
if (cinfo->Al > 10) {
|
||||
return JPEGLI_ERROR("Scan parameter Al=%d is not supported.", cinfo->Al);
|
||||
JPEGLI_ERROR("Scan parameter Al=%d is not supported.", cinfo->Al);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -285,7 +284,7 @@ void ProcessSOS(j_decompress_ptr cinfo, const uint8_t* data, size_t len) {
|
|||
void ProcessDHT(j_decompress_ptr cinfo, const uint8_t* data, size_t len) {
|
||||
size_t pos = 2;
|
||||
if (pos == len) {
|
||||
return JPEGLI_ERROR("DHT marker: no Huffman table found");
|
||||
JPEGLI_ERROR("DHT marker: no Huffman table found");
|
||||
}
|
||||
while (pos < len) {
|
||||
JPEG_VERIFY_LEN(1 + kJpegHuffmanMaxBitLength);
|
||||
|
@ -293,7 +292,7 @@ void ProcessDHT(j_decompress_ptr cinfo, const uint8_t* data, size_t len) {
|
|||
// component Huffman codes, 0x10 is added to the index.
|
||||
int slot_id = ReadUint8(data, &pos);
|
||||
int huffman_index = slot_id;
|
||||
int is_ac_table = (slot_id & 0x10) != 0;
|
||||
bool is_ac_table = ((slot_id & 0x10) != 0);
|
||||
JHUFF_TBL** table;
|
||||
if (is_ac_table) {
|
||||
huffman_index -= 0x10;
|
||||
|
@ -343,7 +342,7 @@ void ProcessDQT(j_decompress_ptr cinfo, const uint8_t* data, size_t len) {
|
|||
}
|
||||
size_t pos = 2;
|
||||
if (pos == len) {
|
||||
return JPEGLI_ERROR("DQT marker: no quantization table found");
|
||||
JPEGLI_ERROR("DQT marker: no quantization table found");
|
||||
}
|
||||
while (pos < len) {
|
||||
JPEG_VERIFY_LEN(1);
|
||||
|
@ -377,7 +376,7 @@ void ProcessDNL(j_decompress_ptr cinfo, const uint8_t* data, size_t len) {
|
|||
void ProcessDRI(j_decompress_ptr cinfo, const uint8_t* data, size_t len) {
|
||||
jpeg_decomp_master* m = cinfo->master;
|
||||
if (m->found_dri_) {
|
||||
return JPEGLI_ERROR("Duplicate DRI marker.");
|
||||
JPEGLI_ERROR("Duplicate DRI marker.");
|
||||
}
|
||||
m->found_dri_ = true;
|
||||
size_t pos = 2;
|
||||
|
@ -411,24 +410,24 @@ void ProcessAPP(j_decompress_ptr cinfo, const uint8_t* data, size_t len) {
|
|||
payload += sizeof(kIccProfileTag);
|
||||
payload_size -= sizeof(kIccProfileTag);
|
||||
if (payload_size < 2) {
|
||||
return JPEGLI_ERROR("ICC chunk is too small.");
|
||||
JPEGLI_ERROR("ICC chunk is too small.");
|
||||
}
|
||||
uint8_t index = payload[0];
|
||||
uint8_t total = payload[1];
|
||||
++m->icc_index_;
|
||||
if (m->icc_index_ != index) {
|
||||
return JPEGLI_ERROR("Invalid ICC chunk order.");
|
||||
JPEGLI_ERROR("Invalid ICC chunk order.");
|
||||
}
|
||||
if (total == 0) {
|
||||
return JPEGLI_ERROR("Invalid ICC chunk total.");
|
||||
JPEGLI_ERROR("Invalid ICC chunk total.");
|
||||
}
|
||||
if (m->icc_total_ == 0) {
|
||||
m->icc_total_ = total;
|
||||
} else if (m->icc_total_ != total) {
|
||||
return JPEGLI_ERROR("Invalid ICC chunk total.");
|
||||
JPEGLI_ERROR("Invalid ICC chunk total.");
|
||||
}
|
||||
if (m->icc_index_ > m->icc_total_) {
|
||||
return JPEGLI_ERROR("Invalid ICC chunk index.");
|
||||
JPEGLI_ERROR("Invalid ICC chunk index.");
|
||||
}
|
||||
m->icc_profile_.insert(m->icc_profile_.end(), payload + 2,
|
||||
payload + payload_size);
|
||||
|
@ -494,8 +493,8 @@ uint8_t ProcessNextMarker(j_decompress_ptr cinfo, const uint8_t* const data,
|
|||
marker = data[*pos + 1];
|
||||
if (num_skipped > 0) {
|
||||
if (m->found_soi_) {
|
||||
JPEGLI_WARN("Skipped %d bytes before marker 0x%02x", (int)num_skipped,
|
||||
marker);
|
||||
JPEGLI_WARN("Skipped %d bytes before marker 0x%02x",
|
||||
static_cast<int>(num_skipped), marker);
|
||||
} else {
|
||||
JPEGLI_ERROR("Did not find SOI marker.");
|
||||
}
|
||||
|
|
|
@ -22,8 +22,8 @@ namespace jpegli {
|
|||
// EOI marker. Input buffer refill is handled by the caller;
|
||||
// * 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);
|
||||
int ProcessMarkers(j_decompress_ptr cinfo, const uint8_t* data, size_t len,
|
||||
size_t* pos);
|
||||
|
||||
jpeg_marker_parser_method GetMarkerProcessor(j_decompress_ptr cinfo);
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ struct BitReaderState {
|
|||
if (bits_left_ <= 16) {
|
||||
while (bits_left_ <= 56) {
|
||||
val_ <<= 8;
|
||||
val_ |= (uint64_t)GetNextByte();
|
||||
val_ |= static_cast<uint64_t>(GetNextByte());
|
||||
bits_left_ += 8;
|
||||
}
|
||||
}
|
||||
|
@ -427,7 +427,7 @@ void PrepareForiMCURow(j_decompress_ptr cinfo) {
|
|||
int offset = m->streaming_mode_ ? 0 : by0;
|
||||
m->coeff_rows[c] = (*cinfo->mem->access_virt_barray)(
|
||||
reinterpret_cast<j_common_ptr>(cinfo), m->coef_arrays[c], offset,
|
||||
max_block_rows, true);
|
||||
max_block_rows, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -451,7 +451,8 @@ int ProcessScan(j_decompress_ptr cinfo, const uint8_t* const data,
|
|||
++num_skipped;
|
||||
}
|
||||
if (num_skipped > 0) {
|
||||
JPEGLI_WARN("Skipped %d bytes before restart marker", (int)num_skipped);
|
||||
JPEGLI_WARN("Skipped %d bytes before restart marker",
|
||||
static_cast<int>(num_skipped));
|
||||
}
|
||||
if (*pos + 2 > len) {
|
||||
return kNeedMoreInput;
|
||||
|
@ -471,7 +472,7 @@ int ProcessScan(j_decompress_ptr cinfo, const uint8_t* const data,
|
|||
}
|
||||
|
||||
// Decode one MCU.
|
||||
HWY_ALIGN_MAX coeff_t sink_block[DCTSIZE2];
|
||||
HWY_ALIGN_MAX static coeff_t sink_block[DCTSIZE2] = {0};
|
||||
bool scan_ok = true;
|
||||
for (int i = 0; i < cinfo->comps_in_scan; ++i) {
|
||||
const jpeg_component_info* comp = cinfo->cur_comp_info[i];
|
||||
|
|
|
@ -21,8 +21,8 @@ namespace jpegli {
|
|||
// * JPEG_SUSPENDED, if the input buffer ends before the end of an iMCU row;
|
||||
// * JPEG_ROW_COMPLETED, if the next iMCU row (but not the scan) is reached;
|
||||
// * JPEG_SCAN_COMPLETED, if the end of the scan is reached.
|
||||
int ProcessScan(j_decompress_ptr cinfo, const uint8_t* const data,
|
||||
const size_t len, size_t* pos, size_t* bit_pos);
|
||||
int ProcessScan(j_decompress_ptr cinfo, const uint8_t* data, size_t len,
|
||||
size_t* pos, size_t* bit_pos);
|
||||
|
||||
void PrepareForiMCURow(j_decompress_ptr cinfo);
|
||||
|
||||
|
|
|
@ -19,13 +19,13 @@ struct StdioDestinationManager {
|
|||
uint8_t* buffer;
|
||||
|
||||
static void init_destination(j_compress_ptr cinfo) {
|
||||
auto dest = reinterpret_cast<StdioDestinationManager*>(cinfo->dest);
|
||||
auto* dest = reinterpret_cast<StdioDestinationManager*>(cinfo->dest);
|
||||
dest->pub.next_output_byte = dest->buffer;
|
||||
dest->pub.free_in_buffer = kDestBufferSize;
|
||||
}
|
||||
|
||||
static boolean empty_output_buffer(j_compress_ptr cinfo) {
|
||||
auto dest = reinterpret_cast<StdioDestinationManager*>(cinfo->dest);
|
||||
auto* dest = reinterpret_cast<StdioDestinationManager*>(cinfo->dest);
|
||||
if (fwrite(dest->buffer, 1, kDestBufferSize, dest->f) != kDestBufferSize) {
|
||||
JPEGLI_ERROR("Failed to write to output stream.");
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ struct StdioDestinationManager {
|
|||
}
|
||||
|
||||
static void term_destination(j_compress_ptr cinfo) {
|
||||
auto dest = reinterpret_cast<StdioDestinationManager*>(cinfo->dest);
|
||||
auto* dest = reinterpret_cast<StdioDestinationManager*>(cinfo->dest);
|
||||
size_t bytes_left = kDestBufferSize - dest->pub.free_in_buffer;
|
||||
if (bytes_left &&
|
||||
fwrite(dest->buffer, 1, bytes_left, dest->f) != bytes_left) {
|
||||
|
@ -62,7 +62,7 @@ struct MemoryDestinationManager {
|
|||
static void init_destination(j_compress_ptr cinfo) {}
|
||||
|
||||
static boolean empty_output_buffer(j_compress_ptr cinfo) {
|
||||
auto dest = reinterpret_cast<MemoryDestinationManager*>(cinfo->dest);
|
||||
auto* dest = reinterpret_cast<MemoryDestinationManager*>(cinfo->dest);
|
||||
uint8_t* next_buffer =
|
||||
reinterpret_cast<uint8_t*>(malloc(dest->buffer_size * 2));
|
||||
memcpy(next_buffer, dest->current_buffer, dest->buffer_size);
|
||||
|
@ -80,7 +80,7 @@ struct MemoryDestinationManager {
|
|||
}
|
||||
|
||||
static void term_destination(j_compress_ptr cinfo) {
|
||||
auto dest = reinterpret_cast<MemoryDestinationManager*>(cinfo->dest);
|
||||
auto* dest = reinterpret_cast<MemoryDestinationManager*>(cinfo->dest);
|
||||
*dest->output_size = dest->buffer_size - dest->pub.free_in_buffer;
|
||||
}
|
||||
};
|
||||
|
@ -99,7 +99,7 @@ void jpegli_stdio_dest(j_compress_ptr cinfo, FILE* outfile) {
|
|||
cinfo->dest = reinterpret_cast<jpeg_destination_mgr*>(
|
||||
jpegli::Allocate<jpegli::StdioDestinationManager>(cinfo, 1));
|
||||
}
|
||||
auto dest = reinterpret_cast<jpegli::StdioDestinationManager*>(cinfo->dest);
|
||||
auto* dest = reinterpret_cast<jpegli::StdioDestinationManager*>(cinfo->dest);
|
||||
dest->f = outfile;
|
||||
dest->buffer = jpegli::Allocate<uint8_t>(cinfo, jpegli::kDestBufferSize);
|
||||
dest->pub.next_output_byte = dest->buffer;
|
||||
|
@ -122,11 +122,11 @@ void jpegli_mem_dest(j_compress_ptr cinfo, unsigned char** outbuffer,
|
|||
JPEGLI_ERROR("jpegli_mem_dest: a different dest manager was already set");
|
||||
}
|
||||
if (!cinfo->dest) {
|
||||
auto dest = jpegli::Allocate<jpegli::MemoryDestinationManager>(cinfo, 1);
|
||||
auto* dest = jpegli::Allocate<jpegli::MemoryDestinationManager>(cinfo, 1);
|
||||
dest->temp_buffer = nullptr;
|
||||
cinfo->dest = reinterpret_cast<jpeg_destination_mgr*>(dest);
|
||||
}
|
||||
auto dest = reinterpret_cast<jpegli::MemoryDestinationManager*>(cinfo->dest);
|
||||
auto* dest = reinterpret_cast<jpegli::MemoryDestinationManager*>(cinfo->dest);
|
||||
dest->pub.init_destination =
|
||||
jpegli::MemoryDestinationManager::init_destination;
|
||||
dest->pub.empty_output_buffer =
|
||||
|
|
|
@ -29,7 +29,7 @@ void DownsampleRow2x1(const float* row_in, size_t len, float* row_out) {
|
|||
const size_t N = Lanes(d);
|
||||
const size_t len_out = len / 2;
|
||||
const auto mul = Set(d, 0.5f);
|
||||
Vec<D> v0, v1;
|
||||
Vec<D> v0, v1; // NOLINT
|
||||
for (size_t x = 0; x < len_out; x += N) {
|
||||
LoadInterleaved2(d, row_in + 2 * x, v0, v1);
|
||||
Store(Mul(mul, Add(v0, v1)), d, row_out + x);
|
||||
|
@ -40,7 +40,7 @@ void DownsampleRow3x1(const float* row_in, size_t len, float* row_out) {
|
|||
const size_t N = Lanes(d);
|
||||
const size_t len_out = len / 3;
|
||||
const auto mul = Set(d, 1.0f / 3);
|
||||
Vec<D> v0, v1, v2;
|
||||
Vec<D> v0, v1, v2; // NOLINT
|
||||
for (size_t x = 0; x < len_out; x += N) {
|
||||
LoadInterleaved3(d, row_in + 3 * x, v0, v1, v2);
|
||||
Store(Mul(mul, Add(Add(v0, v1), v2)), d, row_out + x);
|
||||
|
@ -51,7 +51,7 @@ void DownsampleRow4x1(const float* row_in, size_t len, float* row_out) {
|
|||
const size_t N = Lanes(d);
|
||||
const size_t len_out = len / 4;
|
||||
const auto mul = Set(d, 0.25f);
|
||||
Vec<D> v0, v1, v2, v3;
|
||||
Vec<D> v0, v1, v2, v3; // NOLINT
|
||||
for (size_t x = 0; x < len_out; x += N) {
|
||||
LoadInterleaved4(d, row_in + 4 * x, v0, v1, v2, v3);
|
||||
Store(Mul(mul, Add(Add(v0, v1), Add(v2, v3))), d, row_out + x);
|
||||
|
@ -91,7 +91,7 @@ void Downsample2x2(float* rows_in[MAX_SAMP_FACTOR], size_t len,
|
|||
const auto mul = Set(d, 0.25f);
|
||||
float* row0 = rows_in[0];
|
||||
float* row1 = rows_in[1];
|
||||
Vec<D> v0, v1, v2, v3;
|
||||
Vec<D> v0, v1, v2, v3; // NOLINT
|
||||
for (size_t x = 0; x < len_out; x += N) {
|
||||
LoadInterleaved2(d, row0 + 2 * x, v0, v1);
|
||||
LoadInterleaved2(d, row1 + 2 * x, v2, v3);
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include "lib/jpegli/encode.h"
|
||||
|
||||
#include <jxl/types.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <initializer_list>
|
||||
#include <vector>
|
||||
|
@ -323,8 +325,8 @@ void ProcessCompressionParams(j_compress_ptr cinfo) {
|
|||
if (cinfo->scan_info == nullptr) {
|
||||
SetDefaultScanScript(cinfo);
|
||||
}
|
||||
cinfo->progressive_mode =
|
||||
cinfo->scan_info->Ss != 0 || cinfo->scan_info->Se != DCTSIZE2 - 1;
|
||||
cinfo->progressive_mode = TO_JXL_BOOL(cinfo->scan_info->Ss != 0 ||
|
||||
cinfo->scan_info->Se != DCTSIZE2 - 1);
|
||||
ValidateScanScript(cinfo);
|
||||
m->scan_token_info =
|
||||
Allocate<ScanTokenInfo>(cinfo, cinfo->num_scans, JPOOL_IMAGE);
|
||||
|
@ -449,7 +451,7 @@ void AllocateBuffers(j_compress_ptr cinfo) {
|
|||
const size_t ysize_blocks = comp->height_in_blocks;
|
||||
m->coeff_buffers[c] = (*cinfo->mem->request_virt_barray)(
|
||||
reinterpret_cast<j_common_ptr>(cinfo), JPOOL_IMAGE,
|
||||
/*pre_zero=*/false, xsize_blocks, ysize_blocks, comp->v_samp_factor);
|
||||
/*pre_zero=*/FALSE, xsize_blocks, ysize_blocks, comp->v_samp_factor);
|
||||
}
|
||||
}
|
||||
if (m->use_adaptive_quantization) {
|
||||
|
@ -663,8 +665,8 @@ void jpegli_CreateCompress(j_compress_ptr cinfo, int version,
|
|||
cinfo->num_components = 0;
|
||||
cinfo->jpeg_color_space = JCS_UNKNOWN;
|
||||
cinfo->comp_info = nullptr;
|
||||
for (int i = 0; i < NUM_QUANT_TBLS; ++i) {
|
||||
cinfo->quant_tbl_ptrs[i] = nullptr;
|
||||
for (auto& quant_tbl_ptr : cinfo->quant_tbl_ptrs) {
|
||||
quant_tbl_ptr = nullptr;
|
||||
}
|
||||
for (int i = 0; i < NUM_HUFF_TBLS; ++i) {
|
||||
cinfo->dc_huff_tbl_ptrs[i] = nullptr;
|
||||
|
@ -673,7 +675,7 @@ void jpegli_CreateCompress(j_compress_ptr cinfo, int version,
|
|||
memset(cinfo->arith_dc_L, 0, sizeof(cinfo->arith_dc_L));
|
||||
memset(cinfo->arith_dc_U, 0, sizeof(cinfo->arith_dc_U));
|
||||
memset(cinfo->arith_ac_K, 0, sizeof(cinfo->arith_ac_K));
|
||||
cinfo->write_Adobe_marker = false;
|
||||
cinfo->write_Adobe_marker = FALSE;
|
||||
cinfo->master = jpegli::Allocate<jpeg_comp_master>(cinfo, 1);
|
||||
jpegli::InitializeCompressParams(cinfo);
|
||||
cinfo->master->force_baseline = true;
|
||||
|
@ -763,7 +765,7 @@ void jpegli_set_colorspace(j_compress_ptr cinfo, J_COLOR_SPACE colorspace) {
|
|||
JPEGLI_ERROR("Unsupported jpeg colorspace %d", colorspace);
|
||||
}
|
||||
// Adobe marker is only needed to distinguish CMYK and YCCK JPEGs.
|
||||
cinfo->write_Adobe_marker = (cinfo->jpeg_color_space == JCS_YCCK);
|
||||
cinfo->write_Adobe_marker = TO_JXL_BOOL(cinfo->jpeg_color_space == JCS_YCCK);
|
||||
if (cinfo->comp_info == nullptr) {
|
||||
cinfo->comp_info =
|
||||
jpegli::Allocate<jpeg_component_info>(cinfo, MAX_COMPONENTS);
|
||||
|
@ -810,7 +812,7 @@ void jpegli_set_colorspace(j_compress_ptr cinfo, J_COLOR_SPACE colorspace) {
|
|||
void jpegli_set_distance(j_compress_ptr cinfo, float distance,
|
||||
boolean force_baseline) {
|
||||
CheckState(cinfo, jpegli::kEncStart);
|
||||
cinfo->master->force_baseline = force_baseline;
|
||||
cinfo->master->force_baseline = FROM_JXL_BOOL(force_baseline);
|
||||
float distances[NUM_QUANT_TBLS] = {distance, distance, distance};
|
||||
jpegli::SetQuantMatrices(cinfo, distances, /*add_two_chroma_tables=*/true);
|
||||
}
|
||||
|
@ -834,7 +836,7 @@ void jpegli_set_psnr(j_compress_ptr cinfo, float psnr, float tolerance,
|
|||
void jpegli_set_quality(j_compress_ptr cinfo, int quality,
|
||||
boolean force_baseline) {
|
||||
CheckState(cinfo, jpegli::kEncStart);
|
||||
cinfo->master->force_baseline = force_baseline;
|
||||
cinfo->master->force_baseline = FROM_JXL_BOOL(force_baseline);
|
||||
float distance = jpegli_quality_to_distance(quality);
|
||||
float distances[NUM_QUANT_TBLS] = {distance, distance, distance};
|
||||
jpegli::SetQuantMatrices(cinfo, distances, /*add_two_chroma_tables=*/false);
|
||||
|
@ -843,7 +845,7 @@ void jpegli_set_quality(j_compress_ptr cinfo, int quality,
|
|||
void jpegli_set_linear_quality(j_compress_ptr cinfo, int scale_factor,
|
||||
boolean force_baseline) {
|
||||
CheckState(cinfo, jpegli::kEncStart);
|
||||
cinfo->master->force_baseline = force_baseline;
|
||||
cinfo->master->force_baseline = FROM_JXL_BOOL(force_baseline);
|
||||
float distance = jpegli::LinearQualityToDistance(scale_factor);
|
||||
float distances[NUM_QUANT_TBLS] = {distance, distance, distance};
|
||||
jpegli::SetQuantMatrices(cinfo, distances, /*add_two_chroma_tables=*/false);
|
||||
|
@ -894,7 +896,7 @@ void jpegli_add_quant_table(j_compress_ptr cinfo, int which_tbl,
|
|||
|
||||
void jpegli_enable_adaptive_quantization(j_compress_ptr cinfo, boolean value) {
|
||||
CheckState(cinfo, jpegli::kEncStart);
|
||||
cinfo->master->use_adaptive_quantization = value;
|
||||
cinfo->master->use_adaptive_quantization = FROM_JXL_BOOL(value);
|
||||
}
|
||||
|
||||
void jpegli_simple_progression(j_compress_ptr cinfo) {
|
||||
|
@ -955,7 +957,7 @@ void jpegli_copy_critical_parameters(j_decompress_ptr srcinfo,
|
|||
jpegli_set_colorspace(dstinfo, srcinfo->jpeg_color_space);
|
||||
if (dstinfo->num_components != srcinfo->num_components) {
|
||||
const auto& cinfo = dstinfo;
|
||||
return JPEGLI_ERROR("Mismatch between src colorspace and components");
|
||||
JPEGLI_ERROR("Mismatch between src colorspace and components");
|
||||
}
|
||||
dstinfo->data_precision = srcinfo->data_precision;
|
||||
dstinfo->CCIR601_sampling = srcinfo->CCIR601_sampling;
|
||||
|
@ -1005,7 +1007,7 @@ void jpegli_write_coefficients(j_compress_ptr cinfo,
|
|||
jvirt_barray_ptr* coef_arrays) {
|
||||
CheckState(cinfo, jpegli::kEncStart);
|
||||
cinfo->global_state = jpegli::kEncWriteCoeffs;
|
||||
jpegli::InitCompress(cinfo, /*write_all_tables=*/true);
|
||||
jpegli::InitCompress(cinfo, /*write_all_tables=*/TRUE);
|
||||
cinfo->master->coeff_buffers = coef_arrays;
|
||||
cinfo->next_scanline = cinfo->image_height;
|
||||
cinfo->master->next_input_row = cinfo->image_height;
|
||||
|
@ -1047,7 +1049,7 @@ void jpegli_write_m_header(j_compress_ptr cinfo, int marker,
|
|||
marker_data[1] = marker;
|
||||
marker_data[2] = (datalen + 2) >> 8;
|
||||
marker_data[3] = (datalen + 2) & 0xff;
|
||||
jpegli::WriteOutput(cinfo, &marker_data[0], 4);
|
||||
jpegli::WriteOutput(cinfo, marker_data.data(), 4);
|
||||
}
|
||||
|
||||
void jpegli_write_m_byte(j_compress_ptr cinfo, int val) {
|
||||
|
@ -1213,7 +1215,8 @@ void jpegli_finish_compress(j_compress_ptr cinfo) {
|
|||
}
|
||||
|
||||
const bool tokens_done = jpegli::IsStreamingSupported(cinfo);
|
||||
const bool bitstream_done = tokens_done && !cinfo->optimize_coding;
|
||||
const bool bitstream_done =
|
||||
tokens_done && !FROM_JXL_BOOL(cinfo->optimize_coding);
|
||||
|
||||
if (!tokens_done) {
|
||||
jpegli::TokenizeJpeg(cinfo);
|
||||
|
|
|
@ -133,12 +133,11 @@ TEST(EncodeAPITest, ReuseCinfoSameMemOutput) {
|
|||
jpegli_destroy_compress(&cinfo);
|
||||
}
|
||||
size_t pos = 0;
|
||||
for (size_t i = 0; i < all_configs.size(); ++i) {
|
||||
for (auto& config : all_configs) {
|
||||
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);
|
||||
pos += DecodeWithLibjpeg(config.jparams, DecompressParams(), nullptr, 0,
|
||||
buffer + pos, buffer_size - pos, &output);
|
||||
VerifyOutputImage(config.input, output, config.max_dist);
|
||||
}
|
||||
if (buffer) free(buffer);
|
||||
}
|
||||
|
@ -164,20 +163,21 @@ TEST(EncodeAPITest, ReuseCinfoSameStdOutput) {
|
|||
size_t total_size = ftell(tmpf);
|
||||
rewind(tmpf);
|
||||
std::vector<uint8_t> compressed(total_size);
|
||||
JXL_CHECK(total_size == fread(&compressed[0], 1, total_size, tmpf));
|
||||
JXL_CHECK(total_size == fread(compressed.data(), 1, total_size, tmpf));
|
||||
fclose(tmpf);
|
||||
size_t pos = 0;
|
||||
for (size_t i = 0; i < all_configs.size(); ++i) {
|
||||
for (auto& config : all_configs) {
|
||||
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);
|
||||
pos +=
|
||||
DecodeWithLibjpeg(config.jparams, DecompressParams(), nullptr, 0,
|
||||
&compressed[pos], compressed.size() - pos, &output);
|
||||
VerifyOutputImage(config.input, output, config.max_dist);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EncodeAPITest, ReuseCinfoChangeParams) {
|
||||
TestImage input, output;
|
||||
TestImage input;
|
||||
TestImage output;
|
||||
CompressParams jparams;
|
||||
DecompressParams dparams;
|
||||
uint8_t* buffer = nullptr;
|
||||
|
|
|
@ -213,6 +213,8 @@ float FindDistanceForPSNR(j_compress_ptr cinfo) {
|
|||
d = best_distance;
|
||||
if (sampling == 1 && PSNR_SEARCH_DBG) {
|
||||
printf("Final PSNR %.2f at distance %.4f\n", best_psnr, d);
|
||||
} else {
|
||||
(void)best_psnr;
|
||||
}
|
||||
}
|
||||
return d;
|
||||
|
|
|
@ -99,10 +99,16 @@ void TokenizeACProgressiveScan(j_compress_ptr cinfo, int scan_index,
|
|||
TokenArray* ta = &m->token_arrays[m->cur_token_array];
|
||||
sti->token_offset = m->total_num_tokens + ta->num_tokens;
|
||||
sti->restarts = Allocate<size_t>(cinfo, num_restarts, JPOOL_IMAGE);
|
||||
const auto emit_eob_run = [&]() {
|
||||
int nbits = jxl::FloorLog2Nonzero<uint32_t>(eob_run);
|
||||
int symbol = nbits << 4u;
|
||||
*m->next_token++ = Token(context, symbol, eob_run & ((1 << nbits) - 1));
|
||||
eob_run = 0;
|
||||
};
|
||||
for (JDIMENSION by = 0; by < comp->height_in_blocks; ++by) {
|
||||
JBLOCKARRAY ba = (*cinfo->mem->access_virt_barray)(
|
||||
reinterpret_cast<j_common_ptr>(cinfo), m->coeff_buffers[comp_idx], by,
|
||||
1, false);
|
||||
1, FALSE);
|
||||
// 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.
|
||||
|
@ -121,13 +127,7 @@ void TokenizeACProgressiveScan(j_compress_ptr cinfo, int scan_index,
|
|||
}
|
||||
for (JDIMENSION bx = 0; bx < comp->width_in_blocks; ++bx) {
|
||||
if (restart_interval > 0 && restarts_to_go == 0) {
|
||||
if (eob_run > 0) {
|
||||
int nbits = jxl::FloorLog2Nonzero<uint32_t>(eob_run);
|
||||
int symbol = nbits << 4u;
|
||||
*m->next_token++ =
|
||||
Token(context, symbol, eob_run & ((1 << nbits) - 1));
|
||||
eob_run = 0;
|
||||
}
|
||||
if (eob_run > 0) emit_eob_run();
|
||||
ta->num_tokens = m->next_token - ta->tokens;
|
||||
sti->restarts[restart_idx++] = m->total_num_tokens + ta->num_tokens;
|
||||
restarts_to_go = restart_interval;
|
||||
|
@ -139,7 +139,8 @@ void TokenizeACProgressiveScan(j_compress_ptr cinfo, int scan_index,
|
|||
int num_nzeros = 0;
|
||||
int num_future_nzeros = 0;
|
||||
for (int k = Ss; k <= Se; ++k) {
|
||||
if ((temp = block[k]) == 0) {
|
||||
temp = block[k];
|
||||
if (temp == 0) {
|
||||
r++;
|
||||
continue;
|
||||
}
|
||||
|
@ -156,13 +157,7 @@ void TokenizeACProgressiveScan(j_compress_ptr cinfo, int scan_index,
|
|||
num_future_nzeros++;
|
||||
continue;
|
||||
}
|
||||
if (eob_run > 0) {
|
||||
int nbits = jxl::FloorLog2Nonzero<uint32_t>(eob_run);
|
||||
int symbol = nbits << 4u;
|
||||
*m->next_token++ =
|
||||
Token(context, symbol, eob_run & ((1 << nbits) - 1));
|
||||
eob_run = 0;
|
||||
}
|
||||
if (eob_run > 0) emit_eob_run();
|
||||
while (r > 15) {
|
||||
*m->next_token++ = Token(context, 0xf0, 0);
|
||||
r -= 16;
|
||||
|
@ -175,13 +170,7 @@ void TokenizeACProgressiveScan(j_compress_ptr cinfo, int scan_index,
|
|||
}
|
||||
if (r > 0) {
|
||||
++eob_run;
|
||||
if (eob_run == 0x7FFF) {
|
||||
int nbits = jxl::FloorLog2Nonzero<uint32_t>(eob_run);
|
||||
int symbol = nbits << 4u;
|
||||
*m->next_token++ =
|
||||
Token(context, symbol, eob_run & ((1 << nbits) - 1));
|
||||
eob_run = 0;
|
||||
}
|
||||
if (eob_run == 0x7FFF) emit_eob_run();
|
||||
}
|
||||
sti->num_nonzeros += num_nzeros;
|
||||
sti->num_future_nonzeros += num_future_nzeros;
|
||||
|
@ -190,11 +179,8 @@ void TokenizeACProgressiveScan(j_compress_ptr cinfo, int scan_index,
|
|||
ta->num_tokens = m->next_token - ta->tokens;
|
||||
}
|
||||
if (eob_run > 0) {
|
||||
int nbits = jxl::FloorLog2Nonzero<uint32_t>(eob_run);
|
||||
int symbol = nbits << 4u;
|
||||
*m->next_token++ = Token(context, symbol, eob_run & ((1 << nbits) - 1));
|
||||
emit_eob_run();
|
||||
++ta->num_tokens;
|
||||
eob_run = 0;
|
||||
}
|
||||
sti->num_tokens = m->total_num_tokens + ta->num_tokens - sti->token_offset;
|
||||
sti->restarts[restart_idx++] = m->total_num_tokens + ta->num_tokens;
|
||||
|
@ -229,7 +215,7 @@ void TokenizeACRefinementScan(j_compress_ptr cinfo, int scan_index,
|
|||
for (JDIMENSION by = 0; by < comp->height_in_blocks; ++by) {
|
||||
JBLOCKARRAY ba = (*cinfo->mem->access_virt_barray)(
|
||||
reinterpret_cast<j_common_ptr>(cinfo), m->coeff_buffers[comp_idx], by,
|
||||
1, false);
|
||||
1, FALSE);
|
||||
for (JDIMENSION bx = 0; bx < comp->width_in_blocks; ++bx) {
|
||||
if (restart_interval > 0 && restarts_to_go == 0) {
|
||||
sti->restarts[restart_idx++] = next_token - sti->tokens;
|
||||
|
@ -337,7 +323,7 @@ void TokenizeScan(j_compress_ptr cinfo, size_t scan_index, int ac_ctx_offset,
|
|||
// "Non-interleaved" means color data comes in separate scans, in other words
|
||||
// each scan can contain only one color component.
|
||||
const bool is_interleaved = (scan_info->comps_in_scan > 1);
|
||||
const bool is_progressive = cinfo->progressive_mode;
|
||||
const bool is_progressive = FROM_JXL_BOOL(cinfo->progressive_mode);
|
||||
const int Ah = scan_info->Ah;
|
||||
const int Al = scan_info->Al;
|
||||
HWY_ALIGN constexpr coeff_t kSinkBlock[DCTSIZE2] = {0};
|
||||
|
@ -373,7 +359,7 @@ void TokenizeScan(j_compress_ptr cinfo, size_t scan_index, int ac_ctx_offset,
|
|||
int max_block_rows = std::min(n_blocks_y, block_rows_left);
|
||||
ba[i] = (*cinfo->mem->access_virt_barray)(
|
||||
reinterpret_cast<j_common_ptr>(cinfo), m->coeff_buffers[comp_idx],
|
||||
by0, max_block_rows, false);
|
||||
by0, max_block_rows, FALSE);
|
||||
}
|
||||
if (!cinfo->progressive_mode) {
|
||||
int max_tokens_per_mcu_row = MaxNumTokensPerMCURow(cinfo);
|
||||
|
@ -557,7 +543,7 @@ float HistogramCost(const Histogram& histo) {
|
|||
}
|
||||
counts[kJpegHuffmanAlphabetSize] = 1;
|
||||
CreateHuffmanTree(counts.data(), counts.size(), kJpegHuffmanMaxBitLength,
|
||||
&depths[0]);
|
||||
depths.data());
|
||||
size_t header_bits = (1 + kJpegHuffmanMaxBitLength) * 8;
|
||||
size_t data_bits = 0;
|
||||
for (size_t i = 0; i < kJpegHuffmanAlphabetSize; ++i) {
|
||||
|
@ -576,8 +562,8 @@ void AddHistograms(const Histogram& a, const Histogram& b, Histogram* c) {
|
|||
}
|
||||
|
||||
bool IsEmptyHistogram(const Histogram& histo) {
|
||||
for (size_t i = 0; i < kJpegHuffmanAlphabetSize; ++i) {
|
||||
if (histo.count[i]) return false;
|
||||
for (int count : histo.count) {
|
||||
if (count) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -668,7 +654,7 @@ void BuildJpegHuffmanTable(const Histogram& histo, JHUFF_TBL* table) {
|
|||
}
|
||||
counts[kJpegHuffmanAlphabetSize] = 1;
|
||||
CreateHuffmanTree(counts.data(), counts.size(), kJpegHuffmanMaxBitLength,
|
||||
&depths[0]);
|
||||
depths.data());
|
||||
memset(table, 0, sizeof(JHUFF_TBL));
|
||||
for (size_t i = 0; i < kJpegHuffmanAlphabetSize; ++i) {
|
||||
if (depths[i] > 0) {
|
||||
|
@ -726,7 +712,7 @@ void OptimizeHuffmanCodes(j_compress_ptr cinfo) {
|
|||
jpeg_comp_master* m = cinfo->master;
|
||||
// Build DC and AC histograms.
|
||||
std::vector<Histogram> histograms(m->num_contexts);
|
||||
BuildHistograms(cinfo, &histograms[0]);
|
||||
BuildHistograms(cinfo, histograms.data());
|
||||
|
||||
// Cluster DC histograms.
|
||||
JpegClusteredHistograms dc_clusters;
|
||||
|
@ -760,7 +746,7 @@ void OptimizeHuffmanCodes(j_compress_ptr cinfo) {
|
|||
m->context_map = Allocate<uint8_t>(cinfo, m->num_contexts, JPOOL_IMAGE);
|
||||
memset(m->context_map, 0, m->num_contexts);
|
||||
for (size_t i = 0; i < m->num_contexts; ++i) {
|
||||
if (i < (size_t)cinfo->num_components) {
|
||||
if (i < static_cast<size_t>(cinfo->num_components)) {
|
||||
m->context_map[i] = dc_clusters.histogram_indexes[i];
|
||||
} else if (i >= 4) {
|
||||
m->context_map[i] = num_dc_huff + ac_clusters.histogram_indexes[i - 4];
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include "lib/jpegli/common.h"
|
||||
#include "lib/jxl/base/status.h"
|
||||
|
||||
namespace jpegli {
|
||||
|
||||
|
@ -17,10 +18,12 @@ bool FormatString(char* buffer, const char* format, ...);
|
|||
|
||||
} // namespace jpegli
|
||||
|
||||
// `error_exit` should be no-return; but let's add some guarantees on our side.
|
||||
#define JPEGLI_ERROR(format, ...) \
|
||||
jpegli::FormatString(cinfo->err->msg_parm.s, ("%s:%d: " format), __FILE__, \
|
||||
__LINE__, ##__VA_ARGS__), \
|
||||
(*cinfo->err->error_exit)(reinterpret_cast<j_common_ptr>(cinfo))
|
||||
(*cinfo->err->error_exit)(reinterpret_cast<j_common_ptr>(cinfo)), \
|
||||
(void)jxl::Abort()
|
||||
|
||||
#define JPEGLI_WARN(format, ...) \
|
||||
jpegli::FormatString(cinfo->err->msg_parm.s, ("%s:%d: " format), __FILE__, \
|
||||
|
|
|
@ -241,9 +241,10 @@ TEST(EncoderErrorHandlingTest, InvalidQuantValue) {
|
|||
cinfo.image_height = 1;
|
||||
cinfo.input_components = 1;
|
||||
jpegli_set_defaults(&cinfo);
|
||||
cinfo.quant_tbl_ptrs[0] = jpegli_alloc_quant_table((j_common_ptr)&cinfo);
|
||||
for (size_t k = 0; k < DCTSIZE2; ++k) {
|
||||
cinfo.quant_tbl_ptrs[0]->quantval[k] = 0;
|
||||
cinfo.quant_tbl_ptrs[0] =
|
||||
jpegli_alloc_quant_table(reinterpret_cast<j_common_ptr>(&cinfo));
|
||||
for (UINT16& q : cinfo.quant_tbl_ptrs[0]->quantval) {
|
||||
q = 0;
|
||||
}
|
||||
jpegli_start_compress(&cinfo, TRUE);
|
||||
JSAMPLE image[1] = {0};
|
||||
|
@ -992,7 +993,7 @@ TEST(EncoderErrorHandlingTest, AddOnTableNoStringParam) {
|
|||
jpegli_destroy_compress(&cinfo);
|
||||
}
|
||||
|
||||
static const uint8_t kCompressed0[] = {
|
||||
const uint8_t kCompressed0[] = {
|
||||
// SOI
|
||||
0xff, 0xd8, //
|
||||
// DQT
|
||||
|
@ -1036,12 +1037,12 @@ static const uint8_t kCompressed0[] = {
|
|||
// EOI
|
||||
0xff, 0xd9, //
|
||||
};
|
||||
static const size_t kLen0 = sizeof(kCompressed0);
|
||||
const size_t kLen0 = sizeof(kCompressed0);
|
||||
|
||||
static const size_t kDQTOffset = 2;
|
||||
static const size_t kSOFOffset = 71;
|
||||
static const size_t kDHTOffset = 84;
|
||||
static const size_t kSOSOffset = 296;
|
||||
const size_t kDQTOffset = 2;
|
||||
const size_t kSOFOffset = 71;
|
||||
const size_t kDHTOffset = 84;
|
||||
const size_t kSOSOffset = 296;
|
||||
|
||||
TEST(DecoderErrorHandlingTest, MinimalSuccess) {
|
||||
JXL_CHECK(kCompressed0[kDQTOffset] == 0xff);
|
||||
|
@ -1130,7 +1131,7 @@ TEST(DecoderErrorHandlingTest, NoReadScanlines) {
|
|||
jpegli_destroy_decompress(&cinfo);
|
||||
}
|
||||
|
||||
static const size_t kMaxImageWidth = 0xffff;
|
||||
const size_t kMaxImageWidth = 0xffff;
|
||||
JSAMPLE kOutputBuffer[MAX_COMPONENTS * kMaxImageWidth];
|
||||
|
||||
bool ParseCompressed(const std::vector<uint8_t>& compressed) {
|
||||
|
|
|
@ -183,7 +183,8 @@ void CreateHuffmanTree(const uint32_t* data, const size_t length,
|
|||
size_t i = 0; // Points to the next leaf node.
|
||||
size_t j = n + 1; // Points to the next non-leaf node.
|
||||
for (size_t k = n - 1; k != 0; --k) {
|
||||
size_t left, right;
|
||||
size_t left;
|
||||
size_t right;
|
||||
if (tree[i].total_count <= tree[j].total_count) {
|
||||
left = i;
|
||||
++i;
|
||||
|
@ -210,7 +211,7 @@ void CreateHuffmanTree(const uint32_t* data, const size_t length,
|
|||
tree.push_back(sentinel);
|
||||
}
|
||||
JXL_DASSERT(tree.size() == 2 * n + 1);
|
||||
SetDepth(tree[2 * n - 1], &tree[0], depth, 0);
|
||||
SetDepth(tree[2 * n - 1], tree.data(), depth, 0);
|
||||
|
||||
// We need to pack the Huffman tree in tree_limit bits.
|
||||
// If this was not successful, add fake entities to the lowest values
|
||||
|
|
|
@ -197,7 +197,7 @@ void InverseTransformBlock8x8(const int16_t* JXL_RESTRICT qblock,
|
|||
|
||||
// Computes the N-point IDCT of in[], and stores the result in out[]. The in[]
|
||||
// array is at most 8 values long, values in[8:N-1] are assumed to be 0.
|
||||
void Compute1dIDCT(float* in, float* out, size_t N) {
|
||||
void Compute1dIDCT(const float* in, float* out, size_t N) {
|
||||
switch (N) {
|
||||
case 3: {
|
||||
static constexpr float kC3[3] = {
|
||||
|
@ -608,6 +608,9 @@ void Compute1dIDCT(float* in, float* out, size_t N) {
|
|||
out[8] = even7 - odd7;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
JXL_ABORT("Compute1dIDCT does not support N=%d", static_cast<int>(N));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ void ReadUint8RowInterleaved2(const uint8_t* row_in, size_t len,
|
|||
const size_t simd_len = len & (~(N - 1));
|
||||
float* JXL_RESTRICT const row0 = row_out[0];
|
||||
float* JXL_RESTRICT const row1 = row_out[1];
|
||||
Vec<DU8> out0, out1;
|
||||
Vec<DU8> out0, out1; // NOLINT
|
||||
for (size_t x = 0; x < simd_len; x += N) {
|
||||
LoadInterleaved2(du8, row_in + 2 * x, out0, out1);
|
||||
Store(ConvertTo(d, PromoteTo(du, out0)), d, row0 + x);
|
||||
|
@ -105,7 +105,7 @@ void ReadUint8RowInterleaved3(const uint8_t* row_in, size_t len,
|
|||
float* JXL_RESTRICT const row0 = row_out[0];
|
||||
float* JXL_RESTRICT const row1 = row_out[1];
|
||||
float* JXL_RESTRICT const row2 = row_out[2];
|
||||
Vec<DU8> out0, out1, out2;
|
||||
Vec<DU8> out0, out1, out2; // NOLINT
|
||||
for (size_t x = 0; x < simd_len; x += N) {
|
||||
LoadInterleaved3(du8, row_in + 3 * x, out0, out1, out2);
|
||||
Store(ConvertTo(d, PromoteTo(du, out0)), d, row0 + x);
|
||||
|
@ -123,7 +123,7 @@ void ReadUint8RowInterleaved4(const uint8_t* row_in, size_t len,
|
|||
float* JXL_RESTRICT const row1 = row_out[1];
|
||||
float* JXL_RESTRICT const row2 = row_out[2];
|
||||
float* JXL_RESTRICT const row3 = row_out[3];
|
||||
Vec<DU8> out0, out1, out2, out3;
|
||||
Vec<DU8> out0, out1, out2, out3; // NOLINT
|
||||
for (size_t x = 0; x < simd_len; x += N) {
|
||||
LoadInterleaved4(du8, row_in + 4 * x, out0, out1, out2, out3);
|
||||
Store(ConvertTo(d, PromoteTo(du, out0)), d, row0 + x);
|
||||
|
@ -158,7 +158,7 @@ void ReadUint16RowInterleaved2(const uint8_t* row_in, size_t len,
|
|||
reinterpret_cast<const uint16_t*>(row_in);
|
||||
float* JXL_RESTRICT const row0 = row_out[0];
|
||||
float* JXL_RESTRICT const row1 = row_out[1];
|
||||
Vec<DU16> out0, out1;
|
||||
Vec<DU16> out0, out1; // NOLINT
|
||||
for (size_t x = 0; x < simd_len; x += N) {
|
||||
LoadInterleaved2(du16, row + 2 * x, out0, out1);
|
||||
Store(Mul(mul, ConvertTo(d, PromoteTo(du, out0))), d, row0 + x);
|
||||
|
@ -177,7 +177,7 @@ void ReadUint16RowInterleaved3(const uint8_t* row_in, size_t len,
|
|||
float* JXL_RESTRICT const row0 = row_out[0];
|
||||
float* JXL_RESTRICT const row1 = row_out[1];
|
||||
float* JXL_RESTRICT const row2 = row_out[2];
|
||||
Vec<DU16> out0, out1, out2;
|
||||
Vec<DU16> out0, out1, out2; // NOLINT
|
||||
for (size_t x = 0; x < simd_len; x += N) {
|
||||
LoadInterleaved3(du16, row + 3 * x, out0, out1, out2);
|
||||
Store(Mul(mul, ConvertTo(d, PromoteTo(du, out0))), d, row0 + x);
|
||||
|
@ -198,7 +198,7 @@ void ReadUint16RowInterleaved4(const uint8_t* row_in, size_t len,
|
|||
float* JXL_RESTRICT const row1 = row_out[1];
|
||||
float* JXL_RESTRICT const row2 = row_out[2];
|
||||
float* JXL_RESTRICT const row3 = row_out[3];
|
||||
Vec<DU16> out0, out1, out2, out3;
|
||||
Vec<DU16> out0, out1, out2, out3; // NOLINT
|
||||
for (size_t x = 0; x < simd_len; x += N) {
|
||||
LoadInterleaved4(du16, row + 4 * x, out0, out1, out2, out3);
|
||||
Store(Mul(mul, ConvertTo(d, PromoteTo(du, out0))), d, row0 + x);
|
||||
|
@ -250,7 +250,7 @@ void ReadFloatRowInterleaved2(const uint8_t* row_in, size_t len,
|
|||
const float* JXL_RESTRICT const row = reinterpret_cast<const float*>(row_in);
|
||||
float* JXL_RESTRICT const row0 = row_out[0];
|
||||
float* JXL_RESTRICT const row1 = row_out[1];
|
||||
Vec<D> out0, out1;
|
||||
Vec<D> out0, out1; // NOLINT
|
||||
for (size_t x = 0; x < simd_len; x += N) {
|
||||
LoadInterleaved2(d, row + 2 * x, out0, out1);
|
||||
Store(Mul(mul, out0), d, row0 + x);
|
||||
|
@ -268,7 +268,7 @@ void ReadFloatRowInterleaved3(const uint8_t* row_in, size_t len,
|
|||
float* JXL_RESTRICT const row0 = row_out[0];
|
||||
float* JXL_RESTRICT const row1 = row_out[1];
|
||||
float* JXL_RESTRICT const row2 = row_out[2];
|
||||
Vec<D> out0, out1, out2;
|
||||
Vec<D> out0, out1, out2; // NOLINT
|
||||
for (size_t x = 0; x < simd_len; x += N) {
|
||||
LoadInterleaved3(d, row + 3 * x, out0, out1, out2);
|
||||
Store(Mul(mul, out0), d, row0 + x);
|
||||
|
@ -288,7 +288,7 @@ void ReadFloatRowInterleaved4(const uint8_t* row_in, size_t len,
|
|||
float* JXL_RESTRICT const row1 = row_out[1];
|
||||
float* JXL_RESTRICT const row2 = row_out[2];
|
||||
float* JXL_RESTRICT const row3 = row_out[3];
|
||||
Vec<D> out0, out1, out2, out3;
|
||||
Vec<D> out0, out1, out2, out3; // NOLINT
|
||||
for (size_t x = 0; x < simd_len; x += N) {
|
||||
LoadInterleaved4(d, row + 4 * x, out0, out1, out2, out3);
|
||||
Store(Mul(mul, out0), d, row0 + x);
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
namespace jpegli {
|
||||
namespace {
|
||||
|
||||
static constexpr uint8_t kFakeEoiMarker[2] = {0xff, 0xd9};
|
||||
constexpr uint8_t kFakeEoiMarker[2] = {0xff, 0xd9};
|
||||
|
||||
struct SourceManager {
|
||||
SourceManager(const uint8_t* data, size_t len, size_t max_chunk_size,
|
||||
|
@ -50,14 +50,14 @@ struct SourceManager {
|
|||
}
|
||||
if (pub_.bytes_in_buffer > 0) {
|
||||
EXPECT_LE(pub_.bytes_in_buffer, buffer_.size());
|
||||
memmove(&buffer_[0], pub_.next_input_byte, pub_.bytes_in_buffer);
|
||||
memmove(buffer_.data(), pub_.next_input_byte, pub_.bytes_in_buffer);
|
||||
}
|
||||
size_t chunk_size =
|
||||
pos_ < len_ ? std::min(len_ - pos_, max_chunk_size_) : 2;
|
||||
buffer_.resize(pub_.bytes_in_buffer + chunk_size);
|
||||
memcpy(&buffer_[pub_.bytes_in_buffer],
|
||||
pos_ < len_ ? data_ + pos_ : kFakeEoiMarker, chunk_size);
|
||||
pub_.next_input_byte = &buffer_[0];
|
||||
pub_.next_input_byte = buffer_.data();
|
||||
pub_.bytes_in_buffer += chunk_size;
|
||||
pos_ += chunk_size;
|
||||
return true;
|
||||
|
@ -73,7 +73,7 @@ struct SourceManager {
|
|||
bool is_partial_file_;
|
||||
|
||||
static void init_source(j_decompress_ptr cinfo) {
|
||||
auto src = reinterpret_cast<SourceManager*>(cinfo->src);
|
||||
auto* src = reinterpret_cast<SourceManager*>(cinfo->src);
|
||||
src->pub_.next_input_byte = nullptr;
|
||||
src->pub_.bytes_in_buffer = 0;
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ struct SourceManager {
|
|||
static boolean fill_input_buffer(j_decompress_ptr cinfo) { return FALSE; }
|
||||
|
||||
static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
|
||||
auto src = reinterpret_cast<SourceManager*>(cinfo->src);
|
||||
auto* src = reinterpret_cast<SourceManager*>(cinfo->src);
|
||||
if (num_bytes <= 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -156,10 +156,10 @@ void ReadOutputImage(const DecompressParams& dparams, j_decompress_ptr cinfo,
|
|||
rowdata[c][i] =
|
||||
y0 + i < ysize ? &output->raw_data[c][(y0 + i) * xsize] : nullptr;
|
||||
}
|
||||
data[c] = &rowdata[c][0];
|
||||
data[c] = rowdata[c].data();
|
||||
}
|
||||
while ((num_output_lines =
|
||||
jpegli_read_raw_data(cinfo, &data[0], max_lines)) == 0) {
|
||||
jpegli_read_raw_data(cinfo, data.data(), max_lines)) == 0) {
|
||||
JXL_CHECK(src && src->LoadNextChunk());
|
||||
}
|
||||
} else {
|
||||
|
@ -173,7 +173,7 @@ void ReadOutputImage(const DecompressParams& dparams, j_decompress_ptr cinfo,
|
|||
size_t yidx = cinfo->output_scanline + i;
|
||||
scanlines[i] = &output->pixels[yidx * stride];
|
||||
}
|
||||
while ((num_output_lines = jpegli_read_scanlines(cinfo, &scanlines[0],
|
||||
while ((num_output_lines = jpegli_read_scanlines(cinfo, scanlines.data(),
|
||||
max_lines)) == 0) {
|
||||
JXL_CHECK(src && src->LoadNextChunk());
|
||||
}
|
||||
|
@ -197,7 +197,7 @@ struct TestConfig {
|
|||
|
||||
std::vector<uint8_t> GetTestJpegData(TestConfig& config) {
|
||||
if (!config.fn.empty()) {
|
||||
return ReadTestData(config.fn.c_str());
|
||||
return ReadTestData(config.fn);
|
||||
}
|
||||
GeneratePixels(&config.input);
|
||||
std::vector<uint8_t> compressed;
|
||||
|
@ -249,7 +249,7 @@ TEST_P(InputSuspensionTestParam, InputOutputLockStepNonBuffered) {
|
|||
EXPECT_EQ(0, memcmp(markers_seen, kMarkerSequence, num_markers_seen));
|
||||
}
|
||||
VerifyHeader(config.jparams, &cinfo);
|
||||
cinfo.raw_data_out = dparams.output_mode == RAW_DATA;
|
||||
cinfo.raw_data_out = TO_JXL_BOOL(dparams.output_mode == RAW_DATA);
|
||||
|
||||
if (dparams.output_mode == COEFFICIENTS) {
|
||||
jvirt_barray_ptr* coef_arrays;
|
||||
|
@ -303,7 +303,7 @@ TEST_P(InputSuspensionTestParam, InputOutputLockStepBuffered) {
|
|||
jpegli_set_output_format(&cinfo, dparams.data_type, dparams.endianness);
|
||||
|
||||
cinfo.buffered_image = TRUE;
|
||||
cinfo.raw_data_out = dparams.output_mode == RAW_DATA;
|
||||
cinfo.raw_data_out = TO_JXL_BOOL(dparams.output_mode == RAW_DATA);
|
||||
|
||||
EXPECT_TRUE(jpegli_start_decompress(&cinfo));
|
||||
EXPECT_FALSE(jpegli_input_complete(&cinfo));
|
||||
|
@ -380,8 +380,8 @@ TEST_P(InputSuspensionTestParam, PreConsumeInputBuffered) {
|
|||
}
|
||||
EXPECT_EQ(JPEG_REACHED_SOS, jpegli_consume_input(&cinfo));
|
||||
cinfo.buffered_image = TRUE;
|
||||
cinfo.raw_data_out = dparams.output_mode == RAW_DATA;
|
||||
cinfo.do_block_smoothing = dparams.do_block_smoothing;
|
||||
cinfo.raw_data_out = TO_JXL_BOOL(dparams.output_mode == RAW_DATA);
|
||||
cinfo.do_block_smoothing = TO_JXL_BOOL(dparams.do_block_smoothing);
|
||||
|
||||
EXPECT_TRUE(jpegli_start_decompress(&cinfo));
|
||||
EXPECT_FALSE(jpegli_input_complete(&cinfo));
|
||||
|
@ -446,8 +446,8 @@ TEST_P(InputSuspensionTestParam, PreConsumeInputNonBuffered) {
|
|||
}
|
||||
}
|
||||
EXPECT_EQ(JPEG_REACHED_SOS, jpegli_consume_input(&cinfo));
|
||||
cinfo.raw_data_out = dparams.output_mode == RAW_DATA;
|
||||
cinfo.do_block_smoothing = dparams.do_block_smoothing;
|
||||
cinfo.raw_data_out = TO_JXL_BOOL(dparams.output_mode == RAW_DATA);
|
||||
cinfo.do_block_smoothing = TO_JXL_BOOL(dparams.do_block_smoothing);
|
||||
|
||||
if (dparams.output_mode == COEFFICIENTS) {
|
||||
jpegli_read_coefficients(&cinfo);
|
||||
|
|
|
@ -37,12 +37,13 @@ void ReadOutputPass(j_decompress_ptr cinfo, const DecompressParams& dparams,
|
|||
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]));
|
||||
JSAMPLE** colormap = cinfo->colormap;
|
||||
jxl::msan::UnpoisonMemory(reinterpret_cast<void*>(colormap),
|
||||
cinfo->out_color_components * sizeof(JSAMPLE*));
|
||||
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]));
|
||||
reinterpret_cast<void*>(colormap[c]),
|
||||
cinfo->actual_number_of_colors * sizeof(JSAMPLE));
|
||||
}
|
||||
}
|
||||
if (!cinfo->raw_data_out) {
|
||||
|
@ -89,10 +90,10 @@ void ReadOutputPass(j_decompress_ptr cinfo, const DecompressParams& dparams,
|
|||
rowdata[c][i] =
|
||||
y0 + i < ysize ? &output->raw_data[c][(y0 + i) * xsize] : nullptr;
|
||||
}
|
||||
data[c] = &rowdata[c][0];
|
||||
data[c] = rowdata[c].data();
|
||||
}
|
||||
JXL_CHECK(iMCU_height ==
|
||||
jpeg_read_raw_data(cinfo, &data[0], iMCU_height));
|
||||
jpeg_read_raw_data(cinfo, data.data(), iMCU_height));
|
||||
}
|
||||
}
|
||||
JXL_CHECK(cinfo->total_iMCU_rows ==
|
||||
|
|
|
@ -122,11 +122,11 @@ boolean jpeg_read_icc_profile(j_decompress_ptr cinfo, JOCTET **icc_data_ptr,
|
|||
}
|
||||
|
||||
void jpeg_abort_decompress(j_decompress_ptr cinfo) {
|
||||
return jpegli_abort_decompress(cinfo);
|
||||
jpegli_abort_decompress(cinfo);
|
||||
}
|
||||
|
||||
void jpeg_destroy_decompress(j_decompress_ptr cinfo) {
|
||||
return jpegli_destroy_decompress(cinfo);
|
||||
jpegli_destroy_decompress(cinfo);
|
||||
}
|
||||
|
||||
void jpeg_CreateCompress(j_compress_ptr cinfo, int version, size_t structsize) {
|
||||
|
|
|
@ -19,7 +19,8 @@ void InitMemoryManager(j_common_ptr cinfo);
|
|||
|
||||
template <typename T>
|
||||
T* Allocate(j_common_ptr cinfo, size_t len, int pool_id = JPOOL_PERMANENT) {
|
||||
void* p = (*cinfo->mem->alloc_small)(cinfo, pool_id, len * sizeof(T));
|
||||
const size_t size = len * sizeof(T); // NOLINT
|
||||
void* p = (*cinfo->mem->alloc_small)(cinfo, pool_id, size);
|
||||
return reinterpret_cast<T*>(p);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
namespace jpegli {
|
||||
namespace {
|
||||
|
||||
static constexpr size_t kInitialBufferSize = 1024;
|
||||
static constexpr size_t kFinalBufferSize = 18;
|
||||
constexpr size_t kInitialBufferSize = 1024;
|
||||
constexpr size_t kFinalBufferSize = 18;
|
||||
|
||||
struct DestinationManager {
|
||||
jpeg_destination_mgr pub;
|
||||
|
@ -37,7 +37,7 @@ struct DestinationManager {
|
|||
}
|
||||
|
||||
static void init_destination(j_compress_ptr cinfo) {
|
||||
auto us = reinterpret_cast<DestinationManager*>(cinfo->dest);
|
||||
auto* us = reinterpret_cast<DestinationManager*>(cinfo->dest);
|
||||
us->buffer.resize(kInitialBufferSize);
|
||||
us->Rewind();
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ TEST_P(OutputSuspensionTestParam, PixelData) {
|
|||
while (cinfo.next_scanline < cinfo.image_height) {
|
||||
size_t lines_left = cinfo.image_height - cinfo.next_scanline;
|
||||
size_t num_lines = std::min(config.lines_batch_size, lines_left);
|
||||
memcpy(&row_bytes[0], &input.pixels[cinfo.next_scanline * stride],
|
||||
memcpy(row_bytes.data(), &input.pixels[cinfo.next_scanline * stride],
|
||||
num_lines * stride);
|
||||
std::vector<JSAMPROW> rows(num_lines);
|
||||
for (size_t i = 0; i < num_lines; ++i) {
|
||||
|
@ -142,7 +142,7 @@ TEST_P(OutputSuspensionTestParam, RawData) {
|
|||
std::vector<JSAMPARRAY> data(cinfo.num_components);
|
||||
for (int c = 0; c < cinfo.num_components; ++c) {
|
||||
rowdata[c].resize(config.jparams.v_samp(c) * DCTSIZE);
|
||||
data[c] = &rowdata[c][0];
|
||||
data[c] = rowdata[c].data();
|
||||
}
|
||||
while (cinfo.next_scanline < cinfo.image_height) {
|
||||
for (int c = 0; c < cinfo.num_components; ++c) {
|
||||
|
@ -155,7 +155,7 @@ TEST_P(OutputSuspensionTestParam, RawData) {
|
|||
(y0 + i < cheight ? &raw_data[c][(y0 + i) * cwidth] : nullptr);
|
||||
}
|
||||
}
|
||||
while (jpegli_write_raw_data(&cinfo, &data[0], max_lines) == 0) {
|
||||
while (jpegli_write_raw_data(&cinfo, data.data(), max_lines) == 0) {
|
||||
dest.EmptyTo(&compressed, config.buffer_size);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace {
|
|||
constexpr float kGlobalScaleXYB = 1.43951668f;
|
||||
constexpr float kGlobalScaleYCbCr = 1.73966010f;
|
||||
|
||||
static constexpr float kBaseQuantMatrixXYB[] = {
|
||||
constexpr float kBaseQuantMatrixXYB[] = {
|
||||
// c = 0
|
||||
7.5629935265f,
|
||||
19.8247814178f,
|
||||
|
@ -224,7 +224,7 @@ static constexpr float kBaseQuantMatrixXYB[] = {
|
|||
63.6065597534f,
|
||||
};
|
||||
|
||||
static const float kBaseQuantMatrixYCbCr[] = {
|
||||
const float kBaseQuantMatrixYCbCr[] = {
|
||||
// c = 0
|
||||
1.2397409345866273f, //
|
||||
1.7227115097630963f, //
|
||||
|
@ -422,8 +422,8 @@ static const float kBaseQuantMatrixYCbCr[] = {
|
|||
114.89202448569779f, //
|
||||
};
|
||||
|
||||
static const float k420GlobalScale = 1.22;
|
||||
static const float k420Rescale[64] = {
|
||||
const float k420GlobalScale = 1.22;
|
||||
const float k420Rescale[64] = {
|
||||
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, //
|
||||
|
@ -434,7 +434,7 @@ static const float k420Rescale[64] = {
|
|||
0.3354, 0.3445, 0.3484, 0.3839, 0.3836, 0.0726, 0.0553, 0.3368, //
|
||||
};
|
||||
|
||||
static const float kBaseQuantMatrixStd[] = {
|
||||
const float kBaseQuantMatrixStd[] = {
|
||||
// c = 0
|
||||
16.0f, 11.0f, 10.0f, 16.0f, 24.0f, 40.0f, 51.0f, 61.0f, //
|
||||
12.0f, 12.0f, 14.0f, 19.0f, 26.0f, 58.0f, 60.0f, 55.0f, //
|
||||
|
@ -455,7 +455,7 @@ static const float kBaseQuantMatrixStd[] = {
|
|||
99.0f, 99.0f, 99.0f, 99.0f, 99.0f, 99.0f, 99.0f, 99.0f, //
|
||||
};
|
||||
|
||||
static const float kZeroBiasMulYCbCrLQ[] = {
|
||||
const float kZeroBiasMulYCbCrLQ[] = {
|
||||
// c = 0
|
||||
0.0000f, 0.0568f, 0.3880f, 0.6190f, 0.6190f, 0.4490f, 0.4490f, 0.6187f, //
|
||||
0.0568f, 0.5829f, 0.6189f, 0.6190f, 0.6190f, 0.7190f, 0.6190f, 0.6189f, //
|
||||
|
@ -485,7 +485,7 @@ static const float kZeroBiasMulYCbCrLQ[] = {
|
|||
0.2960f, 0.2113f, 0.2426f, 0.1590f, 0.5403f, 0.3060f, 0.3060f, 0.3060f, //
|
||||
};
|
||||
|
||||
static const float kZeroBiasMulYCbCrHQ[] = {
|
||||
const float kZeroBiasMulYCbCrHQ[] = {
|
||||
// c = 0
|
||||
0.0000f, 0.0044f, 0.2521f, 0.6547f, 0.8161f, 0.6130f, 0.8841f, 0.8155f, //
|
||||
0.0044f, 0.6831f, 0.6553f, 0.6295f, 0.7848f, 0.7843f, 0.8474f, 0.7836f, //
|
||||
|
@ -515,9 +515,9 @@ static const float kZeroBiasMulYCbCrHQ[] = {
|
|||
0.4836f, 0.4897f, 0.2583f, 0.3565f, 0.5949f, 0.6629f, 0.6644f, 0.6644f, //
|
||||
};
|
||||
|
||||
static const float kZeroBiasOffsetYCbCrDC[] = {0.0f, 0.0f, 0.0f};
|
||||
const float kZeroBiasOffsetYCbCrDC[] = {0.0f, 0.0f, 0.0f};
|
||||
|
||||
static const float kZeroBiasOffsetYCbCrAC[] = {
|
||||
const float kZeroBiasOffsetYCbCrAC[] = {
|
||||
0.59082f,
|
||||
0.58146f,
|
||||
0.57988f,
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include <string.h>
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
@ -203,12 +202,13 @@ void WriteToOutput(j_decompress_ptr cinfo, float* JXL_RESTRICT rows[],
|
|||
if (cinfo->quantize_colors && m->quant_pass_ == 1) {
|
||||
float* error_row[kMaxComponents];
|
||||
float* next_error_row[kMaxComponents];
|
||||
if (cinfo->dither_mode == JDITHER_ORDERED) {
|
||||
J_DITHER_MODE dither_mode = cinfo->dither_mode;
|
||||
if (dither_mode == JDITHER_ORDERED) {
|
||||
for (size_t c = 0; c < num_channels; ++c) {
|
||||
DitherRow(cinfo, &rows[c][xoffset], c, cinfo->output_scanline,
|
||||
cinfo->output_width);
|
||||
}
|
||||
} else if (cinfo->dither_mode == JDITHER_FS) {
|
||||
} else if (dither_mode == JDITHER_FS) {
|
||||
for (size_t c = 0; c < num_channels; ++c) {
|
||||
if (cinfo->output_scanline % 2 == 0) {
|
||||
error_row[c] = m->error_row_[c];
|
||||
|
@ -221,12 +221,12 @@ void WriteToOutput(j_decompress_ptr cinfo, float* JXL_RESTRICT rows[],
|
|||
}
|
||||
}
|
||||
const float mul = 255.0f;
|
||||
if (cinfo->dither_mode != JDITHER_FS) {
|
||||
if (dither_mode != JDITHER_FS) {
|
||||
StoreUnsignedRow(rows, xoffset, len, num_channels, mul, scratch_space);
|
||||
}
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
uint8_t* pixel = &scratch_space[num_channels * i];
|
||||
if (cinfo->dither_mode == JDITHER_FS) {
|
||||
if (dither_mode == JDITHER_FS) {
|
||||
for (size_t c = 0; c < num_channels; ++c) {
|
||||
float val = rows[c][i] * mul + LimitError(error_row[c][i]);
|
||||
pixel[c] = std::round(std::min(255.0f, std::max(0.0f, val)));
|
||||
|
@ -234,7 +234,7 @@ void WriteToOutput(j_decompress_ptr cinfo, float* JXL_RESTRICT rows[],
|
|||
}
|
||||
int index = LookupColorIndex(cinfo, pixel);
|
||||
output[i] = index;
|
||||
if (cinfo->dither_mode == JDITHER_FS) {
|
||||
if (dither_mode == JDITHER_FS) {
|
||||
size_t prev_i = i > 0 ? i - 1 : 0;
|
||||
size_t next_i = i + 1 < len ? i + 1 : len - 1;
|
||||
for (size_t c = 0; c < num_channels; ++c) {
|
||||
|
@ -293,19 +293,18 @@ HWY_EXPORT(DecenterRow);
|
|||
void GatherBlockStats(const int16_t* JXL_RESTRICT coeffs,
|
||||
const size_t coeffs_size, int32_t* JXL_RESTRICT nonzeros,
|
||||
int32_t* JXL_RESTRICT sumabs) {
|
||||
return HWY_DYNAMIC_DISPATCH(GatherBlockStats)(coeffs, coeffs_size, nonzeros,
|
||||
sumabs);
|
||||
HWY_DYNAMIC_DISPATCH(GatherBlockStats)(coeffs, coeffs_size, nonzeros, sumabs);
|
||||
}
|
||||
|
||||
void WriteToOutput(j_decompress_ptr cinfo, float* JXL_RESTRICT rows[],
|
||||
size_t xoffset, size_t len, size_t num_channels,
|
||||
uint8_t* JXL_RESTRICT output) {
|
||||
return HWY_DYNAMIC_DISPATCH(WriteToOutput)(cinfo, rows, xoffset, len,
|
||||
num_channels, output);
|
||||
HWY_DYNAMIC_DISPATCH(WriteToOutput)
|
||||
(cinfo, rows, xoffset, len, num_channels, output);
|
||||
}
|
||||
|
||||
void DecenterRow(float* row, size_t xsize) {
|
||||
return HWY_DYNAMIC_DISPATCH(DecenterRow)(row, xsize);
|
||||
HWY_DYNAMIC_DISPATCH(DecenterRow)(row, xsize);
|
||||
}
|
||||
|
||||
bool ShouldApplyDequantBiases(j_decompress_ptr cinfo, int ci) {
|
||||
|
@ -360,8 +359,8 @@ bool do_smoothing(j_decompress_ptr cinfo) {
|
|||
if (!cinfo->progressive_mode || cinfo->coef_bits == nullptr) {
|
||||
return false;
|
||||
}
|
||||
auto coef_bits_latch = m->coef_bits_latch;
|
||||
auto prev_coef_bits_latch = m->prev_coef_bits_latch;
|
||||
auto* coef_bits_latch = m->coef_bits_latch;
|
||||
auto* prev_coef_bits_latch = m->prev_coef_bits_latch;
|
||||
|
||||
for (int ci = 0; ci < cinfo->num_components; ci++) {
|
||||
jpeg_component_info* compptr = &cinfo->comp_info[ci];
|
||||
|
@ -468,6 +467,7 @@ void PredictSmooth(j_decompress_ptr cinfo, JBLOCKARRAY blocks, int component,
|
|||
return swap_indices ? dc_values[j][i] : dc_values[i][j];
|
||||
};
|
||||
Al = coef_bits[coef_index];
|
||||
JXL_ASSERT(coef_index >= 0 && coef_index < 10);
|
||||
switch (coef_index) {
|
||||
case 0:
|
||||
// set the DC
|
||||
|
@ -520,6 +520,7 @@ void PredictSmooth(j_decompress_ptr cinfo, JBLOCKARRAY blocks, int component,
|
|||
break;
|
||||
case 7:
|
||||
case 8:
|
||||
default:
|
||||
// set Q12 and Q21
|
||||
num = (dc(1, 1) - 3 * dc(1, 2) + dc(1, 3) - dc(3, 1) + 3 * dc(3, 2) -
|
||||
dc(3, 3));
|
||||
|
@ -551,7 +552,7 @@ void PredictSmooth(j_decompress_ptr cinfo, JBLOCKARRAY blocks, int component,
|
|||
void PrepareForOutput(j_decompress_ptr cinfo) {
|
||||
jpeg_decomp_master* m = cinfo->master;
|
||||
bool smoothing = do_smoothing(cinfo);
|
||||
m->apply_smoothing = smoothing && cinfo->do_block_smoothing;
|
||||
m->apply_smoothing = smoothing && FROM_JXL_BOOL(cinfo->do_block_smoothing);
|
||||
size_t coeffs_per_block = cinfo->num_components * DCTSIZE2;
|
||||
memset(m->nonzeros_, 0, coeffs_per_block * sizeof(m->nonzeros_[0]));
|
||||
memset(m->sumabs_, 0, coeffs_per_block * sizeof(m->sumabs_[0]));
|
||||
|
@ -584,7 +585,7 @@ void DecodeCurrentiMCURow(j_decompress_ptr cinfo) {
|
|||
int offset = m->streaming_mode_ ? 0 : by0;
|
||||
ba[c] = (*cinfo->mem->access_virt_barray)(
|
||||
reinterpret_cast<j_common_ptr>(cinfo), m->coef_arrays[c], offset,
|
||||
max_block_rows, false);
|
||||
max_block_rows, FALSE);
|
||||
}
|
||||
for (int c = 0; c < cinfo->num_components; ++c) {
|
||||
size_t k0 = c * DCTSIZE2;
|
||||
|
|
|
@ -39,7 +39,7 @@ struct StdioSourceManager {
|
|||
uint8_t* buffer;
|
||||
|
||||
static boolean fill_input_buffer(j_decompress_ptr cinfo) {
|
||||
auto src = reinterpret_cast<StdioSourceManager*>(cinfo->src);
|
||||
auto* src = reinterpret_cast<StdioSourceManager*>(cinfo->src);
|
||||
size_t num_bytes_read = fread(src->buffer, 1, kStdioBufferSize, src->f);
|
||||
if (num_bytes_read == 0) {
|
||||
return EmitFakeEoiMarker(cinfo);
|
||||
|
@ -77,7 +77,7 @@ void jpegli_stdio_src(j_decompress_ptr cinfo, FILE* infile) {
|
|||
cinfo->src = reinterpret_cast<jpeg_source_mgr*>(
|
||||
jpegli::Allocate<jpegli::StdioSourceManager>(cinfo, 1));
|
||||
}
|
||||
auto src = reinterpret_cast<jpegli::StdioSourceManager*>(cinfo->src);
|
||||
auto* src = reinterpret_cast<jpegli::StdioSourceManager*>(cinfo->src);
|
||||
src->f = infile;
|
||||
src->buffer = jpegli::Allocate<uint8_t>(cinfo, jpegli::kStdioBufferSize);
|
||||
src->pub.next_input_byte = src->buffer;
|
||||
|
|
|
@ -50,7 +50,7 @@ FILE* MemOpen(const std::vector<uint8_t>& data) {
|
|||
|
||||
TEST_P(SourceManagerTestParam, TestStdioSourceManager) {
|
||||
TestConfig config = GetParam();
|
||||
std::vector<uint8_t> compressed = ReadTestData(config.fn.c_str());
|
||||
std::vector<uint8_t> compressed = ReadTestData(config.fn);
|
||||
if (config.dparams.size_factor < 1.0) {
|
||||
compressed.resize(compressed.size() * config.dparams.size_factor);
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ TEST_P(SourceManagerTestParam, TestStdioSourceManager) {
|
|||
|
||||
TEST_P(SourceManagerTestParam, TestMemSourceManager) {
|
||||
TestConfig config = GetParam();
|
||||
std::vector<uint8_t> compressed = ReadTestData(config.fn.c_str());
|
||||
std::vector<uint8_t> compressed = ReadTestData(config.fn);
|
||||
if (config.dparams.size_factor < 1.0f) {
|
||||
compressed.resize(compressed.size() * config.dparams.size_factor);
|
||||
}
|
||||
|
|
|
@ -36,13 +36,13 @@ struct SourceManager {
|
|||
// input buffer. The buffer size is kept short because empty_output_buffer() is
|
||||
// called only when the output buffer is full, and we want to update the decoder
|
||||
// input frequently to demonstrate that streaming works.
|
||||
static constexpr size_t kOutputBufferSize = 1024;
|
||||
constexpr size_t kOutputBufferSize = 1024;
|
||||
struct DestinationManager {
|
||||
jpeg_destination_mgr pub;
|
||||
std::vector<uint8_t> buffer;
|
||||
SourceManager* dest;
|
||||
|
||||
DestinationManager(SourceManager* src)
|
||||
explicit DestinationManager(SourceManager* src)
|
||||
: buffer(kOutputBufferSize), dest(src) {
|
||||
pub.next_output_byte = buffer.data();
|
||||
pub.free_in_buffer = buffer.size();
|
||||
|
@ -54,7 +54,7 @@ struct DestinationManager {
|
|||
static void init_destination(j_compress_ptr cinfo) {}
|
||||
|
||||
static boolean empty_output_buffer(j_compress_ptr cinfo) {
|
||||
auto us = reinterpret_cast<DestinationManager*>(cinfo->dest);
|
||||
auto* us = reinterpret_cast<DestinationManager*>(cinfo->dest);
|
||||
jpeg_destination_mgr* src = &us->pub;
|
||||
jpeg_source_mgr* dst = &us->dest->pub;
|
||||
std::vector<uint8_t>& src_buf = us->buffer;
|
||||
|
@ -69,7 +69,7 @@ struct DestinationManager {
|
|||
dst->bytes_in_buffer = dst_buf.size();
|
||||
src->next_output_byte = src_buf.data();
|
||||
src->free_in_buffer = src_buf.size();
|
||||
return true;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void term_destination(j_compress_ptr cinfo) {
|
||||
|
@ -87,6 +87,7 @@ class StreamingTestParam : public ::testing::TestWithParam<TestConfig> {};
|
|||
TEST_P(StreamingTestParam, TestStreaming) {
|
||||
jpeg_decompress_struct dinfo = {};
|
||||
jpeg_compress_struct cinfo = {};
|
||||
SourceManager src;
|
||||
TestConfig config = GetParam();
|
||||
TestImage& input = config.input;
|
||||
TestImage output;
|
||||
|
@ -99,7 +100,6 @@ TEST_P(StreamingTestParam, TestStreaming) {
|
|||
// compressor's output is connected to the decompressor's input.
|
||||
jpegli_create_decompress(&dinfo);
|
||||
jpegli_create_compress(&cinfo);
|
||||
SourceManager src;
|
||||
dinfo.src = reinterpret_cast<jpeg_source_mgr*>(&src);
|
||||
DestinationManager dest(&src);
|
||||
cinfo.dest = reinterpret_cast<jpeg_destination_mgr*>(&dest);
|
||||
|
@ -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 = (J_COLOR_SPACE)input.color_space;
|
||||
cinfo.in_color_space = static_cast<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);
|
||||
|
@ -122,13 +122,13 @@ TEST_P(StreamingTestParam, TestStreaming) {
|
|||
while (yin < cinfo.image_height) {
|
||||
// Feed one iMCU row at a time to the compressor.
|
||||
size_t lines_in = std::min(iMCU_height, cinfo.image_height - yin);
|
||||
memcpy(&row_bytes[0], &input.pixels[yin * stride], lines_in * stride);
|
||||
memcpy(row_bytes.data(), &input.pixels[yin * stride], lines_in * stride);
|
||||
std::vector<JSAMPROW> rows_in(lines_in);
|
||||
for (size_t i = 0; i < lines_in; ++i) {
|
||||
rows_in[i] = &row_bytes[i * stride];
|
||||
}
|
||||
EXPECT_EQ(lines_in,
|
||||
jpegli_write_scanlines(&cinfo, &rows_in[0], lines_in));
|
||||
jpegli_write_scanlines(&cinfo, rows_in.data(), lines_in));
|
||||
yin += lines_in;
|
||||
if (yin == cinfo.image_height) {
|
||||
jpegli_finish_compress(&cinfo);
|
||||
|
@ -180,7 +180,7 @@ TEST_P(StreamingTestParam, TestStreaming) {
|
|||
reinterpret_cast<JSAMPLE*>(&output.pixels[(yout + i) * stride]);
|
||||
}
|
||||
EXPECT_EQ(lines_out,
|
||||
jpegli_read_scanlines(&dinfo, &rows_out[0], lines_out));
|
||||
jpegli_read_scanlines(&dinfo, rows_out.data(), lines_out));
|
||||
VerifyOutputImage(input, output, yout, lines_out, 3.8f);
|
||||
yout += lines_out;
|
||||
|
||||
|
|
|
@ -8,20 +8,20 @@
|
|||
// include paths for the jpeg headers.
|
||||
|
||||
// Sequential non-interleaved.
|
||||
static constexpr jpeg_scan_info kScript1[] = {
|
||||
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[] = {
|
||||
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[] = {
|
||||
constexpr jpeg_scan_info kScript3[] = {
|
||||
// Interleaved full DC.
|
||||
{3, {0, 1, 2}, 0, 0, 0, 0},
|
||||
// Full AC scans.
|
||||
|
@ -29,7 +29,7 @@ static constexpr jpeg_scan_info kScript3[] = {
|
|||
{1, {1}, 1, 63, 0, 0},
|
||||
{1, {2}, 1, 63, 0, 0},
|
||||
};
|
||||
static constexpr jpeg_scan_info kScript4[] = {
|
||||
constexpr jpeg_scan_info kScript4[] = {
|
||||
// Non-interleaved full DC.
|
||||
{1, {0}, 0, 0, 0, 0},
|
||||
{1, {1}, 0, 0, 0, 0},
|
||||
|
@ -39,7 +39,7 @@ static constexpr jpeg_scan_info kScript4[] = {
|
|||
{1, {1}, 1, 63, 0, 0},
|
||||
{1, {2}, 1, 63, 0, 0},
|
||||
};
|
||||
static constexpr jpeg_scan_info kScript5[] = {
|
||||
constexpr jpeg_scan_info kScript5[] = {
|
||||
// Partially interleaved full DC, chroma first.
|
||||
{2, {1, 2}, 0, 0, 0, 0},
|
||||
{1, {0}, 0, 0, 0, 0},
|
||||
|
@ -52,7 +52,7 @@ static constexpr jpeg_scan_info kScript5[] = {
|
|||
{1, {1}, 1, 63, 1, 0},
|
||||
{1, {2}, 1, 63, 1, 0},
|
||||
};
|
||||
static constexpr jpeg_scan_info kScript6[] = {
|
||||
constexpr jpeg_scan_info kScript6[] = {
|
||||
// Interleaved DC shifted by 2 bits.
|
||||
{3, {0, 1, 2}, 0, 0, 0, 2},
|
||||
// Interleaved DC refinement scans.
|
||||
|
@ -64,7 +64,7 @@ static constexpr jpeg_scan_info kScript6[] = {
|
|||
{1, {2}, 1, 63, 0, 0},
|
||||
};
|
||||
|
||||
static constexpr jpeg_scan_info kScript7[] = {
|
||||
constexpr jpeg_scan_info kScript7[] = {
|
||||
// Non-interleaved DC shifted by 2 bits.
|
||||
{1, {0}, 0, 0, 0, 2},
|
||||
{1, {1}, 0, 0, 0, 2},
|
||||
|
@ -83,7 +83,7 @@ static constexpr jpeg_scan_info kScript7[] = {
|
|||
{1, {2}, 1, 63, 0, 0},
|
||||
};
|
||||
|
||||
static constexpr jpeg_scan_info kScript8[] = {
|
||||
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},
|
||||
|
@ -99,7 +99,7 @@ static constexpr jpeg_scan_info kScript8[] = {
|
|||
{1, {2}, 1, 63, 0, 0},
|
||||
};
|
||||
|
||||
static constexpr jpeg_scan_info kScript9[] = {
|
||||
constexpr jpeg_scan_info kScript9[] = {
|
||||
// Interleaved full DC.
|
||||
{3, {0, 1, 2}, 0, 0, 0, 0},
|
||||
// AC scans for component 0
|
||||
|
@ -123,7 +123,7 @@ static constexpr jpeg_scan_info kScript9[] = {
|
|||
{1, {2}, 17, 63, 1, 0},
|
||||
};
|
||||
|
||||
static constexpr jpeg_scan_info kScript10[] = {
|
||||
constexpr jpeg_scan_info kScript10[] = {
|
||||
// Interleaved full DC.
|
||||
{3, {0, 1, 2}, 0, 0, 0, 0},
|
||||
// AC scans for spectral range 1..16
|
||||
|
@ -156,14 +156,14 @@ struct ScanScript {
|
|||
const jpeg_scan_info* scans;
|
||||
};
|
||||
|
||||
static constexpr ScanScript kTestScript[] = {
|
||||
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);
|
||||
constexpr int kNumTestScripts = ARRAY_SIZE(kTestScript);
|
||||
|
||||
void SetScanDecompressParams(const DecompressParams& dparams,
|
||||
j_decompress_ptr cinfo, int scan_number) {
|
||||
|
@ -178,7 +178,7 @@ void SetScanDecompressParams(const DecompressParams& dparams,
|
|||
return;
|
||||
}
|
||||
if (dparams.quantize_colors) {
|
||||
cinfo->dither_mode = (J_DITHER_MODE)sparams->dither_mode;
|
||||
cinfo->dither_mode = static_cast<J_DITHER_MODE>(sparams->dither_mode);
|
||||
if (sparams->color_quant_mode == CQUANT_1PASS) {
|
||||
cinfo->two_pass_quantize = FALSE;
|
||||
cinfo->colormap = nullptr;
|
||||
|
@ -194,7 +194,8 @@ void SetScanDecompressParams(const DecompressParams& dparams,
|
|||
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));
|
||||
jxl::msan::UnpoisonMemory(reinterpret_cast<void*>(cinfo->colormap),
|
||||
3 * sizeof(JSAMPLE*));
|
||||
for (int i = 0; i < kTestColorMapNumColors; ++i) {
|
||||
cinfo->colormap[0][i] = (kTestColorMap[i] >> 16) & 0xff;
|
||||
cinfo->colormap[1][i] = (kTestColorMap[i] >> 8) & 0xff;
|
||||
|
@ -212,20 +213,21 @@ void SetScanDecompressParams(const DecompressParams& dparams,
|
|||
|
||||
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;
|
||||
cinfo->do_block_smoothing = dparams.do_block_smoothing ? 1 : 0;
|
||||
cinfo->do_fancy_upsampling = dparams.do_fancy_upsampling ? 1 : 0;
|
||||
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;
|
||||
cinfo->out_color_space =
|
||||
static_cast<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->quantize_colors = dparams.quantize_colors ? 1 : 0;
|
||||
cinfo->desired_number_of_colors = dparams.desired_number_of_colors;
|
||||
if (!dparams.scan_params.empty()) {
|
||||
if (cinfo->buffered_image) {
|
||||
|
@ -420,7 +422,7 @@ void CopyCoefficients(j_decompress_ptr cinfo, jvirt_barray_ptr* coef_arrays,
|
|||
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);
|
||||
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);
|
||||
|
|
|
@ -153,7 +153,7 @@ bool ReadPNM(const std::vector<uint8_t>& data, size_t* xsize, size_t* ysize,
|
|||
return false;
|
||||
}
|
||||
pixels->resize(data.data() + data.size() - pos);
|
||||
memcpy(&(*pixels)[0], pos, pixels->size());
|
||||
memcpy(pixels->data(), pos, pixels->size());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -216,7 +216,8 @@ 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((J_COLOR_SPACE)input.color_space);
|
||||
os << "InputColor"
|
||||
<< ColorSpaceName(static_cast<J_COLOR_SPACE>(input.color_space));
|
||||
}
|
||||
if (input.color_space == JCS_UNKNOWN) {
|
||||
os << input.components;
|
||||
|
@ -229,18 +230,18 @@ std::ostream& operator<<(std::ostream& os, const CompressParams& jparams) {
|
|||
os << SamplingId(jparams);
|
||||
if (jparams.set_jpeg_colorspace) {
|
||||
os << "JpegColor"
|
||||
<< ColorSpaceName((J_COLOR_SPACE)jparams.jpeg_color_space);
|
||||
<< ColorSpaceName(static_cast<J_COLOR_SPACE>(jparams.jpeg_color_space));
|
||||
}
|
||||
if (!jparams.comp_ids.empty()) {
|
||||
os << "CID";
|
||||
for (size_t i = 0; i < jparams.comp_ids.size(); ++i) {
|
||||
os << jparams.comp_ids[i];
|
||||
for (int cid : jparams.comp_ids) {
|
||||
os << cid;
|
||||
}
|
||||
}
|
||||
if (!jparams.quant_indexes.empty()) {
|
||||
os << "QIDX";
|
||||
for (size_t i = 0; i < jparams.quant_indexes.size(); ++i) {
|
||||
os << jparams.quant_indexes[i];
|
||||
for (int qi : jparams.quant_indexes) {
|
||||
os << qi;
|
||||
}
|
||||
for (const auto& table : jparams.quant_tables) {
|
||||
os << "TABLE" << table.slot_idx << "T" << table.table_type << "F"
|
||||
|
@ -320,7 +321,7 @@ void RGBToYCbCr(float r, float g, float b, float* y, float* cb, float* cr) {
|
|||
void ConvertPixel(const uint8_t* input_rgb, uint8_t* out,
|
||||
J_COLOR_SPACE colorspace, size_t num_channels,
|
||||
JpegliDataType data_type = JPEGLI_TYPE_UINT8,
|
||||
bool swap_endianness = JPEGLI_NATIVE_ENDIAN) {
|
||||
JXL_BOOL swap_endianness = JPEGLI_NATIVE_ENDIAN) {
|
||||
const float kMul = 255.0f;
|
||||
float r = input_rgb[0] / kMul;
|
||||
float g = input_rgb[1] / kMul;
|
||||
|
@ -334,7 +335,9 @@ void ConvertPixel(const uint8_t* input_rgb, uint8_t* out,
|
|||
out8[c] = input_rgb[std::min<size_t>(2, c)];
|
||||
}
|
||||
} else if (colorspace == JCS_YCbCr) {
|
||||
float Y, Cb, Cr;
|
||||
float Y;
|
||||
float Cb;
|
||||
float Cr;
|
||||
RGBToYCbCr(r, g, b, &Y, &Cb, &Cr);
|
||||
out8[0] = static_cast<uint8_t>(std::round(Y * kMul));
|
||||
out8[1] = static_cast<uint8_t>(std::round(Cb * kMul));
|
||||
|
@ -350,7 +353,9 @@ void ConvertPixel(const uint8_t* input_rgb, uint8_t* out,
|
|||
out8[1] = static_cast<uint8_t>(std::round((1.0f - g) * kMul));
|
||||
out8[2] = static_cast<uint8_t>(std::round((1.0f - b) * kMul));
|
||||
} else if (colorspace == JCS_YCCK) {
|
||||
float Y, Cb, Cr;
|
||||
float Y;
|
||||
float Cb;
|
||||
float Cr;
|
||||
RGBToYCbCr(r, g, b, &Y, &Cb, &Cr);
|
||||
out8[0] = static_cast<uint8_t>(std::round(Y * kMul));
|
||||
out8[1] = static_cast<uint8_t>(std::round(Cb * kMul));
|
||||
|
@ -399,7 +404,10 @@ void ConvertToGrayscale(TestImage* img) {
|
|||
|
||||
void GeneratePixels(TestImage* img) {
|
||||
const std::vector<uint8_t> imgdata = ReadTestData("jxl/flower/flower.pnm");
|
||||
size_t xsize, ysize, channels, bitdepth;
|
||||
size_t xsize;
|
||||
size_t ysize;
|
||||
size_t channels;
|
||||
size_t bitdepth;
|
||||
std::vector<uint8_t> pixels;
|
||||
JXL_CHECK(ReadPNM(imgdata, &xsize, &ysize, &channels, &bitdepth, &pixels));
|
||||
if (img->xsize == 0) img->xsize = xsize;
|
||||
|
@ -412,7 +420,8 @@ 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((J_COLOR_SPACE)img->color_space, &img->components);
|
||||
SetNumChannels(static_cast<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;
|
||||
|
@ -427,8 +436,9 @@ void GeneratePixels(TestImage* img) {
|
|||
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],
|
||||
(J_COLOR_SPACE)img->color_space, img->components,
|
||||
img->data_type, swap_endianness);
|
||||
static_cast<J_COLOR_SPACE>(img->color_space),
|
||||
img->components, img->data_type,
|
||||
TO_JXL_BOOL(swap_endianness));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -492,7 +502,7 @@ void EncodeWithJpegli(const TestImage& input, const CompressParams& jparams,
|
|||
jpegli_set_progressive_level(cinfo, 0);
|
||||
}
|
||||
jpegli_set_defaults(cinfo);
|
||||
cinfo->in_color_space = (J_COLOR_SPACE)input.color_space;
|
||||
cinfo->in_color_space = static_cast<J_COLOR_SPACE>(input.color_space);
|
||||
jpegli_default_colorspace(cinfo);
|
||||
if (jparams.override_JFIF >= 0) {
|
||||
cinfo->write_JFIF_header = jparams.override_JFIF;
|
||||
|
@ -501,7 +511,8 @@ void EncodeWithJpegli(const TestImage& input, const CompressParams& jparams,
|
|||
cinfo->write_Adobe_marker = jparams.override_Adobe;
|
||||
}
|
||||
if (jparams.set_jpeg_colorspace) {
|
||||
jpegli_set_colorspace(cinfo, (J_COLOR_SPACE)jparams.jpeg_color_space);
|
||||
jpegli_set_colorspace(cinfo,
|
||||
static_cast<J_COLOR_SPACE>(jparams.jpeg_color_space));
|
||||
}
|
||||
if (!jparams.comp_ids.empty()) {
|
||||
for (int c = 0; c < cinfo->num_components; ++c) {
|
||||
|
@ -522,15 +533,16 @@ void EncodeWithJpegli(const TestImage& input, const CompressParams& jparams,
|
|||
for (const auto& table : jparams.quant_tables) {
|
||||
if (table.add_raw) {
|
||||
cinfo->quant_tbl_ptrs[table.slot_idx] =
|
||||
jpegli_alloc_quant_table((j_common_ptr)cinfo);
|
||||
jpegli_alloc_quant_table(reinterpret_cast<j_common_ptr>(cinfo));
|
||||
for (int k = 0; k < DCTSIZE2; ++k) {
|
||||
cinfo->quant_tbl_ptrs[table.slot_idx]->quantval[k] =
|
||||
table.quantval[k];
|
||||
}
|
||||
cinfo->quant_tbl_ptrs[table.slot_idx]->sent_table = FALSE;
|
||||
} else {
|
||||
jpegli_add_quant_table(cinfo, table.slot_idx, &table.basic_table[0],
|
||||
table.scale_factor, table.force_baseline);
|
||||
jpegli_add_quant_table(cinfo, table.slot_idx, table.basic_table.data(),
|
||||
table.scale_factor,
|
||||
TO_JXL_BOOL(table.force_baseline));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -546,7 +558,8 @@ void EncodeWithJpegli(const TestImage& input, const CompressParams& jparams,
|
|||
jpegli_set_progressive_level(cinfo, jparams.progressive_mode);
|
||||
}
|
||||
jpegli_set_input_format(cinfo, input.data_type, input.endianness);
|
||||
jpegli_enable_adaptive_quantization(cinfo, jparams.use_adaptive_quantization);
|
||||
jpegli_enable_adaptive_quantization(
|
||||
cinfo, TO_JXL_BOOL(jparams.use_adaptive_quantization));
|
||||
cinfo->restart_interval = jparams.restart_interval;
|
||||
cinfo->restart_in_rows = jparams.restart_in_rows;
|
||||
cinfo->smoothing_factor = jparams.smoothing_factor;
|
||||
|
@ -555,7 +568,7 @@ void EncodeWithJpegli(const TestImage& input, const CompressParams& jparams,
|
|||
} else if (jparams.optimize_coding == 0) {
|
||||
cinfo->optimize_coding = FALSE;
|
||||
}
|
||||
cinfo->raw_data_in = !input.raw_data.empty();
|
||||
cinfo->raw_data_in = TO_JXL_BOOL(!input.raw_data.empty());
|
||||
if (jparams.optimize_coding == 0 && jparams.use_flat_dc_luma_code) {
|
||||
JHUFF_TBL* tbl = cinfo->dc_huff_tbl_ptrs[0];
|
||||
memset(tbl, 0, sizeof(*tbl));
|
||||
|
@ -572,13 +585,13 @@ void EncodeWithJpegli(const TestImage& input, const CompressParams& jparams,
|
|||
cinfo->ac_huff_tbl_ptrs[0]->sent_table = TRUE;
|
||||
cinfo->ac_huff_tbl_ptrs[1]->sent_table = TRUE;
|
||||
}
|
||||
jpegli_start_compress(cinfo, write_all_tables);
|
||||
jpegli_start_compress(cinfo, TO_JXL_BOOL(write_all_tables));
|
||||
if (jparams.add_marker) {
|
||||
jpegli_write_marker(cinfo, kSpecialMarker0, kMarkerData,
|
||||
sizeof(kMarkerData));
|
||||
jpegli_write_m_header(cinfo, kSpecialMarker1, sizeof(kMarkerData));
|
||||
for (size_t p = 0; p < sizeof(kMarkerData); ++p) {
|
||||
jpegli_write_m_byte(cinfo, kMarkerData[p]);
|
||||
for (uint8_t c : kMarkerData) {
|
||||
jpegli_write_m_byte(cinfo, c);
|
||||
}
|
||||
for (size_t i = 0; i < kMarkerSequenceLen; ++i) {
|
||||
jpegli_write_marker(cinfo, kMarkerSequence[i], kMarkerData,
|
||||
|
@ -597,7 +610,7 @@ void EncodeWithJpegli(const TestImage& input, const CompressParams& jparams,
|
|||
std::vector<JSAMPARRAY> data(cinfo->num_components);
|
||||
for (int c = 0; c < cinfo->num_components; ++c) {
|
||||
rowdata[c].resize(jparams.v_samp(c) * DCTSIZE);
|
||||
data[c] = &rowdata[c][0];
|
||||
data[c] = rowdata[c].data();
|
||||
}
|
||||
while (cinfo->next_scanline < cinfo->image_height) {
|
||||
for (int c = 0; c < cinfo->num_components; ++c) {
|
||||
|
@ -610,7 +623,7 @@ void EncodeWithJpegli(const TestImage& input, const CompressParams& jparams,
|
|||
(y0 + i < cheight ? &raw_data[c][(y0 + i) * cwidth] : nullptr);
|
||||
}
|
||||
}
|
||||
size_t num_lines = jpegli_write_raw_data(cinfo, &data[0], max_lines);
|
||||
size_t num_lines = jpegli_write_raw_data(cinfo, data.data(), max_lines);
|
||||
JXL_CHECK(num_lines == max_lines);
|
||||
}
|
||||
} else if (!input.coeffs.empty()) {
|
||||
|
@ -630,15 +643,15 @@ void EncodeWithJpegli(const TestImage& input, const CompressParams& jparams,
|
|||
jpegli_write_marker(cinfo, kSpecialMarker0, kMarkerData,
|
||||
sizeof(kMarkerData));
|
||||
jpegli_write_m_header(cinfo, kSpecialMarker1, sizeof(kMarkerData));
|
||||
for (size_t p = 0; p < sizeof(kMarkerData); ++p) {
|
||||
jpegli_write_m_byte(cinfo, kMarkerData[p]);
|
||||
for (uint8_t c : kMarkerData) {
|
||||
jpegli_write_m_byte(cinfo, c);
|
||||
}
|
||||
}
|
||||
for (int c = 0; c < cinfo->num_components; ++c) {
|
||||
jpeg_component_info* comp = &cinfo->comp_info[c];
|
||||
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);
|
||||
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(ba[0], &input.coeffs[c][offset], stride);
|
||||
|
@ -649,7 +662,7 @@ void EncodeWithJpegli(const TestImage& input, const CompressParams& jparams,
|
|||
jpegli_bytes_per_sample(input.data_type);
|
||||
std::vector<uint8_t> row_bytes(stride);
|
||||
for (size_t y = 0; y < cinfo->image_height; ++y) {
|
||||
memcpy(&row_bytes[0], &input.pixels[y * stride], stride);
|
||||
memcpy(row_bytes.data(), &input.pixels[y * stride], stride);
|
||||
JSAMPROW row[] = {row_bytes.data()};
|
||||
jpegli_write_scanlines(cinfo, row, 1);
|
||||
}
|
||||
|
@ -681,15 +694,15 @@ bool EncodeWithJpegli(const TestImage& input, const CompressParams& jparams,
|
|||
|
||||
int NumTestScanScripts() { return kNumTestScripts; }
|
||||
|
||||
void DumpImage(const TestImage& image, const std::string fn) {
|
||||
void DumpImage(const TestImage& image, const std::string& fn) {
|
||||
JXL_CHECK(image.components == 1 || image.components == 3);
|
||||
size_t bytes_per_sample = jpegli_bytes_per_sample(image.data_type);
|
||||
uint32_t maxval = (1u << (8 * bytes_per_sample)) - 1;
|
||||
char type = image.components == 1 ? '5' : '6';
|
||||
std::ofstream out(fn.c_str(), std::ofstream::binary);
|
||||
out << "P" << type << std::endl
|
||||
<< image.xsize << " " << image.ysize << std::endl
|
||||
<< maxval << std::endl;
|
||||
out << "P" << type << "\n"
|
||||
<< image.xsize << " " << image.ysize << "\n"
|
||||
<< maxval << "\n";
|
||||
out.write(reinterpret_cast<const char*>(image.pixels.data()),
|
||||
image.pixels.size());
|
||||
out.close();
|
||||
|
|
|
@ -6,15 +6,7 @@
|
|||
#ifndef LIB_JPEGLI_TESTING_H_
|
||||
#define LIB_JPEGLI_TESTING_H_
|
||||
|
||||
// GTest/GMock specific macros / wrappers.
|
||||
|
||||
// gmock unconditionally redefines those macros (to wrong values).
|
||||
// Lets include it only here and mitigate the problem.
|
||||
#pragma push_macro("PRIdS")
|
||||
#pragma push_macro("PRIuS")
|
||||
#include "gmock/gmock.h"
|
||||
#pragma pop_macro("PRIuS")
|
||||
#pragma pop_macro("PRIdS")
|
||||
// GTest specific macros / wrappers.
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
|
@ -28,8 +20,12 @@
|
|||
|
||||
// Ensures that we don't make our test bounds too lax, effectively disabling the
|
||||
// tests.
|
||||
MATCHER_P(IsSlightlyBelow, max, "") {
|
||||
return max * 0.75 <= arg && arg <= max * 1.0;
|
||||
}
|
||||
#define EXPECT_SLIGHTLY_BELOW(A, E) \
|
||||
{ \
|
||||
double _actual = (A); \
|
||||
double _expected = (E); \
|
||||
EXPECT_LE(_actual, _expected); \
|
||||
EXPECT_GE(_actual, 0.75 * _expected); \
|
||||
}
|
||||
|
||||
#endif // LIB_JPEGLI_TESTING_H_
|
||||
|
|
|
@ -18,8 +18,8 @@ namespace HWY_NAMESPACE {
|
|||
namespace {
|
||||
|
||||
#if HWY_CAP_GE256
|
||||
static JXL_INLINE void Transpose8x8Block(const float* JXL_RESTRICT from,
|
||||
float* JXL_RESTRICT to) {
|
||||
JXL_INLINE void Transpose8x8Block(const float* JXL_RESTRICT from,
|
||||
float* JXL_RESTRICT to) {
|
||||
const HWY_CAPPED(float, 8) d;
|
||||
auto i0 = Load(d, from);
|
||||
auto i1 = Load(d, from + 1 * 8);
|
||||
|
@ -67,8 +67,8 @@ static JXL_INLINE void Transpose8x8Block(const float* JXL_RESTRICT from,
|
|||
Store(i7, d, to + 7 * 8);
|
||||
}
|
||||
#elif HWY_TARGET != HWY_SCALAR
|
||||
static JXL_INLINE void Transpose8x8Block(const float* JXL_RESTRICT from,
|
||||
float* JXL_RESTRICT to) {
|
||||
JXL_INLINE void Transpose8x8Block(const float* JXL_RESTRICT from,
|
||||
float* JXL_RESTRICT to) {
|
||||
const HWY_CAPPED(float, 4) d;
|
||||
for (size_t n = 0; n < 8; n += 4) {
|
||||
for (size_t m = 0; m < 8; m += 4) {
|
||||
|
|
|
@ -122,7 +122,7 @@ HWY_EXPORT(Upsample2Vertical);
|
|||
|
||||
void Upsample2Horizontal(float* JXL_RESTRICT row,
|
||||
float* JXL_RESTRICT scratch_space, size_t len_out) {
|
||||
return HWY_DYNAMIC_DISPATCH(Upsample2Horizontal)(row, scratch_space, len_out);
|
||||
HWY_DYNAMIC_DISPATCH(Upsample2Horizontal)(row, scratch_space, len_out);
|
||||
}
|
||||
|
||||
void Upsample2Vertical(const float* JXL_RESTRICT row_top,
|
||||
|
@ -130,8 +130,8 @@ void Upsample2Vertical(const float* JXL_RESTRICT row_top,
|
|||
const float* JXL_RESTRICT row_bot,
|
||||
float* JXL_RESTRICT row_out0,
|
||||
float* JXL_RESTRICT row_out1, size_t len) {
|
||||
return HWY_DYNAMIC_DISPATCH(Upsample2Vertical)(row_top, row_mid, row_bot,
|
||||
row_out0, row_out1, len);
|
||||
HWY_DYNAMIC_DISPATCH(Upsample2Vertical)
|
||||
(row_top, row_mid, row_bot, row_out0, row_out1, len);
|
||||
}
|
||||
} // namespace jpegli
|
||||
#endif // HWY_ONCE
|
||||
|
|
|
@ -144,7 +144,7 @@ class AcStrategy {
|
|||
8, 4, 8, 16, 8, 16, 32, 16, 32};
|
||||
static_assert(sizeof(kLut) / sizeof(*kLut) == kNumValidStrategies,
|
||||
"Update LUT");
|
||||
return kLut[size_t(strategy_)];
|
||||
return kLut[static_cast<size_t>(strategy_)];
|
||||
}
|
||||
|
||||
JXL_INLINE size_t covered_blocks_y() const {
|
||||
|
@ -153,7 +153,7 @@ class AcStrategy {
|
|||
8, 8, 4, 16, 16, 8, 32, 32, 16};
|
||||
static_assert(sizeof(kLut) / sizeof(*kLut) == kNumValidStrategies,
|
||||
"Update LUT");
|
||||
return kLut[size_t(strategy_)];
|
||||
return kLut[static_cast<size_t>(strategy_)];
|
||||
}
|
||||
|
||||
JXL_INLINE size_t log2_covered_blocks() const {
|
||||
|
@ -162,7 +162,7 @@ class AcStrategy {
|
|||
6, 5, 5, 8, 7, 7, 10, 9, 9};
|
||||
static_assert(sizeof(kLut) / sizeof(*kLut) == kNumValidStrategies,
|
||||
"Update LUT");
|
||||
return kLut[size_t(strategy_)];
|
||||
return kLut[static_cast<size_t>(strategy_)];
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -181,7 +181,9 @@ class AcStrategyRow {
|
|||
public:
|
||||
explicit AcStrategyRow(const uint8_t* row) : row_(row) {}
|
||||
AcStrategy operator[](size_t x) const {
|
||||
return AcStrategy(static_cast<AcStrategy::Type>(row_[x] >> 1), row_[x] & 1);
|
||||
AcStrategy::Type strategy = static_cast<AcStrategy::Type>(row_[x] >> 1);
|
||||
bool is_first = static_cast<bool>(row_[x] & 1);
|
||||
return AcStrategy(strategy, is_first);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -81,7 +81,8 @@ class AcStrategyRoundtrip : public ::hwy::TestWithParamTargetAndT<int> {
|
|||
|
||||
HWY_TARGET_INSTANTIATE_TEST_SUITE_P_T(
|
||||
AcStrategyRoundtrip,
|
||||
::testing::Range(0, int(AcStrategy::Type::kNumValidStrategies)));
|
||||
::testing::Range(0,
|
||||
static_cast<int>(AcStrategy::Type::kNumValidStrategies)));
|
||||
|
||||
TEST_P(AcStrategyRoundtrip, Test) { Run(); }
|
||||
|
||||
|
@ -141,7 +142,8 @@ class AcStrategyRoundtripDownsample
|
|||
|
||||
HWY_TARGET_INSTANTIATE_TEST_SUITE_P_T(
|
||||
AcStrategyRoundtripDownsample,
|
||||
::testing::Range(0, int(AcStrategy::Type::kNumValidStrategies)));
|
||||
::testing::Range(0,
|
||||
static_cast<int>(AcStrategy::Type::kNumValidStrategies)));
|
||||
|
||||
TEST_P(AcStrategyRoundtripDownsample, Test) { Run(); }
|
||||
|
||||
|
@ -205,7 +207,8 @@ class AcStrategyDownsample : public ::hwy::TestWithParamTargetAndT<int> {
|
|||
|
||||
HWY_TARGET_INSTANTIATE_TEST_SUITE_P_T(
|
||||
AcStrategyDownsample,
|
||||
::testing::Range(0, int(AcStrategy::Type::kNumValidStrategies)));
|
||||
::testing::Range(0,
|
||||
static_cast<int>(AcStrategy::Type::kNumValidStrategies)));
|
||||
|
||||
TEST_P(AcStrategyDownsample, Test) { Run(); }
|
||||
|
||||
|
|
|
@ -5,69 +5,59 @@
|
|||
|
||||
#include "lib/jxl/alpha.h"
|
||||
|
||||
#include "lib/jxl/test_utils.h"
|
||||
#include <array>
|
||||
|
||||
#include "lib/jxl/base/common.h"
|
||||
#include "lib/jxl/testing.h"
|
||||
|
||||
namespace jxl {
|
||||
namespace {
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::ElementsAre;
|
||||
using ::testing::FloatNear;
|
||||
|
||||
TEST(AlphaTest, BlendingWithNonPremultiplied) {
|
||||
const float bg_rgb[3] = {100, 110, 120};
|
||||
const Color bg_rgb{100, 110, 120};
|
||||
const float bg_a = 180.f / 255;
|
||||
const float fg_rgb[3] = {25, 21, 23};
|
||||
const Color fg_rgb{25, 21, 23};
|
||||
const float fg_a = 15420.f / 65535;
|
||||
const float fg_a2 = 2.0f;
|
||||
float out_rgb[3];
|
||||
Color out_rgb;
|
||||
float out_a;
|
||||
PerformAlphaBlending(
|
||||
/*bg=*/{&bg_rgb[0], &bg_rgb[1], &bg_rgb[2], &bg_a},
|
||||
/*fg=*/{&fg_rgb[0], &fg_rgb[1], &fg_rgb[2], &fg_a},
|
||||
/*out=*/{&out_rgb[0], &out_rgb[1], &out_rgb[2], &out_a}, 1,
|
||||
/*alpha_is_premultiplied=*/false, /*clamp=*/false);
|
||||
EXPECT_THAT(out_rgb,
|
||||
ElementsAre(FloatNear(77.2f, .05f), FloatNear(83.0f, .05f),
|
||||
FloatNear(90.6f, .05f)));
|
||||
EXPECT_ARRAY_NEAR(out_rgb, (Color{77.2f, 83.0f, 90.6f}), 0.05f);
|
||||
EXPECT_NEAR(out_a, 3174.f / 4095, 1e-5);
|
||||
PerformAlphaBlending(
|
||||
/*bg=*/{&bg_rgb[0], &bg_rgb[1], &bg_rgb[2], &bg_a},
|
||||
/*fg=*/{&fg_rgb[0], &fg_rgb[1], &fg_rgb[2], &fg_a2},
|
||||
/*out=*/{&out_rgb[0], &out_rgb[1], &out_rgb[2], &out_a}, 1,
|
||||
/*alpha_is_premultiplied=*/false, /*clamp=*/true);
|
||||
EXPECT_THAT(out_rgb, ElementsAre(FloatNear(fg_rgb[0], .05f),
|
||||
FloatNear(fg_rgb[1], .05f),
|
||||
FloatNear(fg_rgb[2], .05f)));
|
||||
EXPECT_ARRAY_NEAR(out_rgb, fg_rgb, 0.05f);
|
||||
EXPECT_NEAR(out_a, 1.0f, 1e-5);
|
||||
}
|
||||
|
||||
TEST(AlphaTest, BlendingWithPremultiplied) {
|
||||
const float bg_rgb[3] = {100, 110, 120};
|
||||
const Color bg_rgb{100, 110, 120};
|
||||
const float bg_a = 180.f / 255;
|
||||
const float fg_rgb[3] = {25, 21, 23};
|
||||
const Color fg_rgb{25, 21, 23};
|
||||
const float fg_a = 15420.f / 65535;
|
||||
const float fg_a2 = 2.0f;
|
||||
float out_rgb[3];
|
||||
Color out_rgb;
|
||||
float out_a;
|
||||
PerformAlphaBlending(
|
||||
/*bg=*/{&bg_rgb[0], &bg_rgb[1], &bg_rgb[2], &bg_a},
|
||||
/*fg=*/{&fg_rgb[0], &fg_rgb[1], &fg_rgb[2], &fg_a},
|
||||
/*out=*/{&out_rgb[0], &out_rgb[1], &out_rgb[2], &out_a}, 1,
|
||||
/*alpha_is_premultiplied=*/true, /*clamp=*/false);
|
||||
EXPECT_THAT(out_rgb,
|
||||
ElementsAre(FloatNear(101.5f, .05f), FloatNear(105.1f, .05f),
|
||||
FloatNear(114.8f, .05f)));
|
||||
EXPECT_ARRAY_NEAR(out_rgb, (Color{101.5f, 105.1f, 114.8f}), 0.05f);
|
||||
EXPECT_NEAR(out_a, 3174.f / 4095, 1e-5);
|
||||
PerformAlphaBlending(
|
||||
/*bg=*/{&bg_rgb[0], &bg_rgb[1], &bg_rgb[2], &bg_a},
|
||||
/*fg=*/{&fg_rgb[0], &fg_rgb[1], &fg_rgb[2], &fg_a2},
|
||||
/*out=*/{&out_rgb[0], &out_rgb[1], &out_rgb[2], &out_a}, 1,
|
||||
/*alpha_is_premultiplied=*/true, /*clamp=*/true);
|
||||
EXPECT_THAT(out_rgb, ElementsAre(FloatNear(fg_rgb[0], .05f),
|
||||
FloatNear(fg_rgb[1], .05f),
|
||||
FloatNear(fg_rgb[2], .05f)));
|
||||
EXPECT_ARRAY_NEAR(out_rgb, fg_rgb, 0.05f);
|
||||
EXPECT_NEAR(out_a, 1.0f, 1e-5);
|
||||
}
|
||||
|
||||
|
@ -76,58 +66,51 @@ TEST(AlphaTest, Mul) {
|
|||
const float fg = 25;
|
||||
float out;
|
||||
PerformMulBlending(&bg, &fg, &out, 1, /*clamp=*/false);
|
||||
EXPECT_THAT(out, FloatNear(fg * bg, .05f));
|
||||
EXPECT_NEAR(out, fg * bg, .05f);
|
||||
PerformMulBlending(&bg, &fg, &out, 1, /*clamp=*/true);
|
||||
EXPECT_THAT(out, FloatNear(bg, .05f));
|
||||
EXPECT_NEAR(out, bg, .05f);
|
||||
}
|
||||
|
||||
TEST(AlphaTest, PremultiplyAndUnpremultiply) {
|
||||
const float alpha[] = {0.f, 63.f / 255, 127.f / 255, 1.f};
|
||||
float r[] = {120, 130, 140, 150};
|
||||
float g[] = {124, 134, 144, 154};
|
||||
float b[] = {127, 137, 147, 157};
|
||||
using F4 = std::array<float, 4>;
|
||||
const F4 alpha{0.f, 63.f / 255, 127.f / 255, 1.f};
|
||||
F4 r{120, 130, 140, 150};
|
||||
F4 g{124, 134, 144, 154};
|
||||
F4 b{127, 137, 147, 157};
|
||||
|
||||
PremultiplyAlpha(r, g, b, alpha, 4);
|
||||
EXPECT_THAT(
|
||||
r, ElementsAre(FloatNear(0.f, 1e-5f), FloatNear(130 * 63.f / 255, 1e-5f),
|
||||
FloatNear(140 * 127.f / 255, 1e-5f), 150));
|
||||
EXPECT_THAT(
|
||||
g, ElementsAre(FloatNear(0.f, 1e-5f), FloatNear(134 * 63.f / 255, 1e-5f),
|
||||
FloatNear(144 * 127.f / 255, 1e-5f), 154));
|
||||
EXPECT_THAT(
|
||||
b, ElementsAre(FloatNear(0.f, 1e-5f), FloatNear(137 * 63.f / 255, 1e-5f),
|
||||
FloatNear(147 * 127.f / 255, 1e-5f), 157));
|
||||
PremultiplyAlpha(r.data(), g.data(), b.data(), alpha.data(), alpha.size());
|
||||
EXPECT_ARRAY_NEAR(r, (F4{0.0f, 130 * 63.f / 255, 140 * 127.f / 255, 150}),
|
||||
1e-5f);
|
||||
EXPECT_ARRAY_NEAR(g, (F4{0.0f, 134 * 63.f / 255, 144 * 127.f / 255, 154}),
|
||||
1e-5f);
|
||||
EXPECT_ARRAY_NEAR(b, (F4{0.0f, 137 * 63.f / 255, 147 * 127.f / 255, 157}),
|
||||
1e-5f);
|
||||
|
||||
UnpremultiplyAlpha(r, g, b, alpha, 4);
|
||||
EXPECT_THAT(r, ElementsAre(FloatNear(120, 1e-4f), FloatNear(130, 1e-4f),
|
||||
FloatNear(140, 1e-4f), FloatNear(150, 1e-4f)));
|
||||
EXPECT_THAT(g, ElementsAre(FloatNear(124, 1e-4f), FloatNear(134, 1e-4f),
|
||||
FloatNear(144, 1e-4f), FloatNear(154, 1e-4f)));
|
||||
EXPECT_THAT(b, ElementsAre(FloatNear(127, 1e-4f), FloatNear(137, 1e-4f),
|
||||
FloatNear(147, 1e-4f), FloatNear(157, 1e-4f)));
|
||||
UnpremultiplyAlpha(r.data(), g.data(), b.data(), alpha.data(), alpha.size());
|
||||
EXPECT_ARRAY_NEAR(r, (F4{120, 130, 140, 150}), 1e-4f);
|
||||
EXPECT_ARRAY_NEAR(g, (F4{124, 134, 144, 154}), 1e-4f);
|
||||
EXPECT_ARRAY_NEAR(b, (F4{127, 137, 147, 157}), 1e-4f);
|
||||
}
|
||||
|
||||
TEST(AlphaTest, UnpremultiplyAndPremultiply) {
|
||||
const float alpha[] = {0.f, 63.f / 255, 127.f / 255, 1.f};
|
||||
float r[] = {50, 60, 70, 80};
|
||||
float g[] = {54, 64, 74, 84};
|
||||
float b[] = {57, 67, 77, 87};
|
||||
using F4 = std::array<float, 4>;
|
||||
const F4 alpha{0.f, 63.f / 255, 127.f / 255, 1.f};
|
||||
F4 r{50, 60, 70, 80};
|
||||
F4 g{54, 64, 74, 84};
|
||||
F4 b{57, 67, 77, 87};
|
||||
|
||||
UnpremultiplyAlpha(r, g, b, alpha, 4);
|
||||
EXPECT_THAT(r, ElementsAre(_, FloatNear(60 * 255.f / 63, 1e-4f),
|
||||
FloatNear(70 * 255.f / 127, 1e-4f), 80));
|
||||
EXPECT_THAT(g, ElementsAre(_, FloatNear(64 * 255.f / 63, 1e-4f),
|
||||
FloatNear(74 * 255.f / 127, 1e-4f), 84));
|
||||
EXPECT_THAT(b, ElementsAre(_, FloatNear(67 * 255.f / 63, 1e-4f),
|
||||
FloatNear(77 * 255.f / 127, 1e-4f), 87));
|
||||
UnpremultiplyAlpha(r.data(), g.data(), b.data(), alpha.data(), alpha.size());
|
||||
EXPECT_ARRAY_NEAR(
|
||||
r, (F4{50.0f * (1 << 26), 60 * 255.f / 63, 70 * 255.f / 127, 80}), 1e-4f);
|
||||
EXPECT_ARRAY_NEAR(
|
||||
g, (F4{54.0f * (1 << 26), 64 * 255.f / 63, 74 * 255.f / 127, 84}), 1e-4f);
|
||||
EXPECT_ARRAY_NEAR(
|
||||
b, (F4{57.0f * (1 << 26), 67 * 255.f / 63, 77 * 255.f / 127, 87}), 1e-4f);
|
||||
|
||||
PremultiplyAlpha(r, g, b, alpha, 4);
|
||||
EXPECT_THAT(r, ElementsAre(FloatNear(50, 1e-4f), FloatNear(60, 1e-4f),
|
||||
FloatNear(70, 1e-4f), FloatNear(80, 1e-4f)));
|
||||
EXPECT_THAT(g, ElementsAre(FloatNear(54, 1e-4f), FloatNear(64, 1e-4f),
|
||||
FloatNear(74, 1e-4f), FloatNear(84, 1e-4f)));
|
||||
EXPECT_THAT(b, ElementsAre(FloatNear(57, 1e-4f), FloatNear(67, 1e-4f),
|
||||
FloatNear(77, 1e-4f), FloatNear(87, 1e-4f)));
|
||||
PremultiplyAlpha(r.data(), g.data(), b.data(), alpha.data(), alpha.size());
|
||||
EXPECT_ARRAY_NEAR(r, (F4{50, 60, 70, 80}), 1e-4);
|
||||
EXPECT_ARRAY_NEAR(g, (F4{54, 64, 74, 84}), 1e-4);
|
||||
EXPECT_ARRAY_NEAR(b, (F4{57, 67, 77, 87}), 1e-4);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -24,7 +24,8 @@ namespace jxl {
|
|||
static JXL_INLINE uint32_t GetPopulationCountPrecision(uint32_t logcount,
|
||||
uint32_t shift) {
|
||||
int32_t r = std::min<int>(
|
||||
logcount, int(shift) - int((ANS_LOG_TAB_SIZE - logcount) >> 1));
|
||||
logcount, static_cast<int>(shift) -
|
||||
static_cast<int>((ANS_LOG_TAB_SIZE - logcount) >> 1));
|
||||
if (r < 0) return 0;
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -113,8 +113,8 @@ void RoundtripRandomUnbalancedStream(int alphabet_size) {
|
|||
Rng rng(0);
|
||||
for (size_t i = 0; i < kReps; i++) {
|
||||
std::vector<int> distributions[kNumHistograms] = {};
|
||||
for (int j = 0; j < kNumHistograms; j++) {
|
||||
distributions[j].resize(kPrecision);
|
||||
for (auto& distr : distributions) {
|
||||
distr.resize(kPrecision);
|
||||
int symbol = 0;
|
||||
int remaining = 1;
|
||||
for (int k = 0; k < kPrecision; k++) {
|
||||
|
@ -126,7 +126,7 @@ void RoundtripRandomUnbalancedStream(int alphabet_size) {
|
|||
// sufficiently dissimilar.
|
||||
remaining = rng.UniformU(0, kPrecision - k + 1);
|
||||
}
|
||||
distributions[j][k] = symbol;
|
||||
distr[k] = symbol;
|
||||
remaining--;
|
||||
}
|
||||
}
|
||||
|
@ -158,7 +158,8 @@ TEST(ANSTest, RandomUnbalancedStreamRoundtripBig) {
|
|||
|
||||
TEST(ANSTest, UintConfigRoundtrip) {
|
||||
for (size_t log_alpha_size = 5; log_alpha_size <= 8; log_alpha_size++) {
|
||||
std::vector<HybridUintConfig> uint_config, uint_config_dec;
|
||||
std::vector<HybridUintConfig> uint_config;
|
||||
std::vector<HybridUintConfig> uint_config_dec;
|
||||
for (size_t i = 0; i < log_alpha_size; i++) {
|
||||
for (size_t j = 0; j <= i; j++) {
|
||||
for (size_t k = 0; k <= i - j; k++) {
|
||||
|
@ -187,16 +188,16 @@ TEST(ANSTest, UintConfigRoundtrip) {
|
|||
void TestCheckpointing(bool ans, bool lz77) {
|
||||
std::vector<std::vector<Token>> input_values(1);
|
||||
for (size_t i = 0; i < 1024; i++) {
|
||||
input_values[0].push_back(Token(0, i % 4));
|
||||
input_values[0].emplace_back(0, i % 4);
|
||||
}
|
||||
// up to lz77 window size.
|
||||
for (size_t i = 0; i < (1 << 20) - 1022; i++) {
|
||||
input_values[0].push_back(Token(0, (i % 5) + 4));
|
||||
input_values[0].emplace_back(0, (i % 5) + 4);
|
||||
}
|
||||
// Ensure that when the window wraps around, new values are different.
|
||||
input_values[0].push_back(Token(0, 0));
|
||||
input_values[0].emplace_back(0, 0);
|
||||
for (size_t i = 0; i < 1024; i++) {
|
||||
input_values[0].push_back(Token(0, i % 4));
|
||||
input_values[0].emplace_back(0, i % 4);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> context_map;
|
||||
|
|
|
@ -26,7 +26,8 @@ struct SizeTag {};
|
|||
|
||||
template <typename T>
|
||||
constexpr bool IsSigned() {
|
||||
return T(0) > T(-1);
|
||||
// TODO(eustas): remove dupes
|
||||
return static_cast<T>(0) > static_cast<T>(-1);
|
||||
}
|
||||
|
||||
// Undefined results for x == 0.
|
||||
|
|
|
@ -237,22 +237,22 @@ struct OrderLE {};
|
|||
// Wrappers for calling from generic code.
|
||||
static JXL_INLINE void Store16(OrderBE /*tag*/, const uint32_t native,
|
||||
uint8_t* p) {
|
||||
return StoreBE16(native, p);
|
||||
StoreBE16(native, p);
|
||||
}
|
||||
|
||||
static JXL_INLINE void Store16(OrderLE /*tag*/, const uint32_t native,
|
||||
uint8_t* p) {
|
||||
return StoreLE16(native, p);
|
||||
StoreLE16(native, p);
|
||||
}
|
||||
|
||||
static JXL_INLINE void Store32(OrderBE /*tag*/, const uint32_t native,
|
||||
uint8_t* p) {
|
||||
return StoreBE32(native, p);
|
||||
StoreBE32(native, p);
|
||||
}
|
||||
|
||||
static JXL_INLINE void Store32(OrderLE /*tag*/, const uint32_t native,
|
||||
uint8_t* p) {
|
||||
return StoreLE32(native, p);
|
||||
StoreLE32(native, p);
|
||||
}
|
||||
|
||||
static JXL_INLINE uint32_t Load16(OrderBE /*tag*/, const uint8_t* p) {
|
||||
|
|
|
@ -8,11 +8,13 @@
|
|||
|
||||
// Shared constants and helper functions.
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include "lib/jxl/base/compiler_specific.h"
|
||||
|
||||
|
@ -22,11 +24,11 @@ namespace jxl {
|
|||
constexpr size_t kBitsPerByte = 8; // more clear than CHAR_BIT
|
||||
|
||||
constexpr inline size_t RoundUpBitsToByteMultiple(size_t bits) {
|
||||
return (bits + 7) & ~size_t(7);
|
||||
return (bits + 7) & ~static_cast<size_t>(7);
|
||||
}
|
||||
|
||||
constexpr inline size_t RoundUpToBlockDim(size_t dim) {
|
||||
return (dim + 7) & ~size_t(7);
|
||||
return (dim + 7) & ~static_cast<size_t>(7);
|
||||
}
|
||||
|
||||
static inline bool JXL_MAYBE_UNUSED SafeAdd(const uint64_t a, const uint64_t b,
|
||||
|
@ -68,6 +70,37 @@ std::unique_ptr<T> make_unique(Args&&... args) {
|
|||
using std::make_unique;
|
||||
#endif
|
||||
|
||||
typedef std::array<float, 3> Color;
|
||||
|
||||
// Backported std::experimental::to_array
|
||||
|
||||
template <typename T>
|
||||
using remove_cv_t = typename std::remove_cv<T>::type;
|
||||
|
||||
template <size_t... I>
|
||||
struct index_sequence {};
|
||||
|
||||
template <size_t N, size_t... I>
|
||||
struct make_index_sequence : make_index_sequence<N - 1, N - 1, I...> {};
|
||||
|
||||
template <size_t... I>
|
||||
struct make_index_sequence<0, I...> : index_sequence<I...> {};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T, size_t N, size_t... I>
|
||||
constexpr auto to_array(T (&&arr)[N], index_sequence<I...> _)
|
||||
-> std::array<remove_cv_t<T>, N> {
|
||||
return {{std::move(arr[I])...}};
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T, size_t N>
|
||||
constexpr auto to_array(T (&&arr)[N]) -> std::array<remove_cv_t<T>, N> {
|
||||
return detail::to_array(std::move(arr), make_index_sequence<N>());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
JXL_INLINE T Clamp1(T val, T low, T hi) {
|
||||
return val < low ? low : val > hi ? hi : val;
|
||||
|
@ -77,10 +110,10 @@ JXL_INLINE T Clamp1(T val, T low, T hi) {
|
|||
template <typename T>
|
||||
std::string ToString(T n) {
|
||||
char data[32] = {};
|
||||
if (T(0.1) != T(0)) {
|
||||
if (std::is_floating_point<T>::value) {
|
||||
// float
|
||||
snprintf(data, sizeof(data), "%g", static_cast<double>(n));
|
||||
} else if (T(-1) > T(0)) {
|
||||
} else if (std::is_unsigned<T>::value) {
|
||||
// unsigned
|
||||
snprintf(data, sizeof(data), "%llu", static_cast<unsigned long long>(n));
|
||||
} else {
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче