зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1918647 - Update libjxl to v0.11.0 r=saschanaz
Differential Revision: https://phabricator.services.mozilla.com/D222104
This commit is contained in:
Родитель
6cc15139bc
Коммит
5bd52a5b9c
|
@ -15,7 +15,6 @@ SOURCES += [
|
|||
"/third_party/jpeg-xl/lib/jxl/alpha.cc",
|
||||
"/third_party/jpeg-xl/lib/jxl/ans_common.cc",
|
||||
"/third_party/jpeg-xl/lib/jxl/blending.cc",
|
||||
"/third_party/jpeg-xl/lib/jxl/cache_aligned.cc",
|
||||
"/third_party/jpeg-xl/lib/jxl/chroma_from_luma.cc",
|
||||
"/third_party/jpeg-xl/lib/jxl/coeff_order.cc",
|
||||
"/third_party/jpeg-xl/lib/jxl/color_encoding_internal.cc",
|
||||
|
@ -85,6 +84,7 @@ SOURCES += [
|
|||
"/third_party/jpeg-xl/lib/jxl/render_pipeline/stage_ycbcr.cc",
|
||||
"/third_party/jpeg-xl/lib/jxl/simd_util.cc",
|
||||
"/third_party/jpeg-xl/lib/jxl/splines.cc",
|
||||
"/third_party/jpeg-xl/lib/jxl/test_memory_manager.cc",
|
||||
"/third_party/jpeg-xl/lib/jxl/toc.cc",
|
||||
]
|
||||
|
||||
|
|
|
@ -10,9 +10,9 @@ origin:
|
|||
|
||||
url: https://github.com/libjxl/libjxl
|
||||
|
||||
release: v0.10.3 (2024-06-27T14:10:08+02:00).
|
||||
release: v0.11.0 (2024-09-13T07:31:05+02:00).
|
||||
|
||||
revision: v0.10.3
|
||||
revision: v0.11.0
|
||||
|
||||
license: Apache-2.0
|
||||
|
||||
|
|
|
@ -25,17 +25,20 @@ Checks: >-
|
|||
modernize-*,
|
||||
performance-*,
|
||||
readability-*,
|
||||
-bugprone-narrowing-conversions,
|
||||
-bugprone-branch-clone,
|
||||
-bugprone-easily-swappable-parameters,
|
||||
-bugprone-implicit-widening-of-multiplication-result,
|
||||
-bugprone-infinite-loop,
|
||||
-bugprone-narrowing-conversions,
|
||||
-bugprone-unused-local-non-trivial-variable,
|
||||
-modernize-avoid-c-arrays,
|
||||
-modernize-concat-nested-namespaces,
|
||||
-modernize-deprecated-headers,
|
||||
-modernize-return-braced-init-list,
|
||||
-modernize-type-traits,
|
||||
-modernize-use-auto,
|
||||
-modernize-use-default-member-init,
|
||||
-modernize-use-nodiscard,
|
||||
-modernize-use-trailing-return-type,
|
||||
-modernize-use-using,
|
||||
-performance-enum-size,
|
||||
|
|
|
@ -39,9 +39,11 @@ Alistair Barrow
|
|||
Andrius Lukas Narbutas <andrius4669@gmail.com>
|
||||
Aous Naman <aous@unsw.edu.au>
|
||||
Artem Selishchev
|
||||
Aryan Pingle <realaryanpingle@gmail.com>
|
||||
Biswapriyo Nath <nathbappai@gmail.com>
|
||||
CanadianBaconBoi <beamconnor@gmail.com>
|
||||
Damiano Albani <damiano.albani@gmail.com>
|
||||
Damon Townsend
|
||||
Daniel Novomeský <dnovomesky@gmail.com>
|
||||
David Burnett <vargolsoft@gmail.com>
|
||||
dependabot[bot]
|
||||
|
@ -53,17 +55,20 @@ Dong Xu <xdong181@gmail.com>
|
|||
estrogently <41487185+estrogently@users.noreply.github.com>
|
||||
Even Rouault <even.rouault@spatialys.com>
|
||||
Fred Brennan <copypaste@kittens.ph>
|
||||
Gerhard Huber <support@pl32.com>
|
||||
gi-man
|
||||
Gilles Devillers (GilDev) <gildev@gmail.com>
|
||||
Heiko Becker <heirecka@exherbo.org>
|
||||
Ivan Kokorev
|
||||
Jim Robinson <jimbo2150@gmail.com>
|
||||
John Platts <john_platts@hotmail.com>
|
||||
Jonathan Brown (Jonnyawsom3) <jonathanbr30@gmail.com>
|
||||
Joshua Root <jmr@macports.org>
|
||||
Kai Hollberg <Schweinepriester@users.noreply.github.com>
|
||||
Kerry Su <me@sshockwave.net>
|
||||
Kleis Auke Wolthuizen <github@kleisauke.nl>
|
||||
L. E. Segovia
|
||||
ledoge
|
||||
Leo Izen <leo.izen@gmail.com>
|
||||
Lovell Fuller
|
||||
Maarten DB <anonymous.maarten@gmail.com>
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
# Copyright (c) the JPEG XL Project Authors. All rights reserved.
|
||||
#
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
package(default_visibility = ["//:__subpackages__"])
|
||||
|
||||
filegroup(
|
||||
|
|
|
@ -5,10 +5,23 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.10.3] - 2024-06-27
|
||||
## [0.11.0] - 2024-09-13
|
||||
|
||||
### Fixed
|
||||
- fix decoding of some special images (#3662)
|
||||
### Added
|
||||
- Gain Map API (#3552 and #3628): `JxlGainMapBundle` struct and API functions
|
||||
to read and write gain map bundles`JxlGainMapWriteBundle` and
|
||||
`JxlGainMapReadBundle` as well as handling compressed ICC profiles:
|
||||
`JxlICCProfileEncode` and `JxlICCProfileDecode`.
|
||||
- decoder API: added `JXL_DEC_BOX_COMPLETE` event to signal that the output
|
||||
buffer for the current box has received all contents. Previously, this was
|
||||
to be determined from the fact that the decoder had moved on either to
|
||||
`JXL_DEC_SUCCESS` or to another subsequent `JXL_DEC_BOX`. This change is
|
||||
made backward-compatible by the fact that the new event must be explicitly
|
||||
subscribed to, and that `JXL_DEC_SUCCESS` / `JXL_DEC_BOX` still occur
|
||||
afterwards and still imply that the previous box must be complete.
|
||||
|
||||
### Changed / clarified
|
||||
- avoiding abort in release build (#3631 and #3639)
|
||||
|
||||
## [0.10.2] - 2024-03-08
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ project(LIBJXL LANGUAGES C CXX)
|
|||
|
||||
# TODO(sboukortt): remove once oss-fuzz passes -DBUILD_SHARED_LIBS=OFF
|
||||
if(JPEGXL_ENABLE_FUZZERS)
|
||||
message(INFO "Fuzzer build detected, building static libs")
|
||||
message(STATUS "Fuzzer build detected, building static libs")
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
endif()
|
||||
|
||||
|
@ -21,6 +21,10 @@ check_cxx_compiler_flag("-fsanitize=fuzzer-no-link" CXX_FUZZERS_SUPPORTED)
|
|||
check_cxx_compiler_flag("-fmacro-prefix-map=OLD=NEW" CXX_MACRO_PREFIX_MAP)
|
||||
check_cxx_compiler_flag("-fno-rtti" CXX_NO_RTTI_SUPPORTED)
|
||||
|
||||
# Add "DebugOpt" CMake build type. Unlike builtin DEBUG it is optimized.
|
||||
string(REGEX REPLACE "-DNDEBUG " "" CMAKE_CXX_FLAGS_DEBUGOPT "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DDEBUG" )
|
||||
string(REGEX REPLACE "-DNDEBUG " "" CMAKE_C_FLAGS_DEBUGOPT "${CMAKE_C_FLAGS_RELWITHDEBINFO} -DDEBUG" )
|
||||
|
||||
# Enabled PIE binaries by default if supported.
|
||||
include(CheckPIESupported OPTIONAL RESULT_VARIABLE CHECK_PIE_SUPPORTED)
|
||||
if(CHECK_PIE_SUPPORTED)
|
||||
|
@ -86,6 +90,16 @@ if(EXISTS "${PROJECT_SOURCE_DIR}/third_party/libjpeg-turbo/jconfig.h.in")
|
|||
set(ENABLE_JPEGLI_DEFAULT YES)
|
||||
else()
|
||||
set(ENABLE_JPEGLI_DEFAULT NO)
|
||||
message(STATUS "libjpeg-turbo submodule is absent; not enabling jpegli")
|
||||
endif()
|
||||
|
||||
include(TestBigEndian)
|
||||
test_big_endian(ARCH_IS_BIG_ENDIAN)
|
||||
if(ARCH_IS_BIG_ENDIAN)
|
||||
set(ENABLE_SKCMS_DEFAULT NO)
|
||||
message(STATUS "Big-endian architecture detected; defaulting to lcms2 instead of skcms")
|
||||
else()
|
||||
set(ENABLE_SKCMS_DEFAULT YES)
|
||||
endif()
|
||||
|
||||
# Standard cmake naming for building shared libraries.
|
||||
|
@ -124,7 +138,7 @@ set(JPEGXL_ENABLE_SJPEG true CACHE BOOL
|
|||
"Build JPEGXL with support for encoding with sjpeg.")
|
||||
set(JPEGXL_ENABLE_OPENEXR true CACHE BOOL
|
||||
"Build JPEGXL with support for OpenEXR if available.")
|
||||
set(JPEGXL_ENABLE_SKCMS true CACHE BOOL
|
||||
set(JPEGXL_ENABLE_SKCMS ${ENABLE_SKCMS_DEFAULT} CACHE BOOL
|
||||
"Build with skcms instead of lcms2.")
|
||||
set(JPEGXL_ENABLE_VIEWERS false CACHE BOOL
|
||||
"Build JPEGXL viewer tools for evaluation.")
|
||||
|
@ -160,14 +174,14 @@ set(JPEGXL_ENABLE_AVX512_SPR false CACHE BOOL
|
|||
"Build with AVX-512FP16 support (faster on CPUs that support it, but larger binary size).")
|
||||
set(JPEGXL_ENABLE_AVX512_ZEN4 false CACHE BOOL
|
||||
"Build with Zen4-optimized AVX512 support (faster on CPUs that support it, but larger binary size).")
|
||||
set(JPEGXL_ENABLE_WASM_TRHEADS true CACHE BOOL
|
||||
set(JPEGXL_ENABLE_WASM_THREADS true CACHE BOOL
|
||||
"Builds WASM modules with threads support")
|
||||
|
||||
# Force system dependencies.
|
||||
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
|
||||
|
@ -208,13 +222,20 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|||
|
||||
if(JPEGXL_STATIC)
|
||||
set(BUILD_SHARED_LIBS 0)
|
||||
|
||||
# https://learn.microsoft.com/en-us/cpp/build/reference/md-mt-ld-use-run-time-library?view=msvc-170
|
||||
# https://cmake.org/cmake/help/latest/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded)
|
||||
|
||||
# Clang developers say that in case to use "static" we have to build stdlib
|
||||
# ourselves; for real use case we don't care about stdlib, as it is "granted",
|
||||
# so just linking all other libraries is fine.
|
||||
if (NOT MSVC AND NOT APPLE)
|
||||
if (NOT MSVC)
|
||||
string(APPEND CMAKE_EXE_LINKER_FLAGS " -static")
|
||||
endif()
|
||||
if ((NOT WIN32 AND NOT APPLE) OR CYGWIN OR MINGW)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
|
||||
set(CMAKE_EXE_LINKER_FLAGS
|
||||
"${CMAKE_EXE_LINKER_FLAGS} -static -static-libgcc -static-libstdc++")
|
||||
string(APPEND CMAKE_EXE_LINKER_FLAGS " -static-libgcc -static-libstdc++")
|
||||
endif()
|
||||
endif() # JPEGXL_STATIC
|
||||
|
||||
|
@ -224,7 +245,16 @@ find_package(Threads REQUIRED)
|
|||
|
||||
# These settings are important to drive check_cxx_source_compiles
|
||||
# See CMP0067 (min cmake version is 3.10 anyway)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
if ("cxx_std_17" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
else()
|
||||
if ("cxx_std_14" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
else()
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
endif()
|
||||
endif()
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED YES)
|
||||
|
||||
|
@ -265,7 +295,7 @@ if(JPEGXL_STATIC)
|
|||
endif()
|
||||
endif() # JPEGXL_STATIC
|
||||
|
||||
if (EMSCRIPTEN AND JPEGXL_ENABLE_WASM_TRHEADS)
|
||||
if (EMSCRIPTEN AND JPEGXL_ENABLE_WASM_THREADS)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread")
|
||||
|
@ -343,7 +373,6 @@ else ()
|
|||
if(JPEGXL_ENABLE_COVERAGE)
|
||||
set(JPEGXL_COVERAGE_FLAGS
|
||||
-g -O0 -fprofile-arcs -ftest-coverage
|
||||
-DJXL_ENABLE_ASSERT=0 -DJXL_ENABLE_CHECK=0
|
||||
)
|
||||
set(JPEGXL_COVERAGE_LINK_FLAGS
|
||||
--coverage
|
||||
|
@ -431,7 +460,7 @@ if(JPEGXL_ENABLE_MANPAGES)
|
|||
find_program(ASCIIDOC a2x)
|
||||
if(ASCIIDOC)
|
||||
file(STRINGS "${ASCIIDOC}" ASCIIDOC_SHEBANG LIMIT_COUNT 1)
|
||||
if(ASCIIDOC_SHEBANG MATCHES "/sh|/bash" OR MINGW)
|
||||
if(ASCIIDOC_SHEBANG MATCHES "sh$" OR MINGW)
|
||||
set(ASCIIDOC_PY_FOUND ON)
|
||||
# Run the program directly and set ASCIIDOC as empty.
|
||||
set(ASCIIDOC_PY "${ASCIIDOC}")
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
bazel_dep(name = "bazel_skylib", version = "1.5.0")
|
||||
# Copyright (c) the JPEG XL Project Authors. All rights reserved.
|
||||
#
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
bazel_dep(name = "bazel_skylib", version = "1.7.1")
|
||||
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
|
||||
|
||||
|
@ -127,6 +130,7 @@ format: Cloudinary and Google.
|
|||
* [Test coverage on Codecov.io](https://app.codecov.io/gh/libjxl/libjxl) - for
|
||||
developers
|
||||
* [libjxl documentation on readthedocs.io](https://libjxl.readthedocs.io/)
|
||||
* The development of jpegli, the improved JPEG encoder and decoder, will continue at https://github.com/google/jpegli
|
||||
|
||||
### Contact
|
||||
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository", "new_git_repository")
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
# Copyright (c) the JPEG XL Project Authors. All rights reserved.
|
||||
#
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
workspace(name = "libjxl")
|
||||
|
||||
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository", "new_git_repository")
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
|
||||
local_repository(
|
||||
name = "highway",
|
||||
path = "third_party/highway",
|
||||
|
@ -30,185 +35,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",
|
||||
)
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
# Tests implemented in bash. These typically will run checks about the source
|
||||
# code rather than the compiled one.
|
||||
|
||||
MYDIR=$(dirname $(realpath "$0"))
|
||||
SELF=$(realpath "$0")
|
||||
MYDIR=$(dirname "${SELF}")
|
||||
|
||||
set -u
|
||||
|
||||
|
@ -106,12 +107,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
|
||||
|
|
|
@ -12,10 +12,13 @@ set -eu
|
|||
|
||||
OS=`uname -s`
|
||||
|
||||
MYDIR=$(dirname $(realpath "$0"))
|
||||
SELF=$(realpath "$0")
|
||||
MYDIR=$(dirname "${SELF}")
|
||||
|
||||
### 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 +82,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 +137,34 @@ 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_CANDIDATES=(
|
||||
clang-tidy
|
||||
clang-tidy-6.0
|
||||
clang-tidy-7
|
||||
clang-tidy-8
|
||||
clang-tidy-9
|
||||
clang-tidy-10
|
||||
clang-tidy-11
|
||||
clang-tidy-12
|
||||
clang-tidy-13
|
||||
clang-tidy-14
|
||||
clang-tidy-15
|
||||
clang-tidy-16
|
||||
clang-tidy-17
|
||||
clang-tidy-18
|
||||
)
|
||||
|
||||
CLANG_TIDY_BIN=${CLANG_TIDY_BIN:-$(which ${CLANG_TIDY_BIN_CANDIDATES[@]} 2>/dev/null | tail -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 +437,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 - \
|
||||
|
@ -459,7 +485,7 @@ strip_dead_code() {
|
|||
### Externally visible commands
|
||||
|
||||
cmd_debug() {
|
||||
CMAKE_BUILD_TYPE="Debug"
|
||||
CMAKE_BUILD_TYPE="DebugOpt"
|
||||
cmake_configure "$@"
|
||||
cmake_build_and_test
|
||||
}
|
||||
|
@ -473,7 +499,7 @@ cmd_release() {
|
|||
|
||||
cmd_opt() {
|
||||
CMAKE_BUILD_TYPE="RelWithDebInfo"
|
||||
CMAKE_CXX_FLAGS+=" -DJXL_DEBUG_WARNING -DJXL_DEBUG_ON_ERROR"
|
||||
CMAKE_CXX_FLAGS+=" -DJXL_IS_DEBUG_BUILD"
|
||||
cmake_configure "$@"
|
||||
cmake_build_and_test
|
||||
}
|
||||
|
@ -553,6 +579,7 @@ cmd_msanfuzz() {
|
|||
# Install msan if needed before changing the flags.
|
||||
detect_clang_version
|
||||
local msan_prefix="${HOME}/.msan/${CLANG_VERSION}"
|
||||
# TODO(eustas): why libc++abi.a is bad?
|
||||
if [[ ! -d "${msan_prefix}" || -e "${msan_prefix}/lib/libc++abi.a" ]]; then
|
||||
# Install msan libraries for this version if needed or if an older version
|
||||
# with libc++abi was installed.
|
||||
|
@ -566,9 +593,9 @@ cmd_msanfuzz() {
|
|||
|
||||
cmd_asan() {
|
||||
SANITIZER="asan"
|
||||
CMAKE_C_FLAGS+=" -DJXL_ENABLE_ASSERT=1 -g -DADDRESS_SANITIZER \
|
||||
CMAKE_C_FLAGS+=" -g -DADDRESS_SANITIZER \
|
||||
-fsanitize=address ${UBSAN_FLAGS[@]}"
|
||||
CMAKE_CXX_FLAGS+=" -DJXL_ENABLE_ASSERT=1 -g -DADDRESS_SANITIZER \
|
||||
CMAKE_CXX_FLAGS+=" -g -DADDRESS_SANITIZER \
|
||||
-fsanitize=address ${UBSAN_FLAGS[@]}"
|
||||
strip_dead_code
|
||||
cmake_configure "$@" -DJPEGXL_ENABLE_TCMALLOC=OFF
|
||||
|
@ -578,16 +605,13 @@ cmd_asan() {
|
|||
cmd_tsan() {
|
||||
SANITIZER="tsan"
|
||||
local tsan_args=(
|
||||
-DJXL_ENABLE_ASSERT=1
|
||||
-g
|
||||
-DTHREAD_SANITIZER
|
||||
${UBSAN_FLAGS[@]}
|
||||
-fsanitize=thread
|
||||
)
|
||||
CMAKE_C_FLAGS+=" ${tsan_args[@]}"
|
||||
CMAKE_CXX_FLAGS+=" ${tsan_args[@]}"
|
||||
|
||||
CMAKE_BUILD_TYPE="RelWithDebInfo"
|
||||
cmake_configure "$@" -DJPEGXL_ENABLE_TCMALLOC=OFF
|
||||
cmake_build_and_test
|
||||
}
|
||||
|
@ -606,7 +630,6 @@ cmd_msan() {
|
|||
-fsanitize=memory
|
||||
-fno-omit-frame-pointer
|
||||
|
||||
-DJXL_ENABLE_ASSERT=1
|
||||
-g
|
||||
-DMEMORY_SANITIZER
|
||||
|
||||
|
@ -639,16 +662,22 @@ cmd_msan() {
|
|||
-Wl,-rpath -Wl,"${msan_prefix}"/lib/
|
||||
)
|
||||
|
||||
CMAKE_C_FLAGS+=" ${msan_c_flags[@]} ${UBSAN_FLAGS[@]}"
|
||||
CMAKE_CXX_FLAGS+=" ${msan_cxx_flags[@]} ${UBSAN_FLAGS[@]}"
|
||||
CMAKE_C_FLAGS+=" ${msan_c_flags[@]}"
|
||||
CMAKE_CXX_FLAGS+=" ${msan_cxx_flags[@]}"
|
||||
CMAKE_EXE_LINKER_FLAGS+=" ${msan_linker_flags[@]}"
|
||||
CMAKE_MODULE_LINKER_FLAGS+=" ${msan_linker_flags[@]}"
|
||||
CMAKE_SHARED_LINKER_FLAGS+=" ${msan_linker_flags[@]}"
|
||||
strip_dead_code
|
||||
|
||||
# MSAN share of stack size is non-negligible.
|
||||
TEST_STACK_LIMIT="none"
|
||||
|
||||
# TODO(eustas): investigate why fuzzers do not link when MSAN libc++ is used
|
||||
cmake_configure "$@" \
|
||||
-DCMAKE_CROSSCOMPILING=1 -DRUN_HAVE_STD_REGEX=0 -DRUN_HAVE_POSIX_REGEX=0 \
|
||||
-DJPEGXL_ENABLE_TCMALLOC=OFF -DJPEGXL_WARNINGS_AS_ERRORS=OFF \
|
||||
-DCMAKE_REQUIRED_LINK_OPTIONS="${msan_linker_flags[@]}"
|
||||
-DCMAKE_REQUIRED_LINK_OPTIONS="${msan_linker_flags[@]}" \
|
||||
-DJPEGXL_ENABLE_FUZZERS=OFF
|
||||
cmake_build_and_test
|
||||
}
|
||||
|
||||
|
@ -657,6 +686,8 @@ cmd_msan() {
|
|||
cmd_msan_install() {
|
||||
local tmpdir=$(mktemp -d)
|
||||
CLEANUP_FILES+=("${tmpdir}")
|
||||
local msan_root="${HOME}/.msan"
|
||||
mkdir -p "${msan_root}"
|
||||
# Detect the llvm to install:
|
||||
export CC="${CC:-clang}"
|
||||
export CXX="${CXX:-clang++}"
|
||||
|
@ -664,23 +695,36 @@ cmd_msan_install() {
|
|||
# Allow overriding the LLVM checkout.
|
||||
local llvm_root="${LLVM_ROOT:-}"
|
||||
if [ -z "${llvm_root}" ]; then
|
||||
local llvm_tag="llvmorg-${CLANG_VERSION}.0.0"
|
||||
case "${CLANG_VERSION}" in
|
||||
"6.0")
|
||||
llvm_tag="llvmorg-6.0.1"
|
||||
;;
|
||||
"7")
|
||||
llvm_tag="llvmorg-7.0.1"
|
||||
;;
|
||||
esac
|
||||
local llvm_targz="${tmpdir}/${llvm_tag}.tar.gz"
|
||||
curl -L --show-error -o "${llvm_targz}" \
|
||||
"https://github.com/llvm/llvm-project/archive/${llvm_tag}.tar.gz"
|
||||
declare -A llvm_tag_by_version=(
|
||||
["6.0"]="6.0.1"
|
||||
["7"]="7.1.0"
|
||||
["8"]="8.0.1"
|
||||
["9"]="9.0.2"
|
||||
["10"]="10.0.1"
|
||||
["11"]="11.1.0"
|
||||
["12"]="12.0.1"
|
||||
["13"]="13.0.1"
|
||||
["14"]="14.0.6"
|
||||
["15"]="15.0.7"
|
||||
["16"]="16.0.6"
|
||||
["17"]="17.0.6"
|
||||
["18"]="18.1.6"
|
||||
)
|
||||
local llvm_tag="${CLANG_VERSION}.0.0"
|
||||
if [[ -n "${llvm_tag_by_version["${CLANG_VERSION}"]}" ]]; then
|
||||
llvm_tag=${llvm_tag_by_version["${CLANG_VERSION}"]}
|
||||
fi
|
||||
llvm_tag="llvmorg-${llvm_tag}"
|
||||
local llvm_targz="${msan_root}/${llvm_tag}.tar.gz"
|
||||
if [ ! -f "${llvm_targz}" ]; then
|
||||
curl -L --show-error -o "${llvm_targz}" \
|
||||
"https://github.com/llvm/llvm-project/archive/${llvm_tag}.tar.gz"
|
||||
fi
|
||||
tar -C "${tmpdir}" -zxf "${llvm_targz}"
|
||||
llvm_root="${tmpdir}/llvm-project-${llvm_tag}"
|
||||
fi
|
||||
|
||||
local msan_prefix="${HOME}/.msan/${CLANG_VERSION}"
|
||||
local msan_prefix="${msan_root}/${CLANG_VERSION}"
|
||||
rm -rf "${msan_prefix}"
|
||||
|
||||
local TARGET_OPTS=""
|
||||
|
@ -692,32 +736,29 @@ cmd_msan_install() {
|
|||
"
|
||||
fi
|
||||
|
||||
declare -A CMAKE_EXTRAS
|
||||
CMAKE_EXTRAS[libcxx]="\
|
||||
-DLIBCXX_CXX_ABI=libstdc++ \
|
||||
-DLIBCXX_INSTALL_EXPERIMENTAL_LIBRARY=ON"
|
||||
|
||||
for project in libcxx; do
|
||||
local proj_build="${tmpdir}/build-${project}"
|
||||
local proj_dir="${llvm_root}/${project}"
|
||||
mkdir -p "${proj_build}"
|
||||
cmake -B"${proj_build}" -H"${proj_dir}" \
|
||||
-G Ninja \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DLLVM_USE_SANITIZER=Memory \
|
||||
-DLLVM_PATH="${llvm_root}/llvm" \
|
||||
-DLLVM_CONFIG_PATH="$(which llvm-config llvm-config-7 llvm-config-6.0 | \
|
||||
head -n1)" \
|
||||
-DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS}" \
|
||||
-DCMAKE_C_FLAGS="${CMAKE_C_FLAGS}" \
|
||||
-DCMAKE_EXE_LINKER_FLAGS="${CMAKE_EXE_LINKER_FLAGS}" \
|
||||
-DCMAKE_SHARED_LINKER_FLAGS="${CMAKE_SHARED_LINKER_FLAGS}" \
|
||||
-DCMAKE_INSTALL_PREFIX="${msan_prefix}" \
|
||||
${TARGET_OPTS} \
|
||||
${CMAKE_EXTRAS[${project}]}
|
||||
cmake --build "${proj_build}"
|
||||
ninja -C "${proj_build}" install
|
||||
done
|
||||
local build_dir="${tmpdir}/build-llvm"
|
||||
mkdir -p "${build_dir}"
|
||||
cd ${llvm_root}
|
||||
cmake -B"${build_dir}" \
|
||||
-G Ninja \
|
||||
-S runtimes \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DLLVM_USE_SANITIZER=Memory \
|
||||
-DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind;compiler-rt" \
|
||||
-DLIBCXXABI_ENABLE_SHARED=ON \
|
||||
-DLIBCXXABI_ENABLE_STATIC=OFF \
|
||||
-DLIBCXX_ENABLE_SHARED=ON \
|
||||
-DLIBCXX_ENABLE_STATIC=OFF \
|
||||
-DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS}" \
|
||||
-DCMAKE_C_FLAGS="${CMAKE_C_FLAGS}" \
|
||||
-DCMAKE_EXE_LINKER_FLAGS="${CMAKE_EXE_LINKER_FLAGS}" \
|
||||
-DCMAKE_SHARED_LINKER_FLAGS="${CMAKE_SHARED_LINKER_FLAGS}" \
|
||||
-DCMAKE_INSTALL_PREFIX="${msan_prefix}" \
|
||||
-DLLVM_PATH="${llvm_root}/llvm" \
|
||||
-DLLVM_CONFIG_PATH="$(which llvm-config-${CLANG_VERSION} llvm-config | head -n1)" \
|
||||
${TARGET_OPTS}
|
||||
cmake --build "${build_dir}"
|
||||
ninja -C "${build_dir}" install
|
||||
}
|
||||
|
||||
# Internal build step shared between all cmd_ossfuzz_* commands.
|
||||
|
@ -791,9 +832,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 +876,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 +889,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 +903,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 +929,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.
|
||||
# Check error code for benchmark_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 +1083,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 +1132,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 +1148,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 +1178,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}/"
|
||||
)
|
||||
|
@ -1154,7 +1210,7 @@ cmd_lint() {
|
|||
# It is ok, if buildifier is not installed.
|
||||
if which buildifier >/dev/null; then
|
||||
local buildifier_patch="${tmpdir}/buildifier.patch"
|
||||
local bazel_files=`git -C ${MYDIR} ls-files | grep -E "/BUILD$|WORKSPACE|.bzl$"`
|
||||
local bazel_files=`git -C "${MYDIR}" ls-files | grep -E "/BUILD$|WORKSPACE|.bzl$"`
|
||||
set -x
|
||||
buildifier -d ${bazel_files} >"${buildifier_patch}"|| true
|
||||
{ set +x; } 2>/dev/null
|
||||
|
@ -1167,6 +1223,15 @@ cmd_lint() {
|
|||
fi
|
||||
fi
|
||||
|
||||
# It is ok, if spell-checker is not installed.
|
||||
if which typos >/dev/null; then
|
||||
local src_ext="bazel|bzl|c|cc|cmake|gni|h|html|in|java|js|m|md|nix|py|rst|sh|ts|txt|yaml|yml"
|
||||
local sources=`git -C "${MYDIR}" ls-files | grep -E "\.(${src_ext})$"`
|
||||
typos -c "${MYDIR}/tools/scripts/typos.toml" ${sources}
|
||||
else
|
||||
echo "Consider installing https://github.com/crate-ci/typos for spell-checking"
|
||||
fi
|
||||
|
||||
local installed=()
|
||||
local clang_patch
|
||||
local clang_format
|
||||
|
|
|
@ -10,7 +10,7 @@ if (PkgConfig_FOUND)
|
|||
endif ()
|
||||
|
||||
find_path(HWY_INCLUDE_DIR
|
||||
NAMES hwy/highway.h
|
||||
NAMES hwy/base.h hwy/highway.h
|
||||
HINTS ${PC_HWY_INCLUDEDIR} ${PC_HWY_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
|
@ -19,21 +19,31 @@ find_library(HWY_LIBRARY
|
|||
HINTS ${PC_HWY_LIBDIR} ${PC_HWY_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
# If version not found using pkg-config, try extracting it from header files
|
||||
if (HWY_INCLUDE_DIR AND NOT HWY_VERSION)
|
||||
if (EXISTS "${HWY_INCLUDE_DIR}/hwy/highway.h")
|
||||
file(READ "${HWY_INCLUDE_DIR}/hwy/highway.h" HWY_VERSION_CONTENT)
|
||||
set(HWY_VERSION "")
|
||||
set(HWY_POSSIBLE_HEADERS "${HWY_INCLUDE_DIR}/hwy/base.h" "${HWY_INCLUDE_DIR}/hwy/highway.h")
|
||||
foreach(HWY_HEADER_FILE IN LISTS HWY_POSSIBLE_HEADERS)
|
||||
if (EXISTS "${HWY_HEADER_FILE}")
|
||||
file(READ "${HWY_HEADER_FILE}" HWY_VERSION_CONTENT)
|
||||
|
||||
string(REGEX MATCH "#define HWY_MAJOR +([0-9]+)" _sink "${HWY_VERSION_CONTENT}")
|
||||
set(HWY_VERSION_MAJOR "${CMAKE_MATCH_1}")
|
||||
string(REGEX MATCH "#define HWY_MAJOR +([0-9]+)" _sink "${HWY_VERSION_CONTENT}")
|
||||
set(HWY_VERSION_MAJOR "${CMAKE_MATCH_1}")
|
||||
|
||||
string(REGEX MATCH "#define +HWY_MINOR +([0-9]+)" _sink "${HWY_VERSION_CONTENT}")
|
||||
set(HWY_VERSION_MINOR "${CMAKE_MATCH_1}")
|
||||
string(REGEX MATCH "#define +HWY_MINOR +([0-9]+)" _sink "${HWY_VERSION_CONTENT}")
|
||||
set(HWY_VERSION_MINOR "${CMAKE_MATCH_1}")
|
||||
|
||||
string(REGEX MATCH "#define +HWY_PATCH +([0-9]+)" _sink "${HWY_VERSION_CONTENT}")
|
||||
set(HWY_VERSION_PATCH "${CMAKE_MATCH_1}")
|
||||
|
||||
set(HWY_VERSION "${HWY_VERSION_MAJOR}.${HWY_VERSION_MINOR}.${HWY_VERSION_PATCH}")
|
||||
endif ()
|
||||
string(REGEX MATCH "#define +HWY_PATCH +([0-9]+)" _sink "${HWY_VERSION_CONTENT}")
|
||||
set(HWY_VERSION_PATCH "${CMAKE_MATCH_1}")
|
||||
if (NOT HWY_VERSION_MAJOR STREQUAL "" AND NOT HWY_VERSION_MINOR STREQUAL "" AND NOT HWY_VERSION_PATCH STREQUAL "")
|
||||
set(HWY_VERSION "${HWY_VERSION_MAJOR}.${HWY_VERSION_MINOR}.${HWY_VERSION_PATCH}")
|
||||
break()
|
||||
endif()
|
||||
endif ()
|
||||
endforeach ()
|
||||
if (NOT HWY_VERSION)
|
||||
message(WARNING "Highway version not found.")
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
jpeg-xl (0.10.3) UNRELEASED; urgency=medium
|
||||
jpeg-xl (0.11.0) unstable; urgency=medium
|
||||
|
||||
* Bump JPEG XL version to 0.10.3.
|
||||
* Bump JPEG XL version to 0.11.0.
|
||||
|
||||
-- JPEG XL Maintainers <jpegxl@google.com> Thu, 27 Jun 2024 12:23:45 +0200
|
||||
-- JPEG XL Maintainers <jpegxl@google.com> Tue, 06 Aug 2024 14:35:34 +0200
|
||||
|
||||
jpeg-xl (0.10.2) unstable; urgency=medium
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -9,13 +9,15 @@
|
|||
|
||||
set -eu
|
||||
|
||||
MYDIR=$(dirname $(realpath "$0"))
|
||||
SELF=$(realpath "$0")
|
||||
MYDIR=$(dirname "${SELF}")
|
||||
|
||||
# Git revisions we use for the given submodules. Update these whenever you
|
||||
# update a git submodule.
|
||||
TESTDATA="873045a9c42ed60721756e26e2a6b32e17415205"
|
||||
THIRD_PARTY_BROTLI="36533a866ed1ca4b75cf049f4521e4ec5fe24727"
|
||||
THIRD_PARTY_HIGHWAY="58b52a717469e62b2d9b8eaa2f5dddb44d4a4cbf"
|
||||
THIRD_PARTY_GOOGLETEST="58d77fa8070e8cec2dc1ed015d66b454c8d78850"
|
||||
THIRD_PARTY_HIGHWAY="457c891775a7397bdb0376bb1031e6e027af1c48"
|
||||
THIRD_PARTY_SKCMS="42030a771244ba67f86b1c1c76a6493f873c5f91"
|
||||
THIRD_PARTY_SJPEG="e5ab13008bb214deb66d5f3e17ca2f8dbff150bf"
|
||||
THIRD_PARTY_ZLIB="51b7f2abdade71cd9bb0e7a373ef2610ec6f9daf" # v1.3.1
|
||||
|
@ -82,6 +84,7 @@ EOF
|
|||
# Sources downloaded from a tarball.
|
||||
download_github testdata libjxl/testdata
|
||||
download_github third_party/brotli google/brotli
|
||||
download_github third_party/googletest google/googletest
|
||||
download_github third_party/highway google/highway
|
||||
download_github third_party/sjpeg webmproject/sjpeg
|
||||
download_github third_party/skcms \
|
||||
|
|
|
@ -15,6 +15,9 @@ pkg_check_modules(Jxl REQUIRED IMPORTED_TARGET libjxl libjxl_cms libjxl_threads)
|
|||
|
||||
# Build the example encoder/decoder binaries using the default shared libraries
|
||||
# installed.
|
||||
add_executable(decode_exif_metadata decode_exif_metadata.cc)
|
||||
target_link_libraries(decode_exif_metadata PkgConfig::Jxl)
|
||||
|
||||
add_executable(decode_oneshot decode_oneshot.cc)
|
||||
target_link_libraries(decode_oneshot PkgConfig::Jxl)
|
||||
|
||||
|
|
|
@ -22,7 +22,8 @@ bool DecodeJpegXlExif(const uint8_t* jxl, size_t size,
|
|||
|
||||
// We're only interested in the Exif boxes in this example, so don't
|
||||
// subscribe to events related to pixel data.
|
||||
if (JXL_DEC_SUCCESS != JxlDecoderSubscribeEvents(dec.get(), JXL_DEC_BOX)) {
|
||||
if (JXL_DEC_SUCCESS != JxlDecoderSubscribeEvents(
|
||||
dec.get(), JXL_DEC_BOX | JXL_DEC_BOX_COMPLETE)) {
|
||||
fprintf(stderr, "JxlDecoderSubscribeEvents failed\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -72,7 +73,7 @@ bool DecodeJpegXlExif(const uint8_t* jxl, size_t size,
|
|||
exif->resize(exif->size() + kChunkSize);
|
||||
JxlDecoderSetBoxBuffer(dec.get(), exif->data() + output_pos,
|
||||
exif->size() - output_pos);
|
||||
} else if (status == JXL_DEC_SUCCESS) {
|
||||
} else if (status == JXL_DEC_BOX_COMPLETE) {
|
||||
if (!exif->empty()) {
|
||||
size_t remaining = JxlDecoderReleaseBoxBuffer(dec.get());
|
||||
exif->resize(exif->size() - remaining);
|
||||
|
@ -97,7 +98,7 @@ bool LoadFile(const char* filename, std::vector<uint8_t>* out) {
|
|||
return false;
|
||||
}
|
||||
|
||||
long size = ftell(file);
|
||||
long size = ftell(file); // NOLINT
|
||||
// Avoid invalid file or directory.
|
||||
if (size >= LONG_MAX || size < 0) {
|
||||
fclose(file);
|
||||
|
|
|
@ -169,7 +169,7 @@ bool LoadFile(const char* filename, std::vector<uint8_t>* out) {
|
|||
return false;
|
||||
}
|
||||
|
||||
long size = ftell(file);
|
||||
long size = ftell(file); // NOLINT
|
||||
// Avoid invalid file or directory.
|
||||
if (size >= LONG_MAX || size < 0) {
|
||||
fclose(file);
|
||||
|
|
|
@ -6,16 +6,20 @@
|
|||
// This C++ example decodes a JPEG XL image progressively (input bytes are
|
||||
// passed in chunks). The example outputs the intermediate steps to PAM files.
|
||||
|
||||
#include <inttypes.h>
|
||||
#ifndef __STDC_FORMAT_MACROS
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#endif
|
||||
|
||||
#include <jxl/decode.h>
|
||||
#include <jxl/decode_cxx.h>
|
||||
#include <jxl/resizable_parallel_runner.h>
|
||||
#include <jxl/resizable_parallel_runner_cxx.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <cinttypes> // PRIu64
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
bool WritePAM(const char* filename, const uint8_t* buffer, size_t w, size_t h) {
|
||||
|
@ -174,7 +178,7 @@ bool LoadFile(const char* filename, std::vector<uint8_t>* out) {
|
|||
return false;
|
||||
}
|
||||
|
||||
long size = ftell(file);
|
||||
long size = ftell(file); // NOLINT
|
||||
// Avoid invalid file or directory.
|
||||
if (size >= LONG_MAX || size < 0) {
|
||||
fclose(file);
|
||||
|
@ -220,7 +224,7 @@ int main(int argc, char* argv[]) {
|
|||
}
|
||||
size_t chunksize = jxl.size();
|
||||
if (argc > 3) {
|
||||
long cs = atol(argv[3]);
|
||||
long cs = atol(argv[3]); // NOLINT
|
||||
if (cs < 100) {
|
||||
fprintf(stderr, "Chunk size is too low, try at least 100 bytes\n");
|
||||
return 1;
|
||||
|
|
|
@ -48,7 +48,7 @@ bool ReadPFM(const char* filename, std::vector<float>* pixels, uint32_t* xsize,
|
|||
return false;
|
||||
}
|
||||
|
||||
long size = ftell(file);
|
||||
long size = ftell(file); // NOLINT
|
||||
// Avoid invalid file or directory.
|
||||
if (size >= LONG_MAX || size < 0) {
|
||||
fclose(file);
|
||||
|
@ -64,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 (static_cast<long>(readsize) != size) {
|
||||
if (static_cast<long>(readsize) != size) { // NOLINT
|
||||
fclose(file);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
add_executable(decode_exif_metadata ${CMAKE_CURRENT_LIST_DIR}/decode_exif_metadata.cc)
|
||||
target_link_libraries(decode_exif_metadata jxl_dec jxl_threads)
|
||||
add_executable(decode_oneshot ${CMAKE_CURRENT_LIST_DIR}/decode_oneshot.cc)
|
||||
target_link_libraries(decode_oneshot jxl_dec jxl_threads)
|
||||
add_executable(decode_progressive ${CMAKE_CURRENT_LIST_DIR}/decode_progressive.cc)
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
cmake
|
||||
pkg-config
|
||||
gtest
|
||||
gmock
|
||||
doxygen
|
||||
graphviz
|
||||
python3
|
||||
|
|
|
@ -26,8 +26,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",
|
||||
|
@ -54,7 +54,8 @@ 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",
|
||||
|
@ -67,7 +68,7 @@ DEFAULT_COMPATIBILITY = []
|
|||
INCLUDES_DIR = "include"
|
||||
|
||||
package(
|
||||
default_visibility = ["//:__subpackages__"],
|
||||
default_visibility = DEFAULT_VISIBILITY,
|
||||
)
|
||||
|
||||
licenses(["notice"])
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
# license that can be found in the LICENSE file.
|
||||
|
||||
set(JPEGXL_MAJOR_VERSION 0)
|
||||
set(JPEGXL_MINOR_VERSION 10)
|
||||
set(JPEGXL_PATCH_VERSION 3)
|
||||
set(JPEGXL_MINOR_VERSION 11)
|
||||
set(JPEGXL_PATCH_VERSION 0)
|
||||
set(JPEGXL_LIBRARY_VERSION
|
||||
"${JPEGXL_MAJOR_VERSION}.${JPEGXL_MINOR_VERSION}.${JPEGXL_PATCH_VERSION}")
|
||||
|
||||
|
@ -15,7 +15,7 @@ set(JPEGXL_LIBRARY_VERSION
|
|||
# It is important to update this value when making incompatible API/ABI changes
|
||||
# so that programs that depend on libjxl can update their dependencies. Semantic
|
||||
# versioning allows 0.y.z to have incompatible changes in minor versions.
|
||||
set(JPEGXL_SO_MINOR_VERSION 10)
|
||||
set(JPEGXL_SO_MINOR_VERSION 11)
|
||||
if (JPEGXL_MAJOR_VERSION EQUAL 0)
|
||||
set(JPEGXL_LIBRARY_SOVERSION
|
||||
"${JPEGXL_MAJOR_VERSION}.${JPEGXL_SO_MINOR_VERSION}")
|
||||
|
|
|
@ -6,21 +6,23 @@
|
|||
#include "lib/extras/alpha_blend.h"
|
||||
|
||||
#include "lib/extras/packed_image.h"
|
||||
#include "lib/jxl/base/status.h"
|
||||
|
||||
namespace jxl {
|
||||
namespace extras {
|
||||
|
||||
namespace {
|
||||
|
||||
void AlphaBlend(PackedFrame* frame, const float background[3]) {
|
||||
if (!frame) return;
|
||||
Status AlphaBlend(PackedFrame* frame, const float background[3]) {
|
||||
if (!frame) return true;
|
||||
const PackedImage& im = frame->color;
|
||||
JxlPixelFormat format = im.format;
|
||||
if (format.num_channels != 2 && format.num_channels != 4) {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
--format.num_channels;
|
||||
PackedImage blended(im.xsize, im.ysize, format);
|
||||
JXL_ASSIGN_OR_RETURN(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) {
|
||||
|
@ -44,19 +46,21 @@ void AlphaBlend(PackedFrame* frame, const float background[3]) {
|
|||
}
|
||||
}
|
||||
frame->color = blended.Copy();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void AlphaBlend(PackedPixelFile* ppf, const float background[3]) {
|
||||
Status AlphaBlend(PackedPixelFile* ppf, const float background[3]) {
|
||||
if (!ppf || ppf->info.alpha_bits == 0) {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
ppf->info.alpha_bits = 0;
|
||||
AlphaBlend(ppf->preview_frame.get(), background);
|
||||
JXL_RETURN_IF_ERROR(AlphaBlend(ppf->preview_frame.get(), background));
|
||||
for (auto& frame : ppf->frames) {
|
||||
AlphaBlend(&frame, background);
|
||||
JXL_RETURN_IF_ERROR(AlphaBlend(&frame, background));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace extras
|
||||
|
|
|
@ -7,11 +7,12 @@
|
|||
#define LIB_EXTRAS_ALPHA_BLEND_H_
|
||||
|
||||
#include "lib/extras/packed_image.h"
|
||||
#include "lib/jxl/base/status.h"
|
||||
|
||||
namespace jxl {
|
||||
namespace extras {
|
||||
|
||||
void AlphaBlend(PackedPixelFile* ppf, const float background[3]);
|
||||
Status AlphaBlend(PackedPixelFile* ppf, const float background[3]);
|
||||
|
||||
} // namespace extras
|
||||
} // namespace jxl
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include "lib/extras/packed_image.h"
|
||||
#include "lib/extras/packed_image_convert.h"
|
||||
#include "lib/jxl/base/status.h"
|
||||
#include "lib/jxl/image_bundle.h"
|
||||
|
||||
namespace jxl {
|
||||
namespace {
|
||||
|
@ -95,7 +94,7 @@ Status Encode(const extras::PackedPixelFile& ppf, const extras::Codec codec,
|
|||
}
|
||||
extras::EncodedImage encoded_image;
|
||||
JXL_RETURN_IF_ERROR(encoder->Encode(ppf, &encoded_image, pool));
|
||||
JXL_ASSERT(encoded_image.bitstreams.size() == 1);
|
||||
JXL_ENSURE(encoded_image.bitstreams.size() == 1);
|
||||
*bytes = encoded_image.bitstreams[0];
|
||||
|
||||
return true;
|
||||
|
|
|
@ -7,11 +7,12 @@
|
|||
#include <jxl/color_encoding.h>
|
||||
#include <jxl/encode.h>
|
||||
#include <jxl/types.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
@ -22,10 +23,11 @@
|
|||
#include "lib/extras/common.h"
|
||||
#include "lib/extras/dec/color_hints.h"
|
||||
#include "lib/extras/dec/decode.h"
|
||||
#include "lib/extras/dec/pnm.h"
|
||||
#include "lib/extras/enc/encode.h"
|
||||
#include "lib/extras/packed_image.h"
|
||||
#include "lib/jxl/base/byte_order.h"
|
||||
#include "lib/jxl/base/compiler_specific.h"
|
||||
#include "lib/jxl/base/data_parallel.h"
|
||||
#include "lib/jxl/base/random.h"
|
||||
#include "lib/jxl/base/span.h"
|
||||
#include "lib/jxl/base/status.h"
|
||||
|
@ -35,16 +37,18 @@
|
|||
|
||||
namespace jxl {
|
||||
|
||||
using test::ThreadPoolForTests;
|
||||
using ::jxl::test::ThreadPoolForTests;
|
||||
|
||||
namespace extras {
|
||||
|
||||
Status PnmParseSigned(Bytes str, double* v);
|
||||
Status PnmParseUnsigned(Bytes str, size_t* v);
|
||||
|
||||
namespace {
|
||||
|
||||
using ::testing::AllOf;
|
||||
using ::testing::Contains;
|
||||
using ::testing::Field;
|
||||
using ::testing::IsEmpty;
|
||||
using ::testing::SizeIs;
|
||||
Span<const uint8_t> MakeSpan(const char* str) {
|
||||
return Bytes(reinterpret_cast<const uint8_t*>(str), strlen(str));
|
||||
}
|
||||
|
||||
std::string ExtensionFromCodec(Codec codec, const bool is_gray,
|
||||
const bool has_alpha,
|
||||
|
@ -112,15 +116,15 @@ JxlColorEncoding CreateTestColorEncoding(bool is_gray) {
|
|||
// Roundtrip through internal color encoding to fill in primaries and white
|
||||
// point CIE xy coordinates.
|
||||
ColorEncoding c_internal;
|
||||
JXL_CHECK(c_internal.FromExternal(c));
|
||||
EXPECT_TRUE(c_internal.FromExternal(c));
|
||||
c = c_internal.ToExternal();
|
||||
return c;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> GenerateICC(JxlColorEncoding color_encoding) {
|
||||
ColorEncoding c;
|
||||
JXL_CHECK(c.FromExternal(color_encoding));
|
||||
JXL_CHECK(!c.ICC().empty());
|
||||
EXPECT_TRUE(c.FromExternal(color_encoding));
|
||||
EXPECT_TRUE(!c.ICC().empty());
|
||||
return c.ICC();
|
||||
}
|
||||
|
||||
|
@ -233,13 +237,17 @@ void CreateTestImage(const TestImageParams& params, PackedPixelFile* ppf) {
|
|||
ppf->icc = GenerateICC(color_encoding);
|
||||
ppf->color_encoding = color_encoding;
|
||||
|
||||
PackedFrame frame(params.xsize, params.ysize, params.PixelFormat());
|
||||
JXL_TEST_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_TEST_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;
|
||||
|
@ -335,10 +343,10 @@ TEST(CodecTest, TestRoundTrip) {
|
|||
params.add_alpha = add_alpha;
|
||||
params.big_endian = big_endian;
|
||||
params.add_extra_channels = false;
|
||||
TestRoundTrip(params, &pool);
|
||||
TestRoundTrip(params, pool.get());
|
||||
if (codec == Codec::kPNM && add_alpha) {
|
||||
params.add_extra_channels = true;
|
||||
TestRoundTrip(params, &pool);
|
||||
TestRoundTrip(params, pool.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -371,7 +379,7 @@ TEST(CodecTest, LosslessPNMRoundtrip) {
|
|||
EncodedImage encoded;
|
||||
auto encoder = Encoder::FromExtension(extension);
|
||||
ASSERT_TRUE(encoder.get());
|
||||
ASSERT_TRUE(encoder->Encode(ppf, &encoded, &pool));
|
||||
ASSERT_TRUE(encoder->Encode(ppf, &encoded, pool.get()));
|
||||
ASSERT_EQ(encoded.bitstreams.size(), 1);
|
||||
ASSERT_EQ(orig.size(), encoded.bitstreams[0].size());
|
||||
EXPECT_EQ(0,
|
||||
|
@ -380,7 +388,40 @@ TEST(CodecTest, LosslessPNMRoundtrip) {
|
|||
}
|
||||
}
|
||||
|
||||
TEST(CodecTest, TestPNM) { TestCodecPNM(); }
|
||||
TEST(CodecTest, TestPNM) {
|
||||
size_t u = 77777; // Initialized to wrong value.
|
||||
double d = 77.77;
|
||||
// Failing to parse invalid strings results in a crash if `JXL_CRASH_ON_ERROR`
|
||||
// is defined and hence the tests fail. Therefore we only run these tests if
|
||||
// `JXL_CRASH_ON_ERROR` is not defined.
|
||||
#if (!JXL_CRASH_ON_ERROR)
|
||||
ASSERT_FALSE(PnmParseUnsigned(MakeSpan(""), &u));
|
||||
ASSERT_FALSE(PnmParseUnsigned(MakeSpan("+"), &u));
|
||||
ASSERT_FALSE(PnmParseUnsigned(MakeSpan("-"), &u));
|
||||
ASSERT_FALSE(PnmParseUnsigned(MakeSpan("A"), &u));
|
||||
|
||||
ASSERT_FALSE(PnmParseSigned(MakeSpan(""), &d));
|
||||
ASSERT_FALSE(PnmParseSigned(MakeSpan("+"), &d));
|
||||
ASSERT_FALSE(PnmParseSigned(MakeSpan("-"), &d));
|
||||
ASSERT_FALSE(PnmParseSigned(MakeSpan("A"), &d));
|
||||
#endif
|
||||
ASSERT_TRUE(PnmParseUnsigned(MakeSpan("1"), &u));
|
||||
ASSERT_TRUE(u == 1);
|
||||
|
||||
ASSERT_TRUE(PnmParseUnsigned(MakeSpan("32"), &u));
|
||||
ASSERT_TRUE(u == 32);
|
||||
|
||||
ASSERT_TRUE(PnmParseSigned(MakeSpan("1"), &d));
|
||||
ASSERT_TRUE(d == 1.0);
|
||||
ASSERT_TRUE(PnmParseSigned(MakeSpan("+2"), &d));
|
||||
ASSERT_TRUE(d == 2.0);
|
||||
ASSERT_TRUE(PnmParseSigned(MakeSpan("-3"), &d));
|
||||
ASSERT_TRUE(std::abs(d - -3.0) < 1E-15);
|
||||
ASSERT_TRUE(PnmParseSigned(MakeSpan("3.141592"), &d));
|
||||
ASSERT_TRUE(std::abs(d - 3.141592) < 1E-15);
|
||||
ASSERT_TRUE(PnmParseSigned(MakeSpan("-3.141592"), &d));
|
||||
ASSERT_TRUE(std::abs(d - -3.141592) < 1E-15);
|
||||
}
|
||||
|
||||
TEST(CodecTest, FormatNegotiation) {
|
||||
const std::vector<JxlPixelFormat> accepted_formats = {
|
||||
|
@ -432,15 +473,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()),
|
||||
|
|
|
@ -27,6 +27,7 @@ Status SelectFormat(const std::vector<JxlPixelFormat>& accepted_formats,
|
|||
for (;;) {
|
||||
for (const JxlPixelFormat& candidate : accepted_formats) {
|
||||
if (candidate.num_channels != num_channels) continue;
|
||||
JXL_RETURN_IF_ERROR(PackedImage::ValidateDataType(candidate.data_type));
|
||||
const size_t candidate_bit_depth =
|
||||
PackedImage::BitsPerChannel(candidate.data_type);
|
||||
if (
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
// Copyright (c) the JPEG XL Project Authors. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include <jxl/compressed_icc.h>
|
||||
|
||||
#include "lib/jxl/base/span.h"
|
||||
#include "lib/jxl/enc_aux_out.h"
|
||||
#include "lib/jxl/enc_icc_codec.h"
|
||||
#include "lib/jxl/icc_codec.h"
|
||||
|
||||
JXL_BOOL JxlICCProfileEncode(const JxlMemoryManager* memory_manager,
|
||||
const uint8_t* icc, size_t icc_size,
|
||||
uint8_t** compressed_icc,
|
||||
size_t* compressed_icc_size) {
|
||||
JxlMemoryManager local_memory_manager;
|
||||
if (!jxl::MemoryManagerInit(&local_memory_manager, memory_manager)) {
|
||||
return JXL_FALSE;
|
||||
}
|
||||
jxl::BitWriter writer(&local_memory_manager);
|
||||
JXL_RETURN_IF_ERROR(jxl::WriteICC(jxl::Span<const uint8_t>(icc, icc_size),
|
||||
&writer, jxl::LayerType::Header, nullptr));
|
||||
writer.ZeroPadToByte();
|
||||
jxl::Bytes bytes = writer.GetSpan();
|
||||
*compressed_icc_size = bytes.size();
|
||||
*compressed_icc = static_cast<uint8_t*>(
|
||||
jxl::MemoryManagerAlloc(&local_memory_manager, *compressed_icc_size));
|
||||
memcpy(*compressed_icc, bytes.data(), bytes.size());
|
||||
return JXL_TRUE;
|
||||
}
|
||||
|
||||
JXL_BOOL JxlICCProfileDecode(const JxlMemoryManager* memory_manager,
|
||||
const uint8_t* compressed_icc,
|
||||
size_t compressed_icc_size, uint8_t** icc,
|
||||
size_t* icc_size) {
|
||||
JxlMemoryManager local_memory_manager;
|
||||
if (!jxl::MemoryManagerInit(&local_memory_manager, memory_manager)) {
|
||||
return JXL_FALSE;
|
||||
}
|
||||
jxl::ICCReader icc_reader(&local_memory_manager);
|
||||
jxl::PaddedBytes decompressed(&local_memory_manager);
|
||||
jxl::BitReader bit_reader(
|
||||
jxl::Span<const uint8_t>(compressed_icc, compressed_icc_size));
|
||||
JXL_RETURN_IF_ERROR(icc_reader.Init(&bit_reader));
|
||||
JXL_RETURN_IF_ERROR(icc_reader.Process(&bit_reader, &decompressed));
|
||||
JXL_RETURN_IF_ERROR(bit_reader.Close());
|
||||
*icc_size = decompressed.size();
|
||||
*icc = static_cast<uint8_t*>(
|
||||
jxl::MemoryManagerAlloc(&local_memory_manager, *icc_size));
|
||||
memcpy(*icc, decompressed.data(), *icc_size);
|
||||
return JXL_TRUE;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright (c) the JPEG XL Project Authors. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "jxl/compressed_icc.h"
|
||||
|
||||
#include <jxl/memory_manager.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
#include "lib/jxl/color_encoding_internal.h"
|
||||
#include "lib/jxl/test_memory_manager.h"
|
||||
#include "lib/jxl/test_utils.h"
|
||||
#include "lib/jxl/testing.h"
|
||||
|
||||
namespace jxl {
|
||||
namespace {
|
||||
|
||||
TEST(CompressedIccTest, Roundtrip) {
|
||||
JxlMemoryManager* memory_manager = jxl::test::MemoryManager();
|
||||
uint8_t* compressed_icc;
|
||||
size_t compressed_icc_size;
|
||||
const IccBytes icc = jxl::test::GetIccTestProfile();
|
||||
ASSERT_TRUE(JxlICCProfileEncode(memory_manager, icc.data(), icc.size(),
|
||||
&compressed_icc, &compressed_icc_size));
|
||||
|
||||
EXPECT_LT(compressed_icc_size, icc.size());
|
||||
|
||||
uint8_t* decompressed_icc;
|
||||
size_t decompressed_icc_size;
|
||||
ASSERT_TRUE(JxlICCProfileDecode(memory_manager, compressed_icc,
|
||||
compressed_icc_size, &decompressed_icc,
|
||||
&decompressed_icc_size));
|
||||
|
||||
ASSERT_EQ(decompressed_icc_size, icc.size());
|
||||
|
||||
EXPECT_EQ(0, memcmp(decompressed_icc, icc.data(), decompressed_icc_size));
|
||||
|
||||
memory_manager->free(memory_manager->opaque, compressed_icc);
|
||||
memory_manager->free(memory_manager->opaque, decompressed_icc);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace jxl
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -8,11 +8,10 @@
|
|||
|
||||
// Decodes APNG images in memory.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cstdint>
|
||||
|
||||
#include "lib/extras/dec/color_hints.h"
|
||||
#include "lib/extras/packed_image.h"
|
||||
#include "lib/jxl/base/data_parallel.h"
|
||||
#include "lib/jxl/base/span.h"
|
||||
#include "lib/jxl/base/status.h"
|
||||
|
||||
|
|
|
@ -164,7 +164,7 @@ Status ParsePrimaries(Tokenizer* tokenizer, JxlColorEncoding* c) {
|
|||
JXL_RETURN_IF_ERROR(ParseDouble(&xy_tokenizer, c->primaries_blue_xy + 1));
|
||||
c->primaries = JXL_PRIMARIES_CUSTOM;
|
||||
|
||||
return JXL_FAILURE("Invalid primaries %s", str.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
Status ParseRenderingIntent(Tokenizer* tokenizer, JxlColorEncoding* c) {
|
||||
|
@ -203,12 +203,38 @@ Status ParseTransferFunction(Tokenizer* tokenizer, JxlColorEncoding* c) {
|
|||
|
||||
Status ParseDescription(const std::string& description, JxlColorEncoding* c) {
|
||||
*c = {};
|
||||
Tokenizer tokenizer(&description, '_');
|
||||
JXL_RETURN_IF_ERROR(ParseColorSpace(&tokenizer, c));
|
||||
JXL_RETURN_IF_ERROR(ParseWhitePoint(&tokenizer, c));
|
||||
JXL_RETURN_IF_ERROR(ParsePrimaries(&tokenizer, c));
|
||||
JXL_RETURN_IF_ERROR(ParseRenderingIntent(&tokenizer, c));
|
||||
JXL_RETURN_IF_ERROR(ParseTransferFunction(&tokenizer, c));
|
||||
if (description == "sRGB") {
|
||||
c->color_space = JXL_COLOR_SPACE_RGB;
|
||||
c->white_point = JXL_WHITE_POINT_D65;
|
||||
c->primaries = JXL_PRIMARIES_SRGB;
|
||||
c->transfer_function = JXL_TRANSFER_FUNCTION_SRGB;
|
||||
c->rendering_intent = JXL_RENDERING_INTENT_PERCEPTUAL;
|
||||
} else if (description == "DisplayP3") {
|
||||
c->color_space = JXL_COLOR_SPACE_RGB;
|
||||
c->white_point = JXL_WHITE_POINT_D65;
|
||||
c->primaries = JXL_PRIMARIES_P3;
|
||||
c->transfer_function = JXL_TRANSFER_FUNCTION_SRGB;
|
||||
c->rendering_intent = JXL_RENDERING_INTENT_PERCEPTUAL;
|
||||
} else if (description == "Rec2100PQ") {
|
||||
c->color_space = JXL_COLOR_SPACE_RGB;
|
||||
c->white_point = JXL_WHITE_POINT_D65;
|
||||
c->primaries = JXL_PRIMARIES_2100;
|
||||
c->transfer_function = JXL_TRANSFER_FUNCTION_PQ;
|
||||
c->rendering_intent = JXL_RENDERING_INTENT_RELATIVE;
|
||||
} else if (description == "Rec2100HLG") {
|
||||
c->color_space = JXL_COLOR_SPACE_RGB;
|
||||
c->white_point = JXL_WHITE_POINT_D65;
|
||||
c->primaries = JXL_PRIMARIES_2100;
|
||||
c->transfer_function = JXL_TRANSFER_FUNCTION_HLG;
|
||||
c->rendering_intent = JXL_RENDERING_INTENT_RELATIVE;
|
||||
} else {
|
||||
Tokenizer tokenizer(&description, '_');
|
||||
JXL_RETURN_IF_ERROR(ParseColorSpace(&tokenizer, c));
|
||||
JXL_RETURN_IF_ERROR(ParseWhitePoint(&tokenizer, c));
|
||||
JXL_RETURN_IF_ERROR(ParsePrimaries(&tokenizer, c));
|
||||
JXL_RETURN_IF_ERROR(ParseRenderingIntent(&tokenizer, c));
|
||||
JXL_RETURN_IF_ERROR(ParseTransferFunction(&tokenizer, c));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -91,6 +91,15 @@ bool CanDecode(Codec codec) {
|
|||
}
|
||||
}
|
||||
|
||||
std::string ListOfDecodeCodecs() {
|
||||
std::string list_of_codecs("JXL, PPM, PNM, PFM, PAM, PGX");
|
||||
if (CanDecode(Codec::kPNG)) list_of_codecs.append(", PNG, APNG");
|
||||
if (CanDecode(Codec::kGIF)) list_of_codecs.append(", GIF");
|
||||
if (CanDecode(Codec::kJPG)) list_of_codecs.append(", JPEG");
|
||||
if (CanDecode(Codec::kEXR)) list_of_codecs.append(", EXR");
|
||||
return list_of_codecs;
|
||||
}
|
||||
|
||||
Status DecodeBytes(const Span<const uint8_t> bytes,
|
||||
const ColorHints& color_hints, extras::PackedPixelFile* ppf,
|
||||
const SizeConstraints* constraints, Codec* orig_codec) {
|
||||
|
|
|
@ -8,11 +8,9 @@
|
|||
|
||||
// Facade for image decoders (PNG, PNM, ...).
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "lib/extras/dec/color_hints.h"
|
||||
#include "lib/jxl/base/span.h"
|
||||
|
@ -38,6 +36,8 @@ enum class Codec : uint32_t {
|
|||
|
||||
bool CanDecode(Codec codec);
|
||||
|
||||
std::string ListOfDecodeCodecs();
|
||||
|
||||
// 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(const std::string& path,
|
||||
|
|
|
@ -5,19 +5,51 @@
|
|||
|
||||
#include "lib/extras/dec/exr.h"
|
||||
|
||||
#if JPEGXL_ENABLE_EXR
|
||||
#include <cstdint>
|
||||
|
||||
#include "lib/extras/dec/color_hints.h"
|
||||
#include "lib/extras/packed_image.h"
|
||||
#include "lib/jxl/base/common.h"
|
||||
#include "lib/jxl/base/span.h"
|
||||
#include "lib/jxl/base/status.h"
|
||||
|
||||
#if !JPEGXL_ENABLE_EXR
|
||||
|
||||
namespace jxl {
|
||||
namespace extras {
|
||||
bool CanDecodeEXR() { return false; }
|
||||
|
||||
Status DecodeImageEXR(Span<const uint8_t> bytes, const ColorHints& color_hints,
|
||||
PackedPixelFile* ppf,
|
||||
const SizeConstraints* constraints) {
|
||||
(void)bytes;
|
||||
(void)color_hints;
|
||||
(void)ppf;
|
||||
(void)constraints;
|
||||
return JXL_FAILURE("EXR is not supported");
|
||||
}
|
||||
} // namespace extras
|
||||
} // namespace jxl
|
||||
|
||||
#else // JPEGXL_ENABLE_EXR
|
||||
|
||||
#include <ImfChromaticitiesAttribute.h>
|
||||
#include <ImfIO.h>
|
||||
#include <ImfRgbaFile.h>
|
||||
#include <ImfStandardAttributes.h>
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
|
||||
#ifdef __EXCEPTIONS
|
||||
#include <stdexcept>
|
||||
#define JXL_EXR_THROW_LENGTH_ERROR() throw std::length_error("");
|
||||
#else // __EXCEPTIONS
|
||||
#define JXL_EXR_THROW_LENGTH_ERROR() JXL_CRASH()
|
||||
#endif // __EXCEPTIONS
|
||||
|
||||
namespace jxl {
|
||||
namespace extras {
|
||||
|
||||
#if JPEGXL_ENABLE_EXR
|
||||
namespace {
|
||||
|
||||
namespace OpenEXR = OPENEXR_IMF_NAMESPACE;
|
||||
|
@ -39,7 +71,9 @@ class InMemoryIStream : public OpenEXR::IStream {
|
|||
|
||||
bool isMemoryMapped() const override { return true; }
|
||||
char* readMemoryMapped(const int n) override {
|
||||
JXL_ASSERT(pos_ + n <= bytes_.size());
|
||||
if (pos_ + n < pos_ || pos_ + n > bytes_.size()) {
|
||||
JXL_EXR_THROW_LENGTH_ERROR();
|
||||
}
|
||||
char* const result =
|
||||
const_cast<char*>(reinterpret_cast<const char*>(bytes_.data() + pos_));
|
||||
pos_ += n;
|
||||
|
@ -52,7 +86,9 @@ class InMemoryIStream : public OpenEXR::IStream {
|
|||
|
||||
ExrInt64 tellg() override { return pos_; }
|
||||
void seekg(const ExrInt64 pos) override {
|
||||
JXL_ASSERT(pos + 1 <= bytes_.size());
|
||||
if (pos >= bytes_.size()) {
|
||||
JXL_EXR_THROW_LENGTH_ERROR();
|
||||
}
|
||||
pos_ = pos;
|
||||
}
|
||||
|
||||
|
@ -62,26 +98,18 @@ class InMemoryIStream : public OpenEXR::IStream {
|
|||
};
|
||||
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
bool CanDecodeEXR() {
|
||||
#if JPEGXL_ENABLE_EXR
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
bool CanDecodeEXR() { return true; }
|
||||
|
||||
Status DecodeImageEXR(Span<const uint8_t> bytes, const ColorHints& color_hints,
|
||||
PackedPixelFile* ppf,
|
||||
const SizeConstraints* constraints) {
|
||||
#if JPEGXL_ENABLE_EXR
|
||||
InMemoryIStream is(bytes);
|
||||
|
||||
#ifdef __EXCEPTIONS
|
||||
std::unique_ptr<OpenEXR::RgbaInputFile> input_ptr;
|
||||
try {
|
||||
input_ptr.reset(new OpenEXR::RgbaInputFile(is));
|
||||
input_ptr = jxl::make_unique<OpenEXR::RgbaInputFile>(is);
|
||||
} catch (...) {
|
||||
// silently return false if it is not an EXR file
|
||||
return false;
|
||||
|
@ -121,7 +149,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;
|
||||
|
@ -192,10 +225,9 @@ Status DecodeImageEXR(Span<const uint8_t> bytes, const ColorHints& color_hints,
|
|||
}
|
||||
ppf->info.intensity_target = intensity_target;
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace extras
|
||||
} // namespace jxl
|
||||
|
||||
#endif // JPEGXL_ENABLE_EXR
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
// Decodes OpenEXR images in memory.
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "lib/extras/dec/color_hints.h"
|
||||
#include "lib/extras/packed_image.h"
|
||||
#include "lib/jxl/base/data_parallel.h"
|
||||
|
|
|
@ -5,19 +5,22 @@
|
|||
|
||||
#include "lib/extras/dec/gif.h"
|
||||
|
||||
#include "lib/jxl/base/status.h"
|
||||
|
||||
#if JPEGXL_ENABLE_GIF
|
||||
#include <gif_lib.h>
|
||||
#endif
|
||||
#include <jxl/codestream_header.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "lib/extras/size_constraints.h"
|
||||
#include "lib/jxl/base/compiler_specific.h"
|
||||
#include "lib/jxl/sanitizers.h"
|
||||
#include "lib/jxl/base/rect.h"
|
||||
#include "lib/jxl/base/sanitizers.h"
|
||||
|
||||
namespace jxl {
|
||||
namespace extras {
|
||||
|
@ -42,19 +45,22 @@ struct PackedRgb {
|
|||
uint8_t r, g, b;
|
||||
};
|
||||
|
||||
void ensure_have_alpha(PackedFrame* frame) {
|
||||
if (!frame->extra_channels.empty()) return;
|
||||
Status ensure_have_alpha(PackedFrame* frame) {
|
||||
if (!frame->extra_channels.empty()) return true;
|
||||
const JxlPixelFormat alpha_format{
|
||||
/*num_channels=*/1u,
|
||||
/*data_type=*/JXL_TYPE_UINT8,
|
||||
/*endianness=*/JXL_NATIVE_ENDIAN,
|
||||
/*align=*/0,
|
||||
};
|
||||
frame->extra_channels.emplace_back(frame->color.xsize, frame->color.ysize,
|
||||
alpha_format);
|
||||
JXL_ASSIGN_OR_RETURN(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);
|
||||
return true;
|
||||
}
|
||||
} // namespace
|
||||
#endif
|
||||
|
@ -81,7 +87,7 @@ Status DecodeImageGIF(Span<const uint8_t> bytes, const ColorHints& color_hints,
|
|||
n = state->bytes.size();
|
||||
}
|
||||
memcpy(bytes, state->bytes.data(), n);
|
||||
state->bytes.remove_prefix(n);
|
||||
if (!state->bytes.remove_prefix(n)) return 0;
|
||||
return n;
|
||||
};
|
||||
GifUniquePtr gif(DGifOpen(&state, ReadFromSpan, &error));
|
||||
|
@ -137,7 +143,7 @@ Status DecodeImageGIF(Span<const uint8_t> bytes, const ColorHints& color_hints,
|
|||
|
||||
if (gif->ImageCount > 1) {
|
||||
ppf->info.have_animation = JXL_TRUE;
|
||||
// Delays in GIF are specified in 100ths of a second.
|
||||
// Delays in GIF are specified in censiseconds.
|
||||
ppf->info.animation.tps_numerator = 100;
|
||||
ppf->info.animation.tps_denominator = 1;
|
||||
}
|
||||
|
@ -186,7 +192,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,26 +238,33 @@ 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
|
||||
// need for an alpha channel. This is discovered only as soon as
|
||||
// we see a transparent pixel. We hence initialize alpha lazily.
|
||||
auto set_pixel_alpha = [&frame](size_t x, size_t y, uint8_t a) {
|
||||
auto set_pixel_alpha = [&frame](size_t x, size_t y, uint8_t a) -> Status {
|
||||
// If we do not have an alpha-channel and a==255 (fully opaque),
|
||||
// we can skip setting this pixel-value and rely on
|
||||
// "no alpha channel = no transparency".
|
||||
if (a == 255 && !frame->extra_channels.empty()) return;
|
||||
ensure_have_alpha(frame);
|
||||
if (a == 255 && !frame->extra_channels.empty()) return true;
|
||||
JXL_RETURN_IF_ERROR(ensure_have_alpha(frame));
|
||||
static_cast<uint8_t*>(
|
||||
frame->extra_channels[0].pixels())[y * frame->color.xsize + x] = a;
|
||||
return true;
|
||||
};
|
||||
|
||||
const ColorMapObject* const color_map =
|
||||
image.ImageDesc.ColorMap ? image.ImageDesc.ColorMap : gif->SColorMap;
|
||||
JXL_CHECK(color_map);
|
||||
JXL_ENSURE(color_map);
|
||||
msan::UnpoisonMemory(color_map, sizeof(*color_map));
|
||||
msan::UnpoisonMemory(color_map->Colors,
|
||||
sizeof(*color_map->Colors) * color_map->ColorCount);
|
||||
|
@ -301,8 +316,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) {
|
||||
|
@ -338,7 +355,7 @@ Status DecodeImageGIF(Span<const uint8_t> bytes, const ColorHints& color_hints,
|
|||
row_out[x].r = row_in[x].r;
|
||||
row_out[x].g = row_in[x].g;
|
||||
row_out[x].b = row_in[x].b;
|
||||
set_pixel_alpha(x, y, row_in[x].a);
|
||||
JXL_RETURN_IF_ERROR(set_pixel_alpha(x, y, row_in[x].a));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -355,14 +372,14 @@ Status DecodeImageGIF(Span<const uint8_t> bytes, const ColorHints& color_hints,
|
|||
row[x].r = 0;
|
||||
row[x].g = 0;
|
||||
row[x].b = 0;
|
||||
set_pixel_alpha(x, y, 0);
|
||||
JXL_RETURN_IF_ERROR(set_pixel_alpha(x, y, 0));
|
||||
continue;
|
||||
}
|
||||
GifColorType color = color_map->Colors[byte];
|
||||
row[x].r = color.Red;
|
||||
row[x].g = color.Green;
|
||||
row[x].b = color.Blue;
|
||||
set_pixel_alpha(x, y, 255);
|
||||
JXL_RETURN_IF_ERROR(set_pixel_alpha(x, y, 255));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -402,7 +419,7 @@ Status DecodeImageGIF(Span<const uint8_t> bytes, const ColorHints& color_hints,
|
|||
}
|
||||
if (seen_alpha) {
|
||||
for (PackedFrame& frame : ppf->frames) {
|
||||
ensure_have_alpha(&frame);
|
||||
JXL_RETURN_IF_ERROR(ensure_have_alpha(&frame));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -6,16 +6,17 @@
|
|||
#include "lib/extras/dec/jpegli.h"
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "lib/jpegli/decode.h"
|
||||
#include "lib/jxl/base/compiler_specific.h"
|
||||
#include "lib/jxl/base/sanitizers.h"
|
||||
#include "lib/jxl/base/status.h"
|
||||
#include "lib/jxl/sanitizers.h"
|
||||
|
||||
namespace jxl {
|
||||
namespace extras {
|
||||
|
@ -114,25 +115,26 @@ void MyErrorExit(j_common_ptr cinfo) {
|
|||
}
|
||||
|
||||
void MyOutputMessage(j_common_ptr cinfo) {
|
||||
#if JXL_DEBUG_WARNING == 1
|
||||
char buf[JMSG_LENGTH_MAX + 1];
|
||||
(*cinfo->err->format_message)(cinfo, buf);
|
||||
buf[JMSG_LENGTH_MAX] = 0;
|
||||
JXL_WARNING("%s", buf);
|
||||
#endif
|
||||
if (JXL_IS_DEBUG_BUILD) {
|
||||
char buf[JMSG_LENGTH_MAX + 1];
|
||||
(*cinfo->err->format_message)(cinfo, buf);
|
||||
buf[JMSG_LENGTH_MAX] = 0;
|
||||
JXL_WARNING("%s", buf);
|
||||
}
|
||||
}
|
||||
|
||||
void UnmapColors(uint8_t* row, size_t xsize, int components,
|
||||
JSAMPARRAY colormap, size_t num_colors) {
|
||||
JXL_CHECK(colormap != nullptr);
|
||||
Status UnmapColors(uint8_t* row, size_t xsize, int components,
|
||||
JSAMPARRAY colormap, size_t num_colors) {
|
||||
JXL_ENSURE(colormap != nullptr);
|
||||
std::vector<uint8_t> tmp(xsize * components);
|
||||
for (size_t x = 0; x < xsize; ++x) {
|
||||
JXL_CHECK(row[x] < num_colors);
|
||||
JXL_ENSURE(row[x] < num_colors);
|
||||
for (int c = 0; c < components; ++c) {
|
||||
tmp[x * components + c] = colormap[c][row[x]];
|
||||
}
|
||||
}
|
||||
memcpy(row, tmp.data(), tmp.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -181,7 +183,9 @@ Status DecodeJpeg(const std::vector<uint8_t>& compressed,
|
|||
}
|
||||
int nbcomp = cinfo.num_components;
|
||||
if (nbcomp != 1 && nbcomp != 3) {
|
||||
return failure("unsupported number of components in JPEG");
|
||||
std::string msg =
|
||||
"unsupported number of components in JPEG: " + std::to_string(nbcomp);
|
||||
return failure(msg.c_str());
|
||||
}
|
||||
if (dparams.force_rgb) {
|
||||
cinfo.out_color_space = JCS_RGB;
|
||||
|
@ -246,11 +250,17 @@ 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 *
|
||||
JXL_ENSURE(sizeof(JSAMPLE) * cinfo.out_color_components *
|
||||
cinfo.image_width <=
|
||||
frame.color.stride);
|
||||
if (dparams.num_colors > 0) JXL_ENSURE(cinfo.colormap != nullptr);
|
||||
|
||||
for (size_t y = 0; y < cinfo.image_height; ++y) {
|
||||
JSAMPROW rows[] = {reinterpret_cast<JSAMPLE*>(
|
||||
|
@ -258,8 +268,9 @@ Status DecodeJpeg(const std::vector<uint8_t>& compressed,
|
|||
frame.color.stride * y)};
|
||||
jpegli_read_scanlines(&cinfo, rows, 1);
|
||||
if (dparams.num_colors > 0) {
|
||||
UnmapColors(rows[0], cinfo.output_width, cinfo.out_color_components,
|
||||
cinfo.colormap, cinfo.actual_number_of_colors);
|
||||
JXL_RETURN_IF_ERROR(
|
||||
UnmapColors(rows[0], cinfo.output_width, cinfo.out_color_components,
|
||||
cinfo.colormap, cinfo.actual_number_of_colors));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,19 +6,19 @@
|
|||
#include "lib/extras/dec/jpg.h"
|
||||
|
||||
#if JPEGXL_ENABLE_JPEG
|
||||
#include <jpeglib.h>
|
||||
#include <setjmp.h>
|
||||
#include "lib/jxl/base/include_jpeglib.h" // NOLINT
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <numeric>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "lib/extras/size_constraints.h"
|
||||
#include "lib/jxl/base/compiler_specific.h"
|
||||
#include "lib/jxl/base/sanitizers.h"
|
||||
#include "lib/jxl/base/status.h"
|
||||
#include "lib/jxl/sanitizers.h"
|
||||
|
||||
namespace jxl {
|
||||
namespace extras {
|
||||
|
@ -110,7 +110,7 @@ Status ReadICCProfile(jpeg_decompress_struct* const cinfo,
|
|||
}
|
||||
|
||||
if (seen_markers_count != num_markers) {
|
||||
JXL_DASSERT(has_num_markers);
|
||||
JXL_ENSURE(has_num_markers);
|
||||
return JXL_FAILURE("Incomplete set of ICC chunks");
|
||||
}
|
||||
|
||||
|
@ -156,25 +156,26 @@ void MyErrorExit(j_common_ptr cinfo) {
|
|||
}
|
||||
|
||||
void MyOutputMessage(j_common_ptr cinfo) {
|
||||
#if JXL_DEBUG_WARNING == 1
|
||||
char buf[JMSG_LENGTH_MAX + 1];
|
||||
(*cinfo->err->format_message)(cinfo, buf);
|
||||
buf[JMSG_LENGTH_MAX] = 0;
|
||||
JXL_WARNING("%s", buf);
|
||||
#endif
|
||||
if (JXL_IS_DEBUG_BUILD) {
|
||||
char buf[JMSG_LENGTH_MAX + 1];
|
||||
(*cinfo->err->format_message)(cinfo, buf);
|
||||
buf[JMSG_LENGTH_MAX] = 0;
|
||||
JXL_WARNING("%s", buf);
|
||||
}
|
||||
}
|
||||
|
||||
void UnmapColors(uint8_t* row, size_t xsize, int components,
|
||||
JSAMPARRAY colormap, size_t num_colors) {
|
||||
JXL_CHECK(colormap != nullptr);
|
||||
Status UnmapColors(uint8_t* row, size_t xsize, int components,
|
||||
JSAMPARRAY colormap, size_t num_colors) {
|
||||
JXL_ENSURE(colormap != nullptr);
|
||||
std::vector<uint8_t> tmp(xsize * components);
|
||||
for (size_t x = 0; x < xsize; ++x) {
|
||||
JXL_CHECK(row[x] < num_colors);
|
||||
JXL_ENSURE(row[x] < num_colors);
|
||||
for (int c = 0; c < components; ++c) {
|
||||
tmp[x * components + c] = colormap[c][row[x]];
|
||||
}
|
||||
}
|
||||
memcpy(row, tmp.data(), tmp.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -268,7 +269,7 @@ Status DecodeImageJPG(const Span<const uint8_t> bytes,
|
|||
ppf->info.ysize = cinfo.image_height;
|
||||
// Original data is uint, so exponent_bits_per_sample = 0.
|
||||
ppf->info.bits_per_sample = BITS_IN_JSAMPLE;
|
||||
JXL_ASSERT(BITS_IN_JSAMPLE == 8 || BITS_IN_JSAMPLE == 16);
|
||||
static_assert(BITS_IN_JSAMPLE == 8 || BITS_IN_JSAMPLE == 16);
|
||||
ppf->info.exponent_bits_per_sample = 0;
|
||||
ppf->info.uses_original_profile = JXL_TRUE;
|
||||
|
||||
|
@ -287,7 +288,7 @@ Status DecodeImageJPG(const Span<const uint8_t> bytes,
|
|||
}
|
||||
|
||||
jpeg_start_decompress(&cinfo);
|
||||
JXL_ASSERT(cinfo.out_color_components == nbcomp);
|
||||
JXL_ENSURE(cinfo.out_color_components == nbcomp);
|
||||
JxlDataType data_type =
|
||||
ppf->info.bits_per_sample <= 8 ? JXL_TYPE_UINT8 : JXL_TYPE_UINT16;
|
||||
|
||||
|
@ -299,9 +300,14 @@ 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 *
|
||||
JXL_ENSURE(sizeof(JSAMPLE) * cinfo.out_color_components *
|
||||
cinfo.image_width <=
|
||||
frame.color.stride);
|
||||
|
||||
|
@ -315,6 +321,9 @@ Status DecodeImageJPG(const Span<const uint8_t> bytes,
|
|||
cinfo.actual_number_of_colors * sizeof(JSAMPLE));
|
||||
}
|
||||
}
|
||||
if (dparams && dparams->num_colors > 0) {
|
||||
JXL_ENSURE(cinfo.colormap != nullptr);
|
||||
}
|
||||
for (size_t y = 0; y < cinfo.image_height; ++y) {
|
||||
JSAMPROW rows[] = {reinterpret_cast<JSAMPLE*>(
|
||||
static_cast<uint8_t*>(frame.color.pixels()) +
|
||||
|
@ -323,8 +332,9 @@ Status DecodeImageJPG(const Span<const uint8_t> bytes,
|
|||
msan::UnpoisonMemory(rows[0], sizeof(JSAMPLE) * cinfo.output_components *
|
||||
cinfo.image_width);
|
||||
if (dparams && dparams->num_colors > 0) {
|
||||
UnmapColors(rows[0], cinfo.output_width, cinfo.out_color_components,
|
||||
cinfo.colormap, cinfo.actual_number_of_colors);
|
||||
JXL_RETURN_IF_ERROR(
|
||||
UnmapColors(rows[0], cinfo.output_width, cinfo.out_color_components,
|
||||
cinfo.colormap, cinfo.actual_number_of_colors));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,14 +6,21 @@
|
|||
#include "lib/extras/dec/jxl.h"
|
||||
|
||||
#include <jxl/cms.h>
|
||||
#include <jxl/codestream_header.h>
|
||||
#include <jxl/decode.h>
|
||||
#include <jxl/decode_cxx.h>
|
||||
#include <jxl/types.h>
|
||||
|
||||
#include <cinttypes>
|
||||
#include <cinttypes> // PRIu32
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
#include "lib/extras/common.h"
|
||||
#include "lib/extras/dec/color_description.h"
|
||||
#include "lib/jxl/base/common.h"
|
||||
#include "lib/jxl/base/exif.h"
|
||||
#include "lib/jxl/base/printf_macros.h"
|
||||
#include "lib/jxl/base/status.h"
|
||||
|
@ -22,17 +29,27 @@ namespace jxl {
|
|||
namespace extras {
|
||||
namespace {
|
||||
|
||||
#define QUIT(M) \
|
||||
fprintf(stderr, "%s\n", M); \
|
||||
return false;
|
||||
|
||||
struct BoxProcessor {
|
||||
explicit BoxProcessor(JxlDecoder* dec) : dec_(dec) { Reset(); }
|
||||
|
||||
void InitializeOutput(std::vector<uint8_t>* out) {
|
||||
JXL_ASSERT(out != nullptr);
|
||||
bool InitializeOutput(std::vector<uint8_t>* out) {
|
||||
if (out == nullptr) {
|
||||
fprintf(stderr, "internal: out == nullptr\n");
|
||||
return false;
|
||||
}
|
||||
box_data_ = out;
|
||||
AddMoreOutput();
|
||||
return AddMoreOutput();
|
||||
}
|
||||
|
||||
bool AddMoreOutput() {
|
||||
JXL_ASSERT(box_data_ != nullptr);
|
||||
if (box_data_ == nullptr) {
|
||||
fprintf(stderr, "internal: box_data_ == nullptr\n");
|
||||
return false;
|
||||
}
|
||||
Flush();
|
||||
static const size_t kBoxOutputChunkSize = 1 << 16;
|
||||
box_data_->resize(box_data_->size() + kBoxOutputChunkSize);
|
||||
|
@ -118,7 +135,7 @@ bool DecodeImageJXL(const uint8_t* bytes, size_t bytes_size,
|
|||
// silently return false if this is not a JXL file
|
||||
if (sig == JXL_SIG_INVALID) return false;
|
||||
|
||||
auto decoder = JxlDecoderMake(/*memory_manager=*/nullptr);
|
||||
auto decoder = JxlDecoderMake(dparams.memory_manager);
|
||||
JxlDecoder* dec = decoder.get();
|
||||
ppf->frames.clear();
|
||||
|
||||
|
@ -211,7 +228,7 @@ bool DecodeImageJXL(const uint8_t* bytes, size_t bytes_size,
|
|||
return false;
|
||||
}
|
||||
uint32_t progression_index = 0;
|
||||
bool codestream_done = accepted_formats.empty();
|
||||
bool codestream_done = jpeg_bytes == nullptr && accepted_formats.empty();
|
||||
BoxProcessor boxes(dec);
|
||||
for (;;) {
|
||||
JxlDecoderStatus status = JxlDecoderProcessInput(dec);
|
||||
|
@ -252,14 +269,20 @@ bool DecodeImageJXL(const uint8_t* bytes, size_t bytes_size,
|
|||
box_data = &ppf->metadata.iptc;
|
||||
} else if (memcmp(box_type, "jumb", 4) == 0) {
|
||||
box_data = &ppf->metadata.jumbf;
|
||||
} else if (memcmp(box_type, "jhgm", 4) == 0) {
|
||||
box_data = &ppf->metadata.jhgm;
|
||||
} else if (memcmp(box_type, "xml ", 4) == 0) {
|
||||
box_data = &ppf->metadata.xmp;
|
||||
}
|
||||
if (box_data) {
|
||||
boxes.InitializeOutput(box_data);
|
||||
if (!boxes.InitializeOutput(box_data)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (status == JXL_DEC_BOX_NEED_MORE_OUTPUT) {
|
||||
boxes.AddMoreOutput();
|
||||
if (!boxes.AddMoreOutput()) {
|
||||
return false;
|
||||
}
|
||||
} else if (status == JXL_DEC_JPEG_RECONSTRUCTION) {
|
||||
can_reconstruct_jpeg = true;
|
||||
// Decoding to JPEG.
|
||||
|
@ -270,7 +293,10 @@ 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.
|
||||
if (jpeg_bytes == nullptr) {
|
||||
fprintf(stderr, "internal: jpeg_bytes == nullptr\n");
|
||||
return false;
|
||||
}
|
||||
// Decoded a chunk to JPEG.
|
||||
size_t used_jpeg_output =
|
||||
jpeg_data_chunk.size() - JxlDecoderReleaseJPEGBuffer(dec);
|
||||
|
@ -392,7 +418,12 @@ 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);
|
||||
JXL_ASSIGN_OR_QUIT(jxl::extras::PackedFrame frame,
|
||||
jxl::extras::PackedFrame::Create(
|
||||
ppf->info.xsize, ppf->info.ysize, format),
|
||||
"Failed to create image frame.");
|
||||
if (JXL_DEC_SUCCESS != JxlDecoderGetFrameHeader(dec, &frame.frame_info)) {
|
||||
fprintf(stderr, "JxlDecoderGetFrameHeader failed\n");
|
||||
return false;
|
||||
|
@ -431,9 +462,13 @@ bool DecodeImageJXL(const uint8_t* bytes, size_t bytes_size,
|
|||
fprintf(stderr, "JxlDecoderPreviewOutBufferSize failed\n");
|
||||
return false;
|
||||
}
|
||||
ppf->preview_frame = std::unique_ptr<jxl::extras::PackedFrame>(
|
||||
new jxl::extras::PackedFrame(ppf->info.preview.xsize,
|
||||
ppf->info.preview.ysize, format));
|
||||
JXL_ASSIGN_OR_QUIT(
|
||||
jxl::extras::PackedImage preview_image,
|
||||
jxl::extras::PackedImage::Create(ppf->info.preview.xsize,
|
||||
ppf->info.preview.ysize, format),
|
||||
"Failed to create preview image.");
|
||||
ppf->preview_frame =
|
||||
jxl::make_unique<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);
|
||||
|
@ -500,8 +535,11 @@ 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(ppf->info.xsize, ppf->info.ysize,
|
||||
ec_format);
|
||||
JXL_ASSIGN_OR_QUIT(jxl::extras::PackedImage image,
|
||||
jxl::extras::PackedImage::Create(
|
||||
ppf->info.xsize, ppf->info.ysize, ec_format),
|
||||
"Failed to create extra channel image.");
|
||||
frame.extra_channels.emplace_back(std::move(image));
|
||||
auto& ec = frame.extra_channels.back();
|
||||
size_t buffer_size;
|
||||
if (JXL_DEC_SUCCESS != JxlDecoderExtraChannelBufferSize(
|
||||
|
|
|
@ -8,10 +8,12 @@
|
|||
|
||||
// Decodes JPEG XL images in memory.
|
||||
|
||||
#include <jxl/memory_manager.h>
|
||||
#include <jxl/parallel_runner.h>
|
||||
#include <jxl/types.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -38,6 +40,9 @@ struct JXLDecompressParams {
|
|||
JxlParallelRunner runner;
|
||||
void* runner_opaque = nullptr;
|
||||
|
||||
// If memory_manager is set, decoder uses it.
|
||||
JxlMemoryManager* memory_manager = nullptr;
|
||||
|
||||
// Whether truncated input should be treated as an error.
|
||||
bool allow_partial_input = false;
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
@ -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) {
|
||||
|
|
|
@ -5,10 +5,17 @@
|
|||
|
||||
#include "lib/extras/dec/pgx.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include "lib/extras/packed_image.h"
|
||||
#include "lib/extras/packed_image_convert.h"
|
||||
#include "lib/jxl/base/span.h"
|
||||
#include "lib/jxl/image_bundle.h"
|
||||
#include "lib/jxl/image_ops.h"
|
||||
#include "lib/jxl/test_memory_manager.h"
|
||||
#include "lib/jxl/test_utils.h"
|
||||
#include "lib/jxl/testing.h"
|
||||
|
||||
namespace jxl {
|
||||
|
@ -26,7 +33,7 @@ TEST(CodecPGXTest, Test8bits) {
|
|||
ThreadPool* pool = nullptr;
|
||||
|
||||
EXPECT_TRUE(DecodeImagePGX(MakeSpan(pgx.c_str()), ColorHints(), &ppf));
|
||||
CodecInOut io;
|
||||
CodecInOut io{jxl::test::MemoryManager()};
|
||||
EXPECT_TRUE(ConvertPackedPixelFileToCodecInOut(ppf, pool, &io));
|
||||
|
||||
ScaleImage(255.f, io.Main().color());
|
||||
|
@ -53,7 +60,7 @@ TEST(CodecPGXTest, Test16bits) {
|
|||
ThreadPool* pool = nullptr;
|
||||
|
||||
EXPECT_TRUE(DecodeImagePGX(MakeSpan(pgx.c_str()), ColorHints(), &ppf));
|
||||
CodecInOut io;
|
||||
CodecInOut io{jxl::test::MemoryManager()};
|
||||
EXPECT_TRUE(ConvertPackedPixelFileToCodecInOut(ppf, pool, &io));
|
||||
|
||||
ScaleImage(255.f, io.Main().color());
|
||||
|
|
|
@ -5,17 +5,18 @@
|
|||
|
||||
#include "lib/extras/dec/pnm.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <jxl/encode.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "jxl/encode.h"
|
||||
#include "lib/extras/size_constraints.h"
|
||||
#include "lib/jxl/base/bits.h"
|
||||
#include "lib/jxl/base/compiler_specific.h"
|
||||
#include "lib/jxl/base/c_callback_support.h"
|
||||
#include "lib/jxl/base/span.h"
|
||||
#include "lib/jxl/base/status.h"
|
||||
|
||||
namespace jxl {
|
||||
|
@ -226,6 +227,10 @@ class Parser {
|
|||
header->ec_types.push_back(JXL_CHANNEL_CFA);
|
||||
} else if (MatchString("Thermal")) {
|
||||
header->ec_types.push_back(JXL_CHANNEL_THERMAL);
|
||||
} else if (MatchString("Unknown")) {
|
||||
header->ec_types.push_back(JXL_CHANNEL_UNKNOWN);
|
||||
} else if (MatchString("Optional")) {
|
||||
header->ec_types.push_back(JXL_CHANNEL_OPTIONAL);
|
||||
} else {
|
||||
return JXL_FAILURE("PAM: unknown TUPLTYPE");
|
||||
}
|
||||
|
@ -314,10 +319,6 @@ class Parser {
|
|||
const uint8_t* const end_;
|
||||
};
|
||||
|
||||
Span<const uint8_t> MakeSpan(const char* str) {
|
||||
return Bytes(reinterpret_cast<const uint8_t*>(str), strlen(str));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
struct PNMChunkedInputFrame {
|
||||
|
@ -332,7 +333,7 @@ struct PNMChunkedInputFrame {
|
|||
METHOD_TO_C_CALLBACK(&PNMChunkedInputFrame::ReleaseCurrentData)};
|
||||
}
|
||||
|
||||
void GetColorChannelsPixelFormat(JxlPixelFormat* pixel_format) {
|
||||
void /* NOLINT */ GetColorChannelsPixelFormat(JxlPixelFormat* pixel_format) {
|
||||
*pixel_format = format;
|
||||
}
|
||||
|
||||
|
@ -349,13 +350,18 @@ struct PNMChunkedInputFrame {
|
|||
|
||||
void GetExtraChannelPixelFormat(size_t ec_index,
|
||||
JxlPixelFormat* pixel_format) {
|
||||
JXL_ABORT("Not implemented");
|
||||
(void)this;
|
||||
*pixel_format = {};
|
||||
JXL_DEBUG_ABORT("Not implemented");
|
||||
}
|
||||
|
||||
const void* GetExtraChannelDataAt(size_t ec_index, size_t xpos, size_t ypos,
|
||||
size_t xsize, size_t ysize,
|
||||
size_t* row_offset) {
|
||||
JXL_ABORT("Not implemented");
|
||||
(void)this;
|
||||
*row_offset = 0;
|
||||
JXL_DEBUG_ABORT("Not implemented");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ReleaseCurrentData(const void* buffer) {}
|
||||
|
@ -391,8 +397,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;
|
||||
}
|
||||
|
@ -473,7 +479,7 @@ Status DecodeImagePNM(const Span<const uint8_t> bytes,
|
|||
ppf->info.num_extra_channels = num_alpha_channels + header.ec_types.size();
|
||||
|
||||
for (auto type : header.ec_types) {
|
||||
PackedExtraChannel pec;
|
||||
PackedExtraChannel pec = {};
|
||||
pec.ec_info.bits_per_sample = ppf->info.bits_per_sample;
|
||||
pec.ec_info.type = type;
|
||||
ppf->extra_channels_info.emplace_back(std::move(pec));
|
||||
|
@ -499,10 +505,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) {
|
||||
|
@ -523,6 +537,7 @@ Status DecodeImagePNM(const Span<const uint8_t> bytes,
|
|||
memcpy(row_out, row_in, frame->color.stride);
|
||||
}
|
||||
} else {
|
||||
JXL_RETURN_IF_ERROR(PackedImage::ValidateDataType(data_type));
|
||||
size_t pwidth = PackedImage::BitsPerChannel(data_type) / 8;
|
||||
for (size_t y = 0; y < header.ysize; ++y) {
|
||||
for (size_t x = 0; x < header.xsize; ++x) {
|
||||
|
@ -537,42 +552,19 @@ 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;
|
||||
}
|
||||
|
||||
void TestCodecPNM() {
|
||||
size_t u = 77777; // Initialized to wrong value.
|
||||
double d = 77.77;
|
||||
// Failing to parse invalid strings results in a crash if `JXL_CRASH_ON_ERROR`
|
||||
// is defined and hence the tests fail. Therefore we only run these tests if
|
||||
// `JXL_CRASH_ON_ERROR` is not defined.
|
||||
#ifndef JXL_CRASH_ON_ERROR
|
||||
JXL_CHECK(false == Parser(MakeSpan("")).ParseUnsigned(&u));
|
||||
JXL_CHECK(false == Parser(MakeSpan("+")).ParseUnsigned(&u));
|
||||
JXL_CHECK(false == Parser(MakeSpan("-")).ParseUnsigned(&u));
|
||||
JXL_CHECK(false == Parser(MakeSpan("A")).ParseUnsigned(&u));
|
||||
// Exposed for testing.
|
||||
Status PnmParseSigned(Bytes str, double* v) {
|
||||
return Parser(str).ParseSigned(v);
|
||||
}
|
||||
|
||||
JXL_CHECK(false == Parser(MakeSpan("")).ParseSigned(&d));
|
||||
JXL_CHECK(false == Parser(MakeSpan("+")).ParseSigned(&d));
|
||||
JXL_CHECK(false == Parser(MakeSpan("-")).ParseSigned(&d));
|
||||
JXL_CHECK(false == Parser(MakeSpan("A")).ParseSigned(&d));
|
||||
#endif
|
||||
JXL_CHECK(true == Parser(MakeSpan("1")).ParseUnsigned(&u));
|
||||
JXL_CHECK(u == 1);
|
||||
|
||||
JXL_CHECK(true == Parser(MakeSpan("32")).ParseUnsigned(&u));
|
||||
JXL_CHECK(u == 32);
|
||||
|
||||
JXL_CHECK(true == Parser(MakeSpan("1")).ParseSigned(&d));
|
||||
JXL_CHECK(d == 1.0);
|
||||
JXL_CHECK(true == Parser(MakeSpan("+2")).ParseSigned(&d));
|
||||
JXL_CHECK(d == 2.0);
|
||||
JXL_CHECK(true == Parser(MakeSpan("-3")).ParseSigned(&d));
|
||||
JXL_CHECK(std::abs(d - -3.0) < 1E-15);
|
||||
JXL_CHECK(true == Parser(MakeSpan("3.141592")).ParseSigned(&d));
|
||||
JXL_CHECK(std::abs(d - 3.141592) < 1E-15);
|
||||
JXL_CHECK(true == Parser(MakeSpan("-3.141592")).ParseSigned(&d));
|
||||
JXL_CHECK(std::abs(d - -3.141592) < 1E-15);
|
||||
Status PnmParseUnsigned(Bytes str, size_t* v) {
|
||||
return Parser(str).ParseUnsigned(v);
|
||||
}
|
||||
|
||||
} // namespace extras
|
||||
|
|
|
@ -13,12 +13,10 @@
|
|||
|
||||
// TODO(janwas): workaround for incorrect Win64 codegen (cause unknown)
|
||||
#include <hwy/highway.h>
|
||||
#include <mutex>
|
||||
|
||||
#include "lib/extras/dec/color_hints.h"
|
||||
#include "lib/extras/mmap.h"
|
||||
#include "lib/extras/packed_image.h"
|
||||
#include "lib/jxl/base/data_parallel.h"
|
||||
#include "lib/jxl/base/span.h"
|
||||
#include "lib/jxl/base/status.h"
|
||||
|
||||
|
@ -34,8 +32,6 @@ Status DecodeImagePNM(Span<const uint8_t> bytes, const ColorHints& color_hints,
|
|||
PackedPixelFile* ppf,
|
||||
const SizeConstraints* constraints = nullptr);
|
||||
|
||||
void TestCodecPNM();
|
||||
|
||||
struct HeaderPNM {
|
||||
size_t xsize;
|
||||
size_t ysize;
|
||||
|
|
|
@ -36,8 +36,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
@ -62,7 +61,8 @@ class APNGEncoder : public Encoder {
|
|||
std::vector<JxlPixelFormat> AcceptedFormats() const override {
|
||||
std::vector<JxlPixelFormat> formats;
|
||||
for (const uint32_t num_channels : {1, 2, 3, 4}) {
|
||||
for (const JxlDataType data_type : {JXL_TYPE_UINT8, JXL_TYPE_UINT16}) {
|
||||
for (const JxlDataType data_type :
|
||||
{JXL_TYPE_UINT8, JXL_TYPE_UINT16, JXL_TYPE_FLOAT}) {
|
||||
for (JxlEndianness endianness : {JXL_BIG_ENDIAN, JXL_LITTLE_ENDIAN}) {
|
||||
formats.push_back(
|
||||
JxlPixelFormat{num_channels, data_type, endianness, /*align=*/0});
|
||||
|
@ -73,17 +73,30 @@ class APNGEncoder : public Encoder {
|
|||
}
|
||||
Status Encode(const PackedPixelFile& ppf, EncodedImage* encoded_image,
|
||||
ThreadPool* pool) const override {
|
||||
// Encode main image frames
|
||||
JXL_RETURN_IF_ERROR(VerifyBasicInfo(ppf.info));
|
||||
encoded_image->icc.clear();
|
||||
encoded_image->bitstreams.resize(1);
|
||||
return EncodePackedPixelFileToAPNG(ppf, pool,
|
||||
&encoded_image->bitstreams.front());
|
||||
JXL_RETURN_IF_ERROR(EncodePackedPixelFileToAPNG(
|
||||
ppf, pool, &encoded_image->bitstreams.front()));
|
||||
|
||||
// Encode extra channels
|
||||
for (size_t i = 0; i < ppf.extra_channels_info.size(); ++i) {
|
||||
encoded_image->extra_channel_bitstreams.emplace_back();
|
||||
auto& ec_bitstreams = encoded_image->extra_channel_bitstreams.back();
|
||||
ec_bitstreams.emplace_back();
|
||||
JXL_RETURN_IF_ERROR(EncodePackedPixelFileToAPNG(
|
||||
ppf, pool, &ec_bitstreams.back(), true, i));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
Status EncodePackedPixelFileToAPNG(const PackedPixelFile& ppf,
|
||||
ThreadPool* pool,
|
||||
std::vector<uint8_t>* bytes) const;
|
||||
std::vector<uint8_t>* bytes,
|
||||
bool encode_extra_channels = false,
|
||||
size_t extra_channel_index = 0) const;
|
||||
};
|
||||
|
||||
void PngWrite(png_structp png_ptr, png_bytep data, png_size_t length) {
|
||||
|
@ -127,9 +140,14 @@ class BlobsWriterPNG {
|
|||
}
|
||||
|
||||
private:
|
||||
// TODO(eustas): use array
|
||||
static JXL_INLINE char EncodeNibble(const uint8_t nibble) {
|
||||
JXL_ASSERT(nibble < 16);
|
||||
return (nibble < 10) ? '0' + nibble : 'a' + nibble - 10;
|
||||
if (nibble < 16) {
|
||||
return (nibble < 10) ? '0' + nibble : 'a' + nibble - 10;
|
||||
} else {
|
||||
JXL_DEBUG_ABORT("Internal logic error");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static Status EncodeBase16(const std::string& type,
|
||||
|
@ -146,7 +164,7 @@ class BlobsWriterPNG {
|
|||
base16.push_back(EncodeNibble(bytes[i] & 0x0F));
|
||||
}
|
||||
base16.push_back('\n');
|
||||
JXL_ASSERT(base16.length() == base16_size);
|
||||
JXL_ENSURE(base16.length() == base16_size);
|
||||
|
||||
char key[30];
|
||||
snprintf(key, sizeof(key), "Raw profile type %s", type.c_str());
|
||||
|
@ -247,13 +265,10 @@ void MaybeAddCLLi(const JxlColorEncoding& c_enc, const float intensity_target,
|
|||
png_structp png_ptr, png_infop info_ptr) {
|
||||
if (c_enc.transfer_function != JXL_TRANSFER_FUNCTION_PQ) return;
|
||||
|
||||
const uint32_t max_cll =
|
||||
const uint32_t max_content_light_level =
|
||||
static_cast<uint32_t>(10000.f * Clamp1(intensity_target, 0.f, 10000.f));
|
||||
png_byte chunk_data[8] = {};
|
||||
chunk_data[0] = (max_cll >> 24) & 0xFF;
|
||||
chunk_data[1] = (max_cll >> 16) & 0xFF;
|
||||
chunk_data[2] = (max_cll >> 8) & 0xFF;
|
||||
chunk_data[3] = max_cll & 0xFF;
|
||||
png_save_uint_32(chunk_data, max_content_light_level);
|
||||
// Leave MaxFALL set to 0.
|
||||
png_unknown_chunk chunk;
|
||||
memcpy(chunk.name, "cLLi", 5);
|
||||
|
@ -266,15 +281,21 @@ void MaybeAddCLLi(const JxlColorEncoding& c_enc, const float intensity_target,
|
|||
}
|
||||
|
||||
Status APNGEncoder::EncodePackedPixelFileToAPNG(
|
||||
const PackedPixelFile& ppf, ThreadPool* pool,
|
||||
std::vector<uint8_t>* bytes) const {
|
||||
size_t xsize = ppf.info.xsize;
|
||||
size_t ysize = ppf.info.ysize;
|
||||
bool has_alpha = ppf.info.alpha_bits != 0;
|
||||
bool is_gray = ppf.info.num_color_channels == 1;
|
||||
size_t color_channels = ppf.info.num_color_channels;
|
||||
const PackedPixelFile& ppf, ThreadPool* pool, std::vector<uint8_t>* bytes,
|
||||
bool encode_extra_channels, size_t extra_channel_index) const {
|
||||
JxlExtraChannelInfo ec_info{};
|
||||
if (encode_extra_channels) {
|
||||
if (ppf.extra_channels_info.size() <= extra_channel_index) {
|
||||
return JXL_FAILURE("Invalid index for extra channel");
|
||||
}
|
||||
ec_info = ppf.extra_channels_info[extra_channel_index].ec_info;
|
||||
}
|
||||
|
||||
bool has_alpha = !encode_extra_channels && (ppf.info.alpha_bits != 0);
|
||||
bool is_gray = encode_extra_channels || (ppf.info.num_color_channels == 1);
|
||||
size_t color_channels =
|
||||
encode_extra_channels ? 1 : ppf.info.num_color_channels;
|
||||
size_t num_channels = color_channels + (has_alpha ? 1 : 0);
|
||||
size_t num_samples = num_channels * xsize * ysize;
|
||||
|
||||
if (!ppf.info.have_animation && ppf.frames.size() != 1) {
|
||||
return JXL_FAILURE("Invalid number of frames");
|
||||
|
@ -284,11 +305,27 @@ Status APNGEncoder::EncodePackedPixelFileToAPNG(
|
|||
size_t anim_chunks = 0;
|
||||
|
||||
for (const auto& frame : ppf.frames) {
|
||||
JXL_RETURN_IF_ERROR(VerifyPackedImage(frame.color, ppf.info));
|
||||
const PackedImage& color = encode_extra_channels
|
||||
? frame.extra_channels[extra_channel_index]
|
||||
: frame.color;
|
||||
|
||||
const PackedImage& color = frame.color;
|
||||
size_t xsize = color.xsize;
|
||||
size_t ysize = color.ysize;
|
||||
size_t num_samples = num_channels * xsize * ysize;
|
||||
|
||||
uint32_t bits_per_sample = encode_extra_channels ? ec_info.bits_per_sample
|
||||
: ppf.info.bits_per_sample;
|
||||
if (!encode_extra_channels) {
|
||||
JXL_RETURN_IF_ERROR(VerifyPackedImage(color, ppf.info));
|
||||
} else {
|
||||
JXL_RETURN_IF_ERROR(VerifyFormat(color.format));
|
||||
JXL_RETURN_IF_ERROR(VerifyBitDepth(color.format.data_type,
|
||||
bits_per_sample,
|
||||
ec_info.exponent_bits_per_sample));
|
||||
}
|
||||
const JxlPixelFormat format = color.format;
|
||||
const uint8_t* in = reinterpret_cast<const uint8_t*>(color.pixels());
|
||||
JXL_RETURN_IF_ERROR(PackedImage::ValidateDataType(format.data_type));
|
||||
size_t data_bits_per_sample = PackedImage::BitsPerChannel(format.data_type);
|
||||
size_t bytes_per_sample = data_bits_per_sample / 8;
|
||||
size_t out_bytes_per_sample = bytes_per_sample > 1 ? 2 : 1;
|
||||
|
@ -297,28 +334,41 @@ Status APNGEncoder::EncodePackedPixelFileToAPNG(
|
|||
std::vector<uint8_t> out(out_size);
|
||||
|
||||
if (format.data_type == JXL_TYPE_UINT8) {
|
||||
if (ppf.info.bits_per_sample < 8) {
|
||||
float mul = 255.0 / ((1u << ppf.info.bits_per_sample) - 1);
|
||||
if (bits_per_sample < 8) {
|
||||
float mul = 255.0 / ((1u << bits_per_sample) - 1);
|
||||
for (size_t i = 0; i < num_samples; ++i) {
|
||||
out[i] = static_cast<uint8_t>(in[i] * mul + 0.5);
|
||||
out[i] = static_cast<uint8_t>(std::lroundf(in[i] * mul));
|
||||
}
|
||||
} else {
|
||||
memcpy(out.data(), in, out_size);
|
||||
}
|
||||
} else if (format.data_type == JXL_TYPE_UINT16) {
|
||||
if (ppf.info.bits_per_sample < 16 ||
|
||||
format.endianness != JXL_BIG_ENDIAN) {
|
||||
float mul = 65535.0 / ((1u << ppf.info.bits_per_sample) - 1);
|
||||
if (bits_per_sample < 16 || format.endianness != JXL_BIG_ENDIAN) {
|
||||
float mul = 65535.0 / ((1u << bits_per_sample) - 1);
|
||||
const uint8_t* p_in = in;
|
||||
uint8_t* p_out = out.data();
|
||||
for (size_t i = 0; i < num_samples; ++i, p_in += 2, p_out += 2) {
|
||||
uint32_t val = (format.endianness == JXL_BIG_ENDIAN ? LoadBE16(p_in)
|
||||
: LoadLE16(p_in));
|
||||
StoreBE16(static_cast<uint32_t>(val * mul + 0.5), p_out);
|
||||
StoreBE16(static_cast<uint32_t>(std::lroundf(val * mul)), p_out);
|
||||
}
|
||||
} else {
|
||||
memcpy(out.data(), in, out_size);
|
||||
}
|
||||
} else if (format.data_type == JXL_TYPE_FLOAT) {
|
||||
constexpr float kMul = 65535.0;
|
||||
const uint8_t* p_in = in;
|
||||
uint8_t* p_out = out.data();
|
||||
for (size_t i = 0; i < num_samples;
|
||||
++i, p_in += sizeof(float), p_out += 2) {
|
||||
float val =
|
||||
Clamp1(format.endianness == JXL_BIG_ENDIAN ? LoadBEFloat(p_in)
|
||||
: format.endianness == JXL_LITTLE_ENDIAN
|
||||
? LoadLEFloat(p_in)
|
||||
: *reinterpret_cast<const float*>(p_in),
|
||||
0.f, 1.f);
|
||||
StoreBE16(static_cast<uint32_t>(std::lroundf(val * kMul)), p_out);
|
||||
}
|
||||
}
|
||||
png_structp png_ptr;
|
||||
png_infop info_ptr;
|
||||
|
@ -344,7 +394,7 @@ Status APNGEncoder::EncodePackedPixelFileToAPNG(
|
|||
png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type,
|
||||
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
|
||||
PNG_FILTER_TYPE_BASE);
|
||||
if (count == 0) {
|
||||
if (count == 0 && !encode_extra_channels) {
|
||||
if (!MaybeAddSRGB(ppf.color_encoding, png_ptr, info_ptr)) {
|
||||
MaybeAddCICP(ppf.color_encoding, png_ptr, info_ptr);
|
||||
if (!ppf.icc.empty()) {
|
||||
|
@ -415,10 +465,10 @@ Status APNGEncoder::EncodePackedPixelFileToAPNG(
|
|||
size_t p = pos;
|
||||
while (p + 8 < bytes->size()) {
|
||||
size_t len = png_get_uint_32(bytes->data() + p);
|
||||
JXL_ASSERT(bytes->operator[](p + 4) == 'I');
|
||||
JXL_ASSERT(bytes->operator[](p + 5) == 'D');
|
||||
JXL_ASSERT(bytes->operator[](p + 6) == 'A');
|
||||
JXL_ASSERT(bytes->operator[](p + 7) == 'T');
|
||||
JXL_ENSURE(bytes->operator[](p + 4) == 'I');
|
||||
JXL_ENSURE(bytes->operator[](p + 5) == 'D');
|
||||
JXL_ENSURE(bytes->operator[](p + 6) == 'A');
|
||||
JXL_ENSURE(bytes->operator[](p + 7) == 'T');
|
||||
fdata.insert(fdata.end(), bytes->data() + p + 8,
|
||||
bytes->data() + p + 8 + len);
|
||||
p += len + 12;
|
||||
|
|
|
@ -134,5 +134,13 @@ std::unique_ptr<Encoder> Encoder::FromExtension(std::string extension) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
std::string ListOfEncodeCodecs() {
|
||||
std::string list_of_codecs("PPM, PNM, PFM, PAM, PGX");
|
||||
if (GetAPNGEncoder()) list_of_codecs.append(", PNG, APNG");
|
||||
if (GetJPEGEncoder()) list_of_codecs.append(", JPEG");
|
||||
if (GetEXREncoder()) list_of_codecs.append(", EXR");
|
||||
return list_of_codecs;
|
||||
}
|
||||
|
||||
} // namespace extras
|
||||
} // namespace jxl
|
||||
|
|
|
@ -82,6 +82,8 @@ class Encoder {
|
|||
std::unordered_map<std::string, std::string> options_;
|
||||
};
|
||||
|
||||
std::string ListOfEncodeCodecs();
|
||||
|
||||
} // namespace extras
|
||||
} // namespace jxl
|
||||
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
#include <jxl/codestream_header.h>
|
||||
#include <jxl/types.h>
|
||||
#include <setjmp.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <hwy/aligned_allocator.h>
|
||||
|
@ -33,7 +33,6 @@
|
|||
#include "lib/jxl/base/status.h"
|
||||
#include "lib/jxl/color_encoding_internal.h"
|
||||
#include "lib/jxl/enc_xyb.h"
|
||||
#include "lib/jxl/image.h"
|
||||
#include "lib/jxl/simd_util.h"
|
||||
|
||||
namespace jxl {
|
||||
|
@ -54,6 +53,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) {
|
||||
|
@ -249,32 +252,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 +372,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.");
|
||||
}
|
||||
|
@ -373,13 +389,14 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings,
|
|||
// before the call to setjmp().
|
||||
std::vector<uint8_t> pixels;
|
||||
unsigned char* output_buffer = nullptr;
|
||||
unsigned long output_size = 0;
|
||||
unsigned long output_size = 0; // NOLINT
|
||||
std::vector<uint8_t> row_bytes;
|
||||
size_t rowlen = RoundUpTo(ppf.info.xsize, MaxVectorSize());
|
||||
const size_t max_vector_size = MaxVectorSize();
|
||||
size_t rowlen = RoundUpTo(ppf.info.xsize, max_vector_size);
|
||||
hwy::AlignedFreeUniquePtr<float[]> xyb_tmp =
|
||||
hwy::AllocateAligned<float>(6 * rowlen);
|
||||
hwy::AlignedFreeUniquePtr<float[]> premul_absorb =
|
||||
hwy::AllocateAligned<float>(MaxVectorSize() * 12);
|
||||
hwy::AllocateAligned<float>(max_vector_size * 12);
|
||||
ComputePremulAbsorb(255.0f, premul_absorb.get());
|
||||
|
||||
jpeg_compress_struct cinfo;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -435,6 +454,10 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings,
|
|||
cinfo.comp_info[i].h_samp_factor = 1;
|
||||
cinfo.comp_info[i].v_samp_factor = 1;
|
||||
}
|
||||
} else if (!jpeg_settings.xyb) {
|
||||
// Default is no chroma subsampling.
|
||||
cinfo.comp_info[0].h_samp_factor = 1;
|
||||
cinfo.comp_info[0].v_samp_factor = 1;
|
||||
}
|
||||
jpegli_enable_adaptive_quantization(
|
||||
&cinfo, TO_JXL_BOOL(jpeg_settings.use_adaptive_quantization));
|
||||
|
@ -477,8 +500,8 @@ 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, image.xsize)) {
|
||||
return false;
|
||||
|
@ -517,6 +540,8 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings,
|
|||
}
|
||||
} else {
|
||||
for (size_t y = 0; y < info.ysize; ++y) {
|
||||
JXL_RETURN_IF_ERROR(
|
||||
PackedImage::ValidateDataType(image.format.data_type));
|
||||
int bytes_per_channel =
|
||||
PackedImage::BitsPerChannel(image.format.data_type) / 8;
|
||||
int bytes_per_pixel = cinfo.num_components * bytes_per_channel;
|
||||
|
|
|
@ -6,26 +6,23 @@
|
|||
#include "lib/extras/enc/jpg.h"
|
||||
|
||||
#if JPEGXL_ENABLE_JPEG
|
||||
#include <jpeglib.h>
|
||||
#include <setjmp.h>
|
||||
#include "lib/jxl/base/include_jpeglib.h" // NOLINT
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "lib/extras/exif.h"
|
||||
#include "lib/jxl/base/common.h"
|
||||
#include "lib/jxl/base/sanitizers.h"
|
||||
#include "lib/jxl/base/status.h"
|
||||
#include "lib/jxl/sanitizers.h"
|
||||
#if JPEGXL_ENABLE_SJPEG
|
||||
#include "sjpeg.h"
|
||||
#include "sjpegi.h"
|
||||
|
@ -276,7 +273,7 @@ Status EncodeWithLibJpeg(const PackedImage& image, const JxlBasicInfo& info,
|
|||
cinfo.err = jpeg_std_error(&jerr);
|
||||
jpeg_create_compress(&cinfo);
|
||||
unsigned char* buffer = nullptr;
|
||||
unsigned long size = 0;
|
||||
unsigned long size = 0; // NOLINT
|
||||
jpeg_mem_dest(&cinfo, &buffer, &size);
|
||||
cinfo.image_width = image.xsize;
|
||||
cinfo.image_height = image.ysize;
|
||||
|
@ -476,7 +473,7 @@ Status EncodeWithSJpeg(const PackedImage& image, const JxlBasicInfo& info,
|
|||
param.tolerance = params.search_tolerance;
|
||||
param.qmin = params.search_q_min;
|
||||
param.qmax = params.search_q_max;
|
||||
hook.reset(new MySearchHook());
|
||||
hook = jxl::make_unique<MySearchHook>();
|
||||
hook->ReadBaseTables(params.custom_base_quant_fn);
|
||||
hook->q_start = params.search_q_start;
|
||||
hook->q_precision = params.search_q_precision;
|
||||
|
|
|
@ -5,10 +5,18 @@
|
|||
|
||||
#include "lib/extras/enc/jxl.h"
|
||||
|
||||
#include <jxl/codestream_header.h>
|
||||
#include <jxl/encode.h>
|
||||
#include <jxl/encode_cxx.h>
|
||||
#include <jxl/types.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <vector>
|
||||
|
||||
#include "lib/extras/packed_image.h"
|
||||
#include "lib/jxl/base/exif.h"
|
||||
|
||||
namespace jxl {
|
||||
|
@ -112,7 +120,7 @@ bool ReadCompressedOutput(JxlEncoder* enc, std::vector<uint8_t>* compressed) {
|
|||
bool EncodeImageJXL(const JXLCompressParams& params, const PackedPixelFile& ppf,
|
||||
const std::vector<uint8_t>* jpeg_bytes,
|
||||
std::vector<uint8_t>* compressed) {
|
||||
auto encoder = JxlEncoderMake(/*memory_manager=*/nullptr);
|
||||
auto encoder = JxlEncoderMake(params.memory_manager);
|
||||
JxlEncoder* enc = encoder.get();
|
||||
|
||||
if (params.allow_expert_options) {
|
||||
|
@ -153,7 +161,8 @@ bool EncodeImageJXL(const JXLCompressParams& params, const PackedPixelFile& ppf,
|
|||
|
||||
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();
|
||||
!ppf.metadata.jhgm.empty() || !ppf.metadata.jumbf.empty() ||
|
||||
!ppf.metadata.iptc.empty();
|
||||
bool use_container = params.use_container || use_boxes ||
|
||||
(has_jpeg_bytes && params.jpeg_store_metadata);
|
||||
|
||||
|
@ -202,7 +211,7 @@ bool EncodeImageJXL(const JXLCompressParams& params, const PackedPixelFile& ppf,
|
|||
fprintf(stderr,
|
||||
"JPEG bitstream reconstruction data could not be created. "
|
||||
"Possibly there is too much tail data.\n"
|
||||
"Try using --jpeg_store_metadata 0, to losslessly "
|
||||
"Try using --allow_jpeg_reconstruction 0, to losslessly "
|
||||
"recompress the JPEG image data without bitstream "
|
||||
"reconstruction data.\n");
|
||||
} else {
|
||||
|
@ -223,7 +232,14 @@ bool EncodeImageJXL(const JXLCompressParams& params, const PackedPixelFile& ppf,
|
|||
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 = TO_JXL_BOOL(lossless);
|
||||
auto non_perceptual_option = std::find_if(
|
||||
params.options.begin(), params.options.end(), [](JXLOption option) {
|
||||
return option.id ==
|
||||
JXL_ENC_FRAME_SETTING_DISABLE_PERCEPTUAL_HEURISTICS;
|
||||
});
|
||||
const bool non_perceptual = non_perceptual_option != params.options.end() &&
|
||||
non_perceptual_option->ival == 1;
|
||||
basic_info.uses_original_profile = TO_JXL_BOOL(lossless || non_perceptual);
|
||||
if (params.override_bitdepth != 0) {
|
||||
basic_info.bits_per_sample = params.override_bitdepth;
|
||||
basic_info.exponent_bits_per_sample =
|
||||
|
@ -245,7 +261,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;
|
||||
}
|
||||
|
@ -291,10 +307,9 @@ bool EncodeImageJXL(const JXLCompressParams& params, const PackedPixelFile& ppf,
|
|||
const char* type;
|
||||
const std::vector<uint8_t>& bytes;
|
||||
} boxes[] = {
|
||||
{"Exif", exif_with_offset},
|
||||
{"xml ", ppf.metadata.xmp},
|
||||
{"jumb", ppf.metadata.jumbf},
|
||||
{"xml ", ppf.metadata.iptc},
|
||||
{"Exif", exif_with_offset}, {"xml ", ppf.metadata.xmp},
|
||||
{"jumb", ppf.metadata.jumbf}, {"xml ", ppf.metadata.iptc},
|
||||
{"jhgm", ppf.metadata.jhgm},
|
||||
};
|
||||
for (auto box : boxes) {
|
||||
if (!box.bytes.empty()) {
|
||||
|
|
|
@ -7,11 +7,13 @@
|
|||
#define LIB_EXTRAS_ENC_JXL_H_
|
||||
|
||||
#include <jxl/encode.h>
|
||||
#include <jxl/memory_manager.h>
|
||||
#include <jxl/parallel_runner.h>
|
||||
#include <jxl/thread_parallel_runner.h>
|
||||
#include <jxl/types.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "lib/extras/packed_image.h"
|
||||
|
@ -36,32 +38,41 @@ struct JXLOption {
|
|||
|
||||
struct JXLCompressParams {
|
||||
std::vector<JXLOption> options;
|
||||
|
||||
// Target butteraugli distance, 0.0 means lossless.
|
||||
float distance = 1.0f;
|
||||
float alpha_distance = 0.0f;
|
||||
|
||||
// If set to true, forces container mode.
|
||||
bool use_container = false;
|
||||
|
||||
// Whether to enable/disable byte-exact jpeg reconstruction for jpeg inputs.
|
||||
bool jpeg_store_metadata = true;
|
||||
bool jpeg_strip_exif = false;
|
||||
bool jpeg_strip_xmp = false;
|
||||
bool jpeg_strip_jumbf = false;
|
||||
|
||||
// Whether to create brob boxes.
|
||||
bool compress_boxes = true;
|
||||
|
||||
// Upper bound on the intensity level present in the image in nits (zero means
|
||||
// that the library chooses a default).
|
||||
float intensity_target = 0;
|
||||
int already_downsampled = 1;
|
||||
int upsampling_mode = -1;
|
||||
|
||||
// Overrides for bitdepth, codestream level and alpha premultiply.
|
||||
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.
|
||||
|
||||
// If runner_opaque is set, the encoder uses this parallel runner.
|
||||
JxlParallelRunner runner = JxlThreadParallelRunner;
|
||||
void* runner_opaque = nullptr;
|
||||
|
||||
// If memory_manager is set, encoder uses it.
|
||||
JxlMemoryManager* memory_manager = nullptr;
|
||||
|
||||
JxlEncoderOutputProcessor output_processor = {};
|
||||
JxlDebugImageCallback debug_image = nullptr;
|
||||
void* debug_image_opaque = nullptr;
|
||||
|
|
|
@ -254,14 +254,14 @@ bool WriteFrameToNPYArray(size_t xsize, size_t ysize, const PackedFrame& frame,
|
|||
size_t sample_size = color.pixel_stride();
|
||||
size_t offset = y * color.stride + x * sample_size;
|
||||
uint8_t* pixels = reinterpret_cast<uint8_t*>(color.pixels());
|
||||
JXL_ASSERT(offset + sample_size <= color.pixels_size);
|
||||
JXL_ENSURE(offset + sample_size <= color.pixels_size);
|
||||
Append(out, pixels + offset, sample_size);
|
||||
}
|
||||
for (const auto& ec : frame.extra_channels) {
|
||||
size_t sample_size = ec.pixel_stride();
|
||||
size_t offset = y * ec.stride + x * sample_size;
|
||||
uint8_t* pixels = reinterpret_cast<uint8_t*>(ec.pixels());
|
||||
JXL_ASSERT(offset + sample_size <= ec.pixels_size);
|
||||
JXL_ENSURE(offset + sample_size <= ec.pixels_size);
|
||||
Append(out, pixels + offset, sample_size);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
#include "lib/extras/enc/pgx.h"
|
||||
|
||||
#include <jxl/codestream_header.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "lib/extras/packed_image.h"
|
||||
#include "lib/jxl/base/byte_order.h"
|
||||
|
@ -49,6 +50,7 @@ Status EncodeImagePGX(const PackedFrame& frame, const JxlBasicInfo& info,
|
|||
const PackedImage& color = frame.color;
|
||||
const JxlPixelFormat format = color.format;
|
||||
const uint8_t* in = reinterpret_cast<const uint8_t*>(color.pixels());
|
||||
JXL_RETURN_IF_ERROR(PackedImage::ValidateDataType(format.data_type));
|
||||
size_t data_bits_per_sample = PackedImage::BitsPerChannel(format.data_type);
|
||||
size_t bytes_per_sample = data_bits_per_sample / kBitsPerByte;
|
||||
size_t num_samples = info.xsize * info.ysize;
|
||||
|
|
|
@ -5,28 +5,23 @@
|
|||
|
||||
#include "lib/extras/enc/pnm.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "lib/extras/packed_image.h"
|
||||
#include "lib/jxl/base/byte_order.h"
|
||||
#include "lib/jxl/base/compiler_specific.h"
|
||||
#include "lib/jxl/base/common.h"
|
||||
#include "lib/jxl/base/printf_macros.h"
|
||||
#include "lib/jxl/base/status.h"
|
||||
#include "lib/jxl/dec_external_image.h"
|
||||
#include "lib/jxl/enc_external_image.h"
|
||||
#include "lib/jxl/enc_image_bundle.h"
|
||||
#include "lib/jxl/fields.h" // AllDefault
|
||||
#include "lib/jxl/image.h"
|
||||
#include "lib/jxl/image_bundle.h"
|
||||
|
||||
namespace jxl {
|
||||
namespace extras {
|
||||
namespace {
|
||||
|
||||
constexpr size_t kMaxHeaderSize = 200;
|
||||
constexpr size_t kMaxHeaderSize = 2000;
|
||||
|
||||
class BasePNMEncoder : public Encoder {
|
||||
public:
|
||||
|
@ -87,8 +82,8 @@ class PNMEncoder : public BasePNMEncoder {
|
|||
}
|
||||
|
||||
private:
|
||||
Status EncodeImage(const PackedImage& image, size_t bits_per_sample,
|
||||
std::vector<uint8_t>* bytes) const {
|
||||
static Status EncodeImage(const PackedImage& image, size_t bits_per_sample,
|
||||
std::vector<uint8_t>* bytes) {
|
||||
uint32_t maxval = (1u << bits_per_sample) - 1;
|
||||
char type = image.format.num_channels == 1 ? '5' : '6';
|
||||
char header[kMaxHeaderSize];
|
||||
|
@ -161,8 +156,8 @@ class PFMEncoder : public BasePNMEncoder {
|
|||
}
|
||||
|
||||
private:
|
||||
Status EncodeImage(const PackedImage& image,
|
||||
std::vector<uint8_t>* bytes) const {
|
||||
static Status EncodeImage(const PackedImage& image,
|
||||
std::vector<uint8_t>* bytes) {
|
||||
char type = image.format.num_channels == 1 ? 'f' : 'F';
|
||||
double scale = image.format.endianness == JXL_LITTLE_ENDIAN ? -1.0 : 1.0;
|
||||
char header[kMaxHeaderSize];
|
||||
|
@ -262,6 +257,7 @@ class PAMEncoder : public BasePNMEncoder {
|
|||
reinterpret_cast<const uint8_t*>(frame.extra_channels[i].pixels());
|
||||
}
|
||||
uint8_t* out = bytes->data() + pos;
|
||||
JXL_RETURN_IF_ERROR(PackedImage::ValidateDataType(color.format.data_type));
|
||||
size_t pwidth = PackedImage::BitsPerChannel(color.format.data_type) / 8;
|
||||
for (size_t y = 0; y < color.ysize; ++y) {
|
||||
for (size_t x = 0; x < color.xsize; ++x) {
|
||||
|
@ -299,6 +295,10 @@ class PAMEncoder : public BasePNMEncoder {
|
|||
return std::string("CFA");
|
||||
case JXL_CHANNEL_THERMAL:
|
||||
return std::string("Thermal");
|
||||
case JXL_CHANNEL_UNKNOWN:
|
||||
return std::string("Unknown");
|
||||
case JXL_CHANNEL_OPTIONAL:
|
||||
return std::string("Optional");
|
||||
default:
|
||||
return std::string("UNKNOWN");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,231 @@
|
|||
// Copyright (c) the JPEG XL Project Authors. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include <jxl/gain_map.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "lib/jxl/base/byte_order.h"
|
||||
#include "lib/jxl/base/common.h"
|
||||
#include "lib/jxl/color_encoding_internal.h"
|
||||
#include "lib/jxl/dec_bit_reader.h"
|
||||
#include "lib/jxl/enc_aux_out.h"
|
||||
#include "lib/jxl/enc_bit_writer.h"
|
||||
#include "lib/jxl/fields.h"
|
||||
#include "lib/jxl/memory_manager_internal.h"
|
||||
|
||||
namespace {
|
||||
|
||||
template <size_t N>
|
||||
class FixedSizeMemoryManager {
|
||||
public:
|
||||
FixedSizeMemoryManager() = default;
|
||||
|
||||
JxlMemoryManager* memory_manager() { return &manager_; }
|
||||
|
||||
private:
|
||||
static void* FixedSizeMemoryManagerAlloc(void* opaque, size_t capacity) {
|
||||
auto manager = static_cast<FixedSizeMemoryManager<N>*>(opaque);
|
||||
if (capacity > N + jxl::memory_manager_internal::kAlias) {
|
||||
return nullptr;
|
||||
}
|
||||
return manager->memory_;
|
||||
}
|
||||
static void FixedSizeMemoryManagerFree(void* opaque, void* pointer) {}
|
||||
|
||||
uint8_t memory_[N + jxl::memory_manager_internal::kAlias];
|
||||
JxlMemoryManager manager_ = {
|
||||
/*opaque=*/this,
|
||||
/*alloc=*/&FixedSizeMemoryManagerAlloc,
|
||||
/*free=*/&FixedSizeMemoryManagerFree,
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
JXL_BOOL JxlGainMapGetBundleSize(const JxlGainMapBundle* map_bundle,
|
||||
size_t* bundle_size) {
|
||||
if (map_bundle == nullptr) return JXL_FALSE;
|
||||
|
||||
jxl::ColorEncoding internal_color_encoding;
|
||||
size_t color_encoding_size = 0;
|
||||
size_t extension_bits = 0;
|
||||
if (map_bundle->has_color_encoding) {
|
||||
JXL_RETURN_IF_ERROR(
|
||||
internal_color_encoding.FromExternal(map_bundle->color_encoding));
|
||||
if (!jxl::Bundle::CanEncode(internal_color_encoding, &extension_bits,
|
||||
&color_encoding_size)) {
|
||||
return JXL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
*bundle_size =
|
||||
1 + // size of jhgm_version
|
||||
2 + // size_of gain_map_metadata_size
|
||||
map_bundle->gain_map_metadata_size + // size of gain_map_metadata
|
||||
1 + // size of color_encoding_size
|
||||
jxl::DivCeil(color_encoding_size, 8) + // size of the color_encoding
|
||||
4 + // size of compressed_icc_size
|
||||
map_bundle->alt_icc_size + // size of compressed_icc
|
||||
map_bundle->gain_map_size; // size of gain map
|
||||
return JXL_TRUE;
|
||||
}
|
||||
|
||||
JXL_BOOL JxlGainMapWriteBundle(const JxlGainMapBundle* map_bundle,
|
||||
uint8_t* output_buffer,
|
||||
size_t output_buffer_size,
|
||||
size_t* bytes_written) {
|
||||
if (map_bundle == nullptr) return JXL_FALSE;
|
||||
|
||||
uint8_t jhgm_version = map_bundle->jhgm_version;
|
||||
|
||||
FixedSizeMemoryManager<sizeof(jxl::ColorEncoding)> memory_manager;
|
||||
jxl::ColorEncoding internal_color_encoding;
|
||||
jxl::BitWriter color_encoding_writer(memory_manager.memory_manager());
|
||||
if (map_bundle->has_color_encoding) {
|
||||
JXL_RETURN_IF_ERROR(
|
||||
internal_color_encoding.FromExternal(map_bundle->color_encoding));
|
||||
if (!jxl::Bundle::Write(internal_color_encoding, &color_encoding_writer,
|
||||
jxl::LayerType::Header, nullptr)) {
|
||||
return JXL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
color_encoding_writer.ZeroPadToByte();
|
||||
|
||||
uint64_t cursor = 0;
|
||||
uint64_t next_cursor = 0;
|
||||
|
||||
#define SAFE_CURSOR_UPDATE(n) \
|
||||
do { \
|
||||
cursor = next_cursor; \
|
||||
if (!jxl::SafeAdd(cursor, n, next_cursor) || \
|
||||
next_cursor > output_buffer_size) { \
|
||||
return JXL_FALSE; \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
SAFE_CURSOR_UPDATE(1);
|
||||
memcpy(output_buffer + cursor, &jhgm_version, 1);
|
||||
|
||||
SAFE_CURSOR_UPDATE(2);
|
||||
StoreBE16(map_bundle->gain_map_metadata_size, output_buffer + cursor);
|
||||
|
||||
SAFE_CURSOR_UPDATE(map_bundle->gain_map_metadata_size);
|
||||
memcpy(output_buffer + cursor, map_bundle->gain_map_metadata,
|
||||
map_bundle->gain_map_metadata_size);
|
||||
|
||||
jxl::Bytes bytes = color_encoding_writer.GetSpan();
|
||||
uint8_t color_enc_size = static_cast<uint8_t>(bytes.size());
|
||||
if (color_enc_size != bytes.size()) return JXL_FALSE;
|
||||
SAFE_CURSOR_UPDATE(1);
|
||||
memcpy(output_buffer + cursor, &color_enc_size, 1);
|
||||
|
||||
SAFE_CURSOR_UPDATE(color_enc_size);
|
||||
memcpy(output_buffer + cursor, bytes.data(), color_enc_size);
|
||||
|
||||
SAFE_CURSOR_UPDATE(4);
|
||||
StoreBE32(map_bundle->alt_icc_size, output_buffer + cursor);
|
||||
|
||||
SAFE_CURSOR_UPDATE(map_bundle->alt_icc_size);
|
||||
memcpy(output_buffer + cursor, map_bundle->alt_icc, map_bundle->alt_icc_size);
|
||||
|
||||
SAFE_CURSOR_UPDATE(map_bundle->gain_map_size);
|
||||
memcpy(output_buffer + cursor, map_bundle->gain_map,
|
||||
map_bundle->gain_map_size);
|
||||
|
||||
#undef SAFE_CURSOR_UPDATE
|
||||
|
||||
cursor = next_cursor;
|
||||
|
||||
if (bytes_written != nullptr)
|
||||
*bytes_written = cursor; // Ensure size_t compatibility
|
||||
return cursor == output_buffer_size ? JXL_TRUE : JXL_FALSE;
|
||||
}
|
||||
|
||||
JXL_BOOL JxlGainMapReadBundle(JxlGainMapBundle* map_bundle,
|
||||
const uint8_t* input_buffer,
|
||||
const size_t input_buffer_size,
|
||||
size_t* bytes_read) {
|
||||
if (map_bundle == nullptr || input_buffer == nullptr ||
|
||||
input_buffer_size == 0) {
|
||||
return JXL_FALSE;
|
||||
}
|
||||
|
||||
uint64_t cursor = 0;
|
||||
uint64_t next_cursor = 0;
|
||||
|
||||
#define SAFE_CURSOR_UPDATE(n) \
|
||||
do { \
|
||||
cursor = next_cursor; \
|
||||
if (!jxl::SafeAdd(cursor, n, next_cursor) || \
|
||||
next_cursor > input_buffer_size) { \
|
||||
return JXL_FALSE; \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
// Read the version byte
|
||||
SAFE_CURSOR_UPDATE(1);
|
||||
map_bundle->jhgm_version = input_buffer[cursor];
|
||||
|
||||
// Read gain_map_metadata_size
|
||||
SAFE_CURSOR_UPDATE(2);
|
||||
uint16_t gain_map_metadata_size = LoadBE16(input_buffer + cursor);
|
||||
|
||||
SAFE_CURSOR_UPDATE(gain_map_metadata_size);
|
||||
map_bundle->gain_map_metadata_size = gain_map_metadata_size;
|
||||
map_bundle->gain_map_metadata = input_buffer + cursor;
|
||||
|
||||
// Read compressed_color_encoding_size
|
||||
SAFE_CURSOR_UPDATE(1);
|
||||
uint8_t compressed_color_encoding_size;
|
||||
memcpy(&compressed_color_encoding_size, input_buffer + cursor, 1);
|
||||
|
||||
map_bundle->has_color_encoding = (compressed_color_encoding_size > 0);
|
||||
if (map_bundle->has_color_encoding) {
|
||||
SAFE_CURSOR_UPDATE(compressed_color_encoding_size);
|
||||
// Decode color encoding
|
||||
jxl::Span<const uint8_t> color_encoding_span(
|
||||
input_buffer + cursor, compressed_color_encoding_size);
|
||||
jxl::BitReader color_encoding_reader(color_encoding_span);
|
||||
jxl::ColorEncoding internal_color_encoding;
|
||||
if (!jxl::Bundle::Read(&color_encoding_reader, &internal_color_encoding)) {
|
||||
return JXL_FALSE;
|
||||
}
|
||||
JXL_RETURN_IF_ERROR(color_encoding_reader.Close());
|
||||
map_bundle->color_encoding = internal_color_encoding.ToExternal();
|
||||
}
|
||||
|
||||
// Read compressed_icc_size
|
||||
SAFE_CURSOR_UPDATE(4);
|
||||
uint32_t compressed_icc_size = LoadBE32(input_buffer + cursor);
|
||||
|
||||
SAFE_CURSOR_UPDATE(compressed_icc_size);
|
||||
map_bundle->alt_icc_size = compressed_icc_size;
|
||||
map_bundle->alt_icc = input_buffer + cursor;
|
||||
|
||||
// Calculate remaining bytes for gain map
|
||||
cursor = next_cursor;
|
||||
// This calculation is guaranteed not to underflow because `cursor` is always
|
||||
// updated to a position within or at the end of `input_buffer` (not beyond).
|
||||
// Thus, subtracting `cursor` from `input_buffer_size` (the total size of the
|
||||
// buffer) will always result in a non-negative integer representing the
|
||||
// remaining buffer size.
|
||||
map_bundle->gain_map_size = input_buffer_size - cursor;
|
||||
SAFE_CURSOR_UPDATE(map_bundle->gain_map_size);
|
||||
map_bundle->gain_map = input_buffer + cursor;
|
||||
|
||||
#undef SAFE_CURSOR_UPDATE
|
||||
|
||||
cursor = next_cursor;
|
||||
|
||||
if (bytes_read != nullptr) {
|
||||
*bytes_read = cursor;
|
||||
}
|
||||
return JXL_TRUE;
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
// Copyright (c) the JPEG XL Project Authors. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "jxl/gain_map.h"
|
||||
|
||||
#include <jxl/color_encoding.h>
|
||||
#include <jxl/encode.h>
|
||||
#include <jxl/types.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "lib/jxl/test_utils.h"
|
||||
#include "lib/jxl/testing.h"
|
||||
|
||||
namespace {
|
||||
|
||||
std::vector<uint8_t> GoldenTestGainMap(bool has_icc, bool has_color_encoding) {
|
||||
// Define the parts of the gain map
|
||||
uint8_t jhgm_version = 0x00;
|
||||
std::vector<uint8_t> gain_map_metadata_size = {0x00, 0x58}; // 88 in decimal
|
||||
// TODO(firsching): Replace with more realistic data
|
||||
std::string first_placeholder =
|
||||
"placeholder gain map metadata, fill with actual example after (ISO "
|
||||
"21496-1) is finalized";
|
||||
|
||||
uint8_t color_encoding_size = has_color_encoding ? 3 : 0;
|
||||
std::vector<uint8_t> color_encoding = {0x50, 0xb4, 0x00};
|
||||
|
||||
std::vector<uint8_t> icc_size = {0x00, 0x00, 0x00, 0x00};
|
||||
if (has_icc) {
|
||||
icc_size = {0x00, 0x00, 0x00, 0x88}; // 136 in decimal
|
||||
}
|
||||
std::vector<uint8_t> icc_data = jxl::test::GetCompressedIccTestProfile();
|
||||
std::string second_placeholder =
|
||||
"placeholder for an actual naked JPEG XL codestream";
|
||||
|
||||
// Assemble the gain map
|
||||
std::vector<uint8_t> gain_map;
|
||||
gain_map.push_back(jhgm_version);
|
||||
gain_map.insert(gain_map.end(), gain_map_metadata_size.begin(),
|
||||
gain_map_metadata_size.end());
|
||||
gain_map.insert(gain_map.end(), first_placeholder.begin(),
|
||||
first_placeholder.end());
|
||||
gain_map.push_back(color_encoding_size);
|
||||
if (has_color_encoding) {
|
||||
gain_map.insert(gain_map.end(), color_encoding.begin(),
|
||||
color_encoding.end());
|
||||
}
|
||||
gain_map.insert(gain_map.end(), icc_size.begin(), icc_size.end());
|
||||
if (has_icc) {
|
||||
gain_map.insert(gain_map.end(), icc_data.begin(), icc_data.end());
|
||||
}
|
||||
gain_map.insert(gain_map.end(), second_placeholder.begin(),
|
||||
second_placeholder.end());
|
||||
|
||||
return gain_map;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace jxl {
|
||||
namespace {
|
||||
|
||||
struct GainMapTestParams {
|
||||
bool has_color_encoding;
|
||||
std::vector<uint8_t> icc_data;
|
||||
};
|
||||
|
||||
class GainMapTest : public ::testing::TestWithParam<GainMapTestParams> {};
|
||||
|
||||
TEST_P(GainMapTest, GainMapRoundtrip) {
|
||||
size_t bundle_size;
|
||||
const GainMapTestParams& params = GetParam();
|
||||
std::vector<uint8_t> golden_gain_map =
|
||||
GoldenTestGainMap(!params.icc_data.empty(), params.has_color_encoding);
|
||||
|
||||
JxlGainMapBundle orig_bundle;
|
||||
// Initialize the bundle with some test data
|
||||
orig_bundle.jhgm_version = 0;
|
||||
const char* metadata_str =
|
||||
"placeholder gain map metadata, fill with actual example after (ISO "
|
||||
"21496-1) is finalized";
|
||||
std::vector<uint8_t> gain_map_metadata(metadata_str,
|
||||
metadata_str + strlen(metadata_str));
|
||||
orig_bundle.gain_map_metadata_size = gain_map_metadata.size();
|
||||
orig_bundle.gain_map_metadata = gain_map_metadata.data();
|
||||
|
||||
// Use the ICC profile from the parameter
|
||||
orig_bundle.has_color_encoding = TO_JXL_BOOL(params.has_color_encoding);
|
||||
if (orig_bundle.has_color_encoding) {
|
||||
JxlColorEncoding color_encoding = {};
|
||||
JxlColorEncodingSetToLinearSRGB(&color_encoding, /*is_gray=*/JXL_FALSE);
|
||||
orig_bundle.color_encoding = color_encoding;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> alt_icc(params.icc_data.begin(), params.icc_data.end());
|
||||
orig_bundle.alt_icc = alt_icc.data();
|
||||
orig_bundle.alt_icc_size = alt_icc.size();
|
||||
|
||||
const char* gain_map_str =
|
||||
"placeholder for an actual naked JPEG XL codestream";
|
||||
std::vector<uint8_t> gain_map(gain_map_str,
|
||||
gain_map_str + strlen(gain_map_str));
|
||||
orig_bundle.gain_map_size = gain_map.size();
|
||||
orig_bundle.gain_map = gain_map.data();
|
||||
|
||||
ASSERT_TRUE(JxlGainMapGetBundleSize(&orig_bundle, &bundle_size));
|
||||
EXPECT_EQ(bundle_size, golden_gain_map.size());
|
||||
|
||||
std::vector<uint8_t> buffer(bundle_size);
|
||||
size_t bytes_written;
|
||||
ASSERT_TRUE(JxlGainMapWriteBundle(&orig_bundle, buffer.data(), buffer.size(),
|
||||
&bytes_written));
|
||||
EXPECT_EQ(bytes_written, bundle_size);
|
||||
EXPECT_EQ(buffer[0], orig_bundle.jhgm_version);
|
||||
EXPECT_EQ(buffer.size(), golden_gain_map.size());
|
||||
EXPECT_TRUE(
|
||||
std::equal(buffer.begin(), buffer.end(), golden_gain_map.begin()));
|
||||
|
||||
JxlGainMapBundle output_bundle;
|
||||
size_t bytes_read;
|
||||
ASSERT_TRUE(JxlGainMapReadBundle(&output_bundle, buffer.data(), buffer.size(),
|
||||
&bytes_read));
|
||||
|
||||
EXPECT_EQ(output_bundle.gain_map_size, orig_bundle.gain_map_size);
|
||||
EXPECT_EQ(output_bundle.gain_map_metadata_size,
|
||||
orig_bundle.gain_map_metadata_size);
|
||||
EXPECT_EQ(output_bundle.alt_icc_size, orig_bundle.alt_icc_size);
|
||||
EXPECT_EQ(output_bundle.has_color_encoding, params.has_color_encoding);
|
||||
EXPECT_EQ(output_bundle.jhgm_version, orig_bundle.jhgm_version);
|
||||
std::vector<uint8_t> output_gain_map_metadata(
|
||||
output_bundle.gain_map_metadata,
|
||||
output_bundle.gain_map_metadata + output_bundle.gain_map_metadata_size);
|
||||
std::vector<uint8_t> output_alt_icc(
|
||||
output_bundle.alt_icc,
|
||||
output_bundle.alt_icc + output_bundle.alt_icc_size);
|
||||
std::vector<uint8_t> output_gain_map(
|
||||
output_bundle.gain_map,
|
||||
output_bundle.gain_map + output_bundle.gain_map_size);
|
||||
EXPECT_TRUE(std::equal(output_gain_map_metadata.begin(),
|
||||
output_gain_map_metadata.end(),
|
||||
gain_map_metadata.begin()));
|
||||
EXPECT_TRUE(std::equal(output_alt_icc.begin(), output_alt_icc.end(),
|
||||
alt_icc.begin()));
|
||||
EXPECT_TRUE(std::equal(output_gain_map.begin(), output_gain_map.end(),
|
||||
gain_map.begin()));
|
||||
}
|
||||
|
||||
JXL_GTEST_INSTANTIATE_TEST_SUITE_P(
|
||||
GainMapTestCases, GainMapTest,
|
||||
::testing::Values(
|
||||
GainMapTestParams{true, std::vector<uint8_t>()},
|
||||
GainMapTestParams{true, test::GetCompressedIccTestProfile()},
|
||||
GainMapTestParams{false, test::GetCompressedIccTestProfile()},
|
||||
GainMapTestParams{false, std::vector<uint8_t>()}),
|
||||
[](const testing::TestParamInfo<GainMapTest::ParamType>& info) {
|
||||
std::string name =
|
||||
"HasColorEncoding" + std::to_string(info.param.has_color_encoding);
|
||||
|
||||
name += "ICCSize" + std::to_string(info.param.icc_data.size());
|
||||
|
||||
return name;
|
||||
});
|
||||
|
||||
} // namespace
|
||||
} // namespace jxl
|
|
@ -26,27 +26,27 @@ Status HlgOOTF(ImageBundle* ib, const float gamma, ThreadPool* pool) {
|
|||
JXL_RETURN_IF_ERROR(
|
||||
ib->TransformTo(linear_rec2020, *JxlGetDefaultCms(), pool));
|
||||
|
||||
JXL_RETURN_IF_ERROR(RunOnPool(
|
||||
pool, 0, ib->ysize(), ThreadPool::NoInit,
|
||||
[&](const int y, const int thread) {
|
||||
float* const JXL_RESTRICT rows[3] = {ib->color()->PlaneRow(0, y),
|
||||
ib->color()->PlaneRow(1, y),
|
||||
ib->color()->PlaneRow(2, y)};
|
||||
for (size_t x = 0; x < ib->xsize(); ++x) {
|
||||
float& red = rows[0][x];
|
||||
float& green = rows[1][x];
|
||||
float& blue = rows[2][x];
|
||||
const float luminance =
|
||||
0.2627f * red + 0.6780f * green + 0.0593f * blue;
|
||||
const float ratio = std::pow(luminance, gamma - 1);
|
||||
if (std::isfinite(ratio)) {
|
||||
red *= ratio;
|
||||
green *= ratio;
|
||||
blue *= ratio;
|
||||
}
|
||||
}
|
||||
},
|
||||
"HlgOOTF"));
|
||||
const auto process_row = [&](const int y, const int thread) -> Status {
|
||||
float* const JXL_RESTRICT rows[3] = {ib->color()->PlaneRow(0, y),
|
||||
ib->color()->PlaneRow(1, y),
|
||||
ib->color()->PlaneRow(2, y)};
|
||||
for (size_t x = 0; x < ib->xsize(); ++x) {
|
||||
float& red = rows[0][x];
|
||||
float& green = rows[1][x];
|
||||
float& blue = rows[2][x];
|
||||
const float luminance = 0.2627f * red + 0.6780f * green + 0.0593f * blue;
|
||||
const float ratio = std::pow(luminance, gamma - 1);
|
||||
if (std::isfinite(ratio)) {
|
||||
red *= ratio;
|
||||
green *= ratio;
|
||||
blue *= ratio;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
JXL_RETURN_IF_ERROR(RunOnPool(pool, 0, ib->ysize(), ThreadPool::NoInit,
|
||||
process_row, "HlgOOTF"));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include <jxl/color_encoding.h>
|
||||
#include <jxl/types.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
@ -40,9 +39,9 @@ namespace jxl {
|
|||
namespace extras {
|
||||
namespace {
|
||||
|
||||
using test::Butteraugli3Norm;
|
||||
using test::ButteraugliDistance;
|
||||
using test::TestImage;
|
||||
using ::jxl::test::Butteraugli3Norm;
|
||||
using ::jxl::test::ButteraugliDistance;
|
||||
using ::jxl::test::TestImage;
|
||||
|
||||
Status ReadTestImage(const std::string& pathname, PackedPixelFile* ppf) {
|
||||
const std::vector<uint8_t> encoded = jxl::test::ReadTestData(pathname);
|
||||
|
@ -93,7 +92,7 @@ Status EncodeWithLibjpeg(const PackedPixelFile& ppf, int quality,
|
|||
|
||||
std::string Description(const JxlColorEncoding& color_encoding) {
|
||||
ColorEncoding c_enc;
|
||||
JXL_CHECK(c_enc.FromExternal(color_encoding));
|
||||
EXPECT_TRUE(c_enc.FromExternal(color_encoding));
|
||||
return Description(c_enc);
|
||||
}
|
||||
|
||||
|
@ -156,8 +155,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) {
|
||||
|
@ -165,9 +164,10 @@ TEST(JpegliTest, JpegliDecodeTestLargeSmoothArea) {
|
|||
TestImage t;
|
||||
const size_t xsize = 2070;
|
||||
const size_t ysize = 1063;
|
||||
t.SetDimensions(xsize, ysize).SetChannels(3);
|
||||
ASSERT_TRUE(t.SetDimensions(xsize, ysize));
|
||||
ASSERT_TRUE(t.SetChannels(3));
|
||||
t.SetAllBitDepths(8).SetEndianness(JXL_NATIVE_ENDIAN);
|
||||
TestImage::Frame frame = t.AddFrame();
|
||||
JXL_TEST_ASSIGN_OR_DIE(TestImage::Frame frame, t.AddFrame());
|
||||
frame.RandomFill();
|
||||
// Create a large smooth area in the top half of the image. This is to test
|
||||
// that the bias statistics calculation can handle many blocks with all-zero
|
||||
|
@ -175,7 +175,7 @@ TEST(JpegliTest, JpegliDecodeTestLargeSmoothArea) {
|
|||
for (size_t y = 0; y < ysize / 2; ++y) {
|
||||
for (size_t x = 0; x < xsize; ++x) {
|
||||
for (size_t c = 0; c < 3; ++c) {
|
||||
frame.SetValue(y, x, c, 0.5f);
|
||||
ASSERT_TRUE(frame.SetValue(y, x, c, 0.5f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,15 +247,15 @@ 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) {
|
||||
std::string testimage = "jxl/hdr_room.png";
|
||||
PackedPixelFile ppf_in;
|
||||
ASSERT_TRUE(ReadTestImage(testimage, &ppf_in));
|
||||
EXPECT_EQ("RGB_D65_202_Rel_HLG", Description(ppf_in.color_encoding));
|
||||
EXPECT_EQ("Rec2100HLG", Description(ppf_in.color_encoding));
|
||||
EXPECT_EQ(16, ppf_in.info.bits_per_sample);
|
||||
|
||||
std::vector<uint8_t> compressed;
|
||||
|
@ -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) {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <hwy/highway.h>
|
||||
|
||||
#include "lib/jxl/base/compiler_specific.h"
|
||||
#include "lib/jxl/base/rect.h"
|
||||
#include "lib/jxl/base/status.h"
|
||||
#include "lib/jxl/color_encoding_internal.h"
|
||||
HWY_BEFORE_NAMESPACE();
|
||||
|
@ -125,23 +126,27 @@ double ComputeDistanceP(const ImageF& distmap, const ButteraugliParams& params,
|
|||
|
||||
void ComputeSumOfSquares(const ImageBundle& ib1, const ImageBundle& ib2,
|
||||
const JxlCmsInterface& cms, double sum_of_squares[3]) {
|
||||
sum_of_squares[0] = sum_of_squares[1] = sum_of_squares[2] =
|
||||
std::numeric_limits<double>::max();
|
||||
// Convert to sRGB - closer to perception than linear.
|
||||
const Image3F* srgb1 = &ib1.color();
|
||||
Image3F copy1;
|
||||
if (!ib1.IsSRGB()) {
|
||||
JXL_CHECK(
|
||||
ib1.CopyTo(Rect(ib1), ColorEncoding::SRGB(ib1.IsGray()), cms, ©1));
|
||||
if (!ib1.CopyTo(Rect(ib1), ColorEncoding::SRGB(ib1.IsGray()), cms, ©1))
|
||||
return;
|
||||
srgb1 = ©1;
|
||||
}
|
||||
const Image3F* srgb2 = &ib2.color();
|
||||
Image3F copy2;
|
||||
if (!ib2.IsSRGB()) {
|
||||
JXL_CHECK(
|
||||
ib2.CopyTo(Rect(ib2), ColorEncoding::SRGB(ib2.IsGray()), cms, ©2));
|
||||
if (!ib2.CopyTo(Rect(ib2), ColorEncoding::SRGB(ib2.IsGray()), cms, ©2))
|
||||
return;
|
||||
srgb2 = ©2;
|
||||
}
|
||||
|
||||
JXL_CHECK(SameSize(*srgb1, *srgb2));
|
||||
if (!SameSize(*srgb1, *srgb2)) return;
|
||||
|
||||
sum_of_squares[0] = sum_of_squares[1] = sum_of_squares[2] = 0.0;
|
||||
|
||||
// TODO(veluca): SIMD.
|
||||
float yuvmatrix[3][3] = {{0.299, 0.587, 0.114},
|
||||
|
|
|
@ -18,10 +18,10 @@ class MemoryMappedFile {
|
|||
static StatusOr<MemoryMappedFile> Init(const char* path);
|
||||
const uint8_t* data() const;
|
||||
size_t size() const;
|
||||
MemoryMappedFile();
|
||||
~MemoryMappedFile();
|
||||
MemoryMappedFile(MemoryMappedFile&&) noexcept;
|
||||
MemoryMappedFile& operator=(MemoryMappedFile&&) noexcept;
|
||||
MemoryMappedFile(); // NOLINT
|
||||
~MemoryMappedFile(); // NOLINT
|
||||
MemoryMappedFile(MemoryMappedFile&&) noexcept; // NOLINT
|
||||
MemoryMappedFile& operator=(MemoryMappedFile&&) noexcept; // NOLINT
|
||||
|
||||
private:
|
||||
std::unique_ptr<MemoryMappedFileImpl> impl_;
|
||||
|
|
|
@ -12,22 +12,19 @@
|
|||
#include <jxl/codestream_header.h>
|
||||
#include <jxl/encode.h>
|
||||
#include <jxl/types.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "lib/jxl/base/byte_order.h"
|
||||
#include "lib/jxl/base/c_callback_support.h"
|
||||
#include "lib/jxl/base/common.h"
|
||||
#include "lib/jxl/base/status.h"
|
||||
|
||||
|
@ -37,11 +34,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;
|
||||
|
@ -73,6 +77,15 @@ class PackedImage {
|
|||
|
||||
size_t pixel_stride() const { return pixel_stride_; }
|
||||
|
||||
static Status ValidateDataType(JxlDataType data_type) {
|
||||
if ((data_type != JXL_TYPE_UINT8) && (data_type != JXL_TYPE_UINT16) &&
|
||||
(data_type != JXL_TYPE_FLOAT) && (data_type != JXL_TYPE_FLOAT16)) {
|
||||
return JXL_FAILURE("Unhandled data type: %d",
|
||||
static_cast<int>(data_type));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static size_t BitsPerChannel(JxlDataType data_type) {
|
||||
switch (data_type) {
|
||||
case JXL_TYPE_UINT8:
|
||||
|
@ -84,7 +97,8 @@ class PackedImage {
|
|||
case JXL_TYPE_FLOAT16:
|
||||
return 16;
|
||||
default:
|
||||
JXL_ABORT("Unhandled JxlDataType");
|
||||
JXL_DEBUG_ABORT("Unreachable");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,7 +118,8 @@ class PackedImage {
|
|||
return swap_endianness_ ? BSwapFloat(val) : val;
|
||||
}
|
||||
default:
|
||||
JXL_ABORT("Unhandled JxlDataType");
|
||||
JXL_DEBUG_ABORT("Unreachable");
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,7 +145,7 @@ class PackedImage {
|
|||
break;
|
||||
}
|
||||
default:
|
||||
JXL_ABORT("Unhandled JxlDataType");
|
||||
JXL_DEBUG_ABORT("Unreachable");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,11 +184,20 @@ 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();
|
||||
|
@ -224,6 +248,7 @@ class PackedMetadata {
|
|||
public:
|
||||
std::vector<uint8_t> exif;
|
||||
std::vector<uint8_t> iptc;
|
||||
std::vector<uint8_t> jhgm;
|
||||
std::vector<uint8_t> jumbf;
|
||||
std::vector<uint8_t> xmp;
|
||||
};
|
||||
|
@ -261,6 +286,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;
|
||||
|
|
|
@ -7,10 +7,14 @@
|
|||
|
||||
#include <jxl/cms.h>
|
||||
#include <jxl/color_encoding.h>
|
||||
#include <jxl/memory_manager.h>
|
||||
#include <jxl/types.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
|
||||
#include "lib/extras/packed_image.h"
|
||||
#include "lib/jxl/base/rect.h"
|
||||
#include "lib/jxl/base/status.h"
|
||||
#include "lib/jxl/color_encoding_internal.h"
|
||||
#include "lib/jxl/dec_external_image.h"
|
||||
|
@ -22,25 +26,31 @@ 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;
|
||||
JXL_ASSERT(frame_bits_per_sample != 0);
|
||||
JxlMemoryManager* memory_manager = io.memory_manager;
|
||||
JXL_ENSURE(frame.color.pixels() != nullptr);
|
||||
size_t frame_bits_per_sample;
|
||||
if (input_bitdepth.type == JXL_BIT_DEPTH_FROM_PIXEL_FORMAT) {
|
||||
JXL_RETURN_IF_ERROR(
|
||||
PackedImage::ValidateDataType(frame.color.format.data_type));
|
||||
frame_bits_per_sample =
|
||||
PackedImage::BitsPerChannel(frame.color.format.data_type);
|
||||
} else {
|
||||
frame_bits_per_sample = info.bits_per_sample;
|
||||
}
|
||||
JXL_ENSURE(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.
|
||||
JXL_ASSERT(1 <= frame.color.format.num_channels &&
|
||||
JXL_ENSURE(1 <= frame.color.format.num_channels &&
|
||||
frame.color.format.num_channels <= 4);
|
||||
|
||||
const Span<const uint8_t> span(
|
||||
static_cast<const uint8_t*>(frame.color.pixels()),
|
||||
frame.color.pixels_size);
|
||||
JXL_ASSERT(Rect(frame.frame_info.layer_info.crop_x0,
|
||||
JXL_ENSURE(Rect(frame.frame_info.layer_info.crop_x0,
|
||||
frame.frame_info.layer_info.crop_y0,
|
||||
frame.frame_info.layer_info.xsize,
|
||||
frame.frame_info.layer_info.ysize)
|
||||
|
@ -54,7 +64,7 @@ Status ConvertPackedFrameToImageBundle(const JxlBasicInfo& info,
|
|||
bundle->origin.y0 = frame.frame_info.layer_info.crop_y0;
|
||||
}
|
||||
bundle->name = frame.name; // frame.frame_info.name_length is ignored here.
|
||||
JXL_ASSERT(io.metadata.m.color_encoding.IsGray() ==
|
||||
JXL_ENSURE(io.metadata.m.color_encoding.IsGray() ==
|
||||
(frame.color.format.num_channels <= 2));
|
||||
|
||||
JXL_RETURN_IF_ERROR(ConvertFromExternal(
|
||||
|
@ -64,31 +74,33 @@ Status ConvertPackedFrameToImageBundle(const JxlBasicInfo& info,
|
|||
bundle->extra_channels().resize(io.metadata.m.extra_channel_info.size());
|
||||
for (size_t i = 0; i < frame.extra_channels.size(); i++) {
|
||||
const auto& ppf_ec = frame.extra_channels[i];
|
||||
JXL_ASSIGN_OR_RETURN(bundle->extra_channels()[i],
|
||||
ImageF::Create(ppf_ec.xsize, ppf_ec.ysize));
|
||||
JXL_CHECK(BufferToImageF(ppf_ec.format, ppf_ec.xsize, ppf_ec.ysize,
|
||||
ppf_ec.pixels(), ppf_ec.pixels_size, pool,
|
||||
&bundle->extra_channels()[i]));
|
||||
JXL_ASSIGN_OR_RETURN(
|
||||
bundle->extra_channels()[i],
|
||||
ImageF::Create(memory_manager, ppf_ec.xsize, ppf_ec.ysize));
|
||||
JXL_RETURN_IF_ERROR(BufferToImageF(
|
||||
ppf_ec.format, ppf_ec.xsize, ppf_ec.ysize, ppf_ec.pixels(),
|
||||
ppf_ec.pixels_size, pool, &bundle->extra_channels()[i]));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Status ConvertPackedPixelFileToCodecInOut(const PackedPixelFile& ppf,
|
||||
ThreadPool* pool, CodecInOut* io) {
|
||||
JxlMemoryManager* memory_manager = io->memory_manager;
|
||||
const bool has_alpha = ppf.info.alpha_bits != 0;
|
||||
JXL_ASSERT(!ppf.frames.empty());
|
||||
JXL_ENSURE(!ppf.frames.empty());
|
||||
if (has_alpha) {
|
||||
JXL_ASSERT(ppf.info.alpha_bits == ppf.info.bits_per_sample);
|
||||
JXL_ASSERT(ppf.info.alpha_exponent_bits ==
|
||||
JXL_ENSURE(ppf.info.alpha_bits == ppf.info.bits_per_sample);
|
||||
JXL_ENSURE(ppf.info.alpha_exponent_bits ==
|
||||
ppf.info.exponent_bits_per_sample);
|
||||
}
|
||||
|
||||
const bool is_gray = (ppf.info.num_color_channels == 1);
|
||||
JXL_ASSERT(ppf.info.num_color_channels == 1 ||
|
||||
JXL_ENSURE(ppf.info.num_color_channels == 1 ||
|
||||
ppf.info.num_color_channels == 3);
|
||||
|
||||
// Convert the image metadata
|
||||
io->SetSize(ppf.info.xsize, ppf.info.ysize);
|
||||
JXL_RETURN_IF_ERROR(io->SetSize(ppf.info.xsize, ppf.info.ysize));
|
||||
io->metadata.m.bit_depth.bits_per_sample = ppf.info.bits_per_sample;
|
||||
io->metadata.m.bit_depth.exponent_bits_per_sample =
|
||||
ppf.info.exponent_bits_per_sample;
|
||||
|
@ -103,11 +115,11 @@ Status ConvertPackedPixelFileToCodecInOut(const PackedPixelFile& ppf,
|
|||
if (alpha) alpha->bit_depth = io->metadata.m.bit_depth;
|
||||
|
||||
io->metadata.m.xyb_encoded = !FROM_JXL_BOOL(ppf.info.uses_original_profile);
|
||||
JXL_ASSERT(ppf.info.orientation > 0 && ppf.info.orientation <= 8);
|
||||
JXL_ENSURE(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);
|
||||
JXL_ENSURE(ppf.frames.size() == 1 || 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;
|
||||
|
@ -141,6 +153,7 @@ Status ConvertPackedPixelFileToCodecInOut(const PackedPixelFile& ppf,
|
|||
// Convert the extra blobs
|
||||
io->blobs.exif = ppf.metadata.exif;
|
||||
io->blobs.iptc = ppf.metadata.iptc;
|
||||
io->blobs.jhgm = ppf.metadata.jhgm;
|
||||
io->blobs.jumbf = ppf.metadata.jumbf;
|
||||
io->blobs.xmp = ppf.metadata.xmp;
|
||||
|
||||
|
@ -171,15 +184,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));
|
||||
ImageBundle bundle(memory_manager, &io->metadata.m);
|
||||
JXL_RETURN_IF_ERROR(ConvertPackedFrameToImageBundle(
|
||||
ppf.info, ppf.input_bitdepth, frame, *io, pool, &bundle));
|
||||
io->frames.push_back(std::move(bundle));
|
||||
}
|
||||
|
||||
|
@ -192,18 +206,18 @@ Status ConvertPackedPixelFileToCodecInOut(const PackedPixelFile& ppf,
|
|||
} else {
|
||||
SetIntensityTarget(&io->metadata.m);
|
||||
}
|
||||
io->CheckMetadata();
|
||||
JXL_RETURN_IF_ERROR(io->CheckMetadata());
|
||||
return true;
|
||||
}
|
||||
|
||||
PackedPixelFile ConvertImage3FToPackedPixelFile(const Image3F& image,
|
||||
const ColorEncoding& c_enc,
|
||||
JxlPixelFormat format,
|
||||
ThreadPool* pool) {
|
||||
PackedPixelFile ppf;
|
||||
StatusOr<PackedPixelFile> ConvertImage3FToPackedPixelFile(
|
||||
const Image3F& image, const ColorEncoding& c_enc, JxlPixelFormat format,
|
||||
ThreadPool* pool) {
|
||||
PackedPixelFile ppf{};
|
||||
ppf.info.xsize = image.xsize();
|
||||
ppf.info.ysize = image.ysize();
|
||||
ppf.info.num_color_channels = 3;
|
||||
JXL_RETURN_IF_ERROR(PackedImage::ValidateDataType(format.data_type));
|
||||
ppf.info.bits_per_sample = PackedImage::BitsPerChannel(format.data_type);
|
||||
ppf.info.exponent_bits_per_sample = format.data_type == JXL_TYPE_FLOAT ? 8
|
||||
: format.data_type == JXL_TYPE_FLOAT16
|
||||
|
@ -211,13 +225,15 @@ 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_RETURN(
|
||||
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);
|
||||
}
|
||||
bool float_samples = ppf.info.exponent_bits_per_sample > 0;
|
||||
JXL_CHECK(ConvertChannelsToExternal(
|
||||
JXL_RETURN_IF_ERROR(ConvertChannelsToExternal(
|
||||
channels, 3, ppf.info.bits_per_sample, float_samples, format.endianness,
|
||||
frame.color.stride, pool, frame.color.pixels(0, 0, 0),
|
||||
frame.color.pixels_size, PixelCallback(), Orientation::kIdentity));
|
||||
|
@ -231,14 +247,15 @@ Status ConvertCodecInOutToPackedPixelFile(const CodecInOut& io,
|
|||
const ColorEncoding& c_desired,
|
||||
ThreadPool* pool,
|
||||
PackedPixelFile* ppf) {
|
||||
JxlMemoryManager* memory_manager = io.memory_manager;
|
||||
const bool has_alpha = io.metadata.m.HasAlpha();
|
||||
JXL_ASSERT(!io.frames.empty());
|
||||
JXL_ENSURE(!io.frames.empty());
|
||||
|
||||
if (has_alpha) {
|
||||
JXL_ASSERT(io.metadata.m.GetAlphaBits() ==
|
||||
JXL_ENSURE(io.metadata.m.GetAlphaBits() ==
|
||||
io.metadata.m.bit_depth.bits_per_sample);
|
||||
const auto* alpha_channel = io.metadata.m.Find(ExtraChannel::kAlpha);
|
||||
JXL_ASSERT(alpha_channel->bit_depth.exponent_bits_per_sample ==
|
||||
JXL_ENSURE(alpha_channel->bit_depth.exponent_bits_per_sample ==
|
||||
io.metadata.m.bit_depth.exponent_bits_per_sample);
|
||||
ppf->info.alpha_bits = alpha_channel->bit_depth.bits_per_sample;
|
||||
ppf->info.alpha_exponent_bits =
|
||||
|
@ -262,13 +279,13 @@ Status ConvertCodecInOutToPackedPixelFile(const CodecInOut& io,
|
|||
TO_JXL_BOOL(io.metadata.m.tone_mapping.relative_to_max_display);
|
||||
|
||||
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);
|
||||
JXL_ENSURE(0 < io.metadata.m.orientation && io.metadata.m.orientation <= 8);
|
||||
ppf->info.orientation =
|
||||
static_cast<JxlOrientation>(io.metadata.m.orientation);
|
||||
ppf->info.num_color_channels = io.metadata.m.color_encoding.Channels();
|
||||
|
||||
// Convert animation metadata
|
||||
JXL_ASSERT(io.frames.size() == 1 || io.metadata.m.have_animation);
|
||||
JXL_ENSURE(io.frames.size() == 1 || 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;
|
||||
|
@ -284,6 +301,7 @@ Status ConvertCodecInOutToPackedPixelFile(const CodecInOut& io,
|
|||
// Convert the extra blobs
|
||||
ppf->metadata.exif = io.blobs.exif;
|
||||
ppf->metadata.iptc = io.blobs.iptc;
|
||||
ppf->metadata.jhgm = io.blobs.jhgm;
|
||||
ppf->metadata.jumbf = io.blobs.jumbf;
|
||||
ppf->metadata.xmp = io.blobs.xmp;
|
||||
const bool float_out = pixel_format.data_type == JXL_TYPE_FLOAT ||
|
||||
|
@ -291,7 +309,7 @@ Status ConvertCodecInOutToPackedPixelFile(const CodecInOut& io,
|
|||
// Convert the pixels
|
||||
ppf->frames.clear();
|
||||
for (const auto& frame : io.frames) {
|
||||
JXL_ASSERT(frame.metadata()->bit_depth.bits_per_sample != 0);
|
||||
JXL_ENSURE(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;
|
||||
|
@ -302,8 +320,10 @@ Status ConvertCodecInOutToPackedPixelFile(const CodecInOut& io,
|
|||
/*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));
|
||||
JXL_RETURN_IF_ERROR(PackedImage::ValidateDataType(pixel_format.data_type));
|
||||
const size_t bits_per_sample =
|
||||
float_out ? packed_frame.color.BitsPerChannel(pixel_format.data_type)
|
||||
: ppf->info.bits_per_sample;
|
||||
|
@ -313,7 +333,7 @@ Status ConvertCodecInOutToPackedPixelFile(const CodecInOut& io,
|
|||
JXL_ASSIGN_OR_RETURN(ImageBundle ib, frame.Copy());
|
||||
const ImageBundle* to_color_transform = &ib;
|
||||
ImageMetadata metadata = io.metadata.m;
|
||||
ImageBundle store(&metadata);
|
||||
ImageBundle store(memory_manager, &metadata);
|
||||
const ImageBundle* transformed;
|
||||
// TODO(firsching): handle the transform here.
|
||||
JXL_RETURN_IF_ERROR(TransformIfNeeded(*to_color_transform, c_desired,
|
||||
|
@ -329,7 +349,7 @@ Status ConvertCodecInOutToPackedPixelFile(const CodecInOut& io,
|
|||
|
||||
// TODO(firsching): Convert the extra channels, beside one potential alpha
|
||||
// channel. FIXME!
|
||||
JXL_CHECK(frame.extra_channels().size() <= has_alpha);
|
||||
JXL_ENSURE(frame.extra_channels().size() <= (has_alpha ? 1 : 0));
|
||||
ppf->frames.push_back(std::move(packed_frame));
|
||||
}
|
||||
|
||||
|
|
|
@ -31,10 +31,9 @@ Status ConvertCodecInOutToPackedPixelFile(const CodecInOut& io,
|
|||
ThreadPool* pool,
|
||||
PackedPixelFile* ppf);
|
||||
|
||||
PackedPixelFile ConvertImage3FToPackedPixelFile(const Image3F& image,
|
||||
const ColorEncoding& c_enc,
|
||||
JxlPixelFormat format,
|
||||
ThreadPool* pool);
|
||||
StatusOr<PackedPixelFile> ConvertImage3FToPackedPixelFile(
|
||||
const Image3F& image, const ColorEncoding& c_enc, JxlPixelFormat format,
|
||||
ThreadPool* pool);
|
||||
} // namespace extras
|
||||
} // namespace jxl
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ double Now() {
|
|||
if (timebase.denom == 0) {
|
||||
(void)mach_timebase_info(&timebase);
|
||||
}
|
||||
return double(t) * timebase.numer / timebase.denom * 1E-9;
|
||||
return double(t) * timebase.numer / timebase.denom * 1E-9; // notypo
|
||||
#elif JXL_OS_HAIKU
|
||||
return double(system_time_nsecs()) * 1E-9;
|
||||
#else
|
||||
|
|
|
@ -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) {
|
||||
|
@ -44,23 +44,25 @@ Status ToneMapFrame(const std::pair<float, float> display_nits,
|
|||
ib->metadata()->IntensityTarget()},
|
||||
display_nits, rec2020_luminances);
|
||||
|
||||
return RunOnPool(
|
||||
pool, 0, ib->ysize(), ThreadPool::NoInit,
|
||||
[&](const uint32_t y, size_t /* thread */) {
|
||||
float* const JXL_RESTRICT row_r = ib->color()->PlaneRow(0, y);
|
||||
float* const JXL_RESTRICT row_g = ib->color()->PlaneRow(1, y);
|
||||
float* const JXL_RESTRICT row_b = ib->color()->PlaneRow(2, y);
|
||||
for (size_t x = 0; x < ib->xsize(); x += Lanes(df)) {
|
||||
V red = Load(df, row_r + x);
|
||||
V green = Load(df, row_g + x);
|
||||
V blue = Load(df, row_b + x);
|
||||
tone_mapper.ToneMap(&red, &green, &blue);
|
||||
Store(red, df, row_r + x);
|
||||
Store(green, df, row_g + x);
|
||||
Store(blue, df, row_b + x);
|
||||
}
|
||||
},
|
||||
"ToneMap");
|
||||
const auto process_row = [&](const uint32_t y,
|
||||
size_t /* thread */) -> Status {
|
||||
float* const JXL_RESTRICT row_r = ib->color()->PlaneRow(0, y);
|
||||
float* const JXL_RESTRICT row_g = ib->color()->PlaneRow(1, y);
|
||||
float* const JXL_RESTRICT row_b = ib->color()->PlaneRow(2, y);
|
||||
for (size_t x = 0; x < ib->xsize(); x += Lanes(df)) {
|
||||
V red = Load(df, row_r + x);
|
||||
V green = Load(df, row_g + x);
|
||||
V blue = Load(df, row_b + x);
|
||||
tone_mapper.ToneMap(&red, &green, &blue);
|
||||
Store(red, df, row_r + x);
|
||||
Store(green, df, row_g + x);
|
||||
Store(blue, df, row_b + x);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
JXL_RETURN_IF_ERROR(RunOnPool(pool, 0, ib->ysize(), ThreadPool::NoInit,
|
||||
process_row, "ToneMap"));
|
||||
return true;
|
||||
}
|
||||
|
||||
Status GamutMapFrame(ImageBundle* const ib, float preserve_saturation,
|
||||
|
@ -77,24 +79,24 @@ Status GamutMapFrame(ImageBundle* const ib, float preserve_saturation,
|
|||
JXL_RETURN_IF_ERROR(
|
||||
ib->TransformTo(linear_rec2020, *JxlGetDefaultCms(), pool));
|
||||
|
||||
JXL_RETURN_IF_ERROR(RunOnPool(
|
||||
pool, 0, ib->ysize(), ThreadPool::NoInit,
|
||||
[&](const uint32_t y, size_t /* thread*/) {
|
||||
float* const JXL_RESTRICT row_r = ib->color()->PlaneRow(0, y);
|
||||
float* const JXL_RESTRICT row_g = ib->color()->PlaneRow(1, y);
|
||||
float* const JXL_RESTRICT row_b = ib->color()->PlaneRow(2, y);
|
||||
for (size_t x = 0; x < ib->xsize(); x += Lanes(df)) {
|
||||
V red = Load(df, row_r + x);
|
||||
V green = Load(df, row_g + x);
|
||||
V blue = Load(df, row_b + x);
|
||||
GamutMap(&red, &green, &blue, rec2020_luminances,
|
||||
preserve_saturation);
|
||||
Store(red, df, row_r + x);
|
||||
Store(green, df, row_g + x);
|
||||
Store(blue, df, row_b + x);
|
||||
}
|
||||
},
|
||||
"GamutMap"));
|
||||
const auto process_row = [&](const uint32_t y, size_t /* thread*/) -> Status {
|
||||
float* const JXL_RESTRICT row_r = ib->color()->PlaneRow(0, y);
|
||||
float* const JXL_RESTRICT row_g = ib->color()->PlaneRow(1, y);
|
||||
float* const JXL_RESTRICT row_b = ib->color()->PlaneRow(2, y);
|
||||
for (size_t x = 0; x < ib->xsize(); x += Lanes(df)) {
|
||||
V red = Load(df, row_r + x);
|
||||
V green = Load(df, row_g + x);
|
||||
V blue = Load(df, row_b + x);
|
||||
GamutMap(&red, &green, &blue, rec2020_luminances, preserve_saturation);
|
||||
Store(red, df, row_r + x);
|
||||
Store(green, df, row_g + x);
|
||||
Store(blue, df, row_b + x);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
JXL_RETURN_IF_ERROR(RunOnPool(pool, 0, ib->ysize(), ThreadPool::NoInit,
|
||||
process_row, "GamutMap"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -3,37 +3,55 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include <jxl/memory_manager.h>
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
#include "lib/extras/codec.h"
|
||||
#include "lib/extras/tone_mapping.h"
|
||||
#include "lib/jxl/base/status.h"
|
||||
#include "lib/jxl/image.h"
|
||||
#include "tools/no_memory_manager.h"
|
||||
|
||||
namespace jxl {
|
||||
|
||||
#define QUIT(M) \
|
||||
state.SkipWithError(M); \
|
||||
return;
|
||||
|
||||
#define BM_CHECK(C) \
|
||||
if (!(C)) { \
|
||||
QUIT(#C) \
|
||||
}
|
||||
|
||||
static void BM_ToneMapping(benchmark::State& state) {
|
||||
JXL_ASSIGN_OR_DIE(Image3F color, Image3F::Create(2268, 1512));
|
||||
JxlMemoryManager* memory_manager = jpegxl::tools::NoMemoryManager();
|
||||
JXL_ASSIGN_OR_QUIT(Image3F color, Image3F::Create(memory_manager, 2268, 1512),
|
||||
"Failed to allocate color plane");
|
||||
FillImage(0.5f, &color);
|
||||
|
||||
// Use linear Rec. 2020 so that `ToneMapTo` doesn't have to convert to it and
|
||||
// we mainly measure the tone mapping itself.
|
||||
ColorEncoding linear_rec2020;
|
||||
linear_rec2020.SetColorSpace(ColorSpace::kRGB);
|
||||
JXL_CHECK(linear_rec2020.SetPrimariesType(Primaries::k2100));
|
||||
JXL_CHECK(linear_rec2020.SetWhitePointType(WhitePoint::kD65));
|
||||
BM_CHECK(linear_rec2020.SetPrimariesType(Primaries::k2100));
|
||||
BM_CHECK(linear_rec2020.SetWhitePointType(WhitePoint::kD65));
|
||||
linear_rec2020.Tf().SetTransferFunction(TransferFunction::kLinear);
|
||||
JXL_CHECK(linear_rec2020.CreateICC());
|
||||
BM_CHECK(linear_rec2020.CreateICC());
|
||||
|
||||
for (auto _ : state) {
|
||||
(void)_;
|
||||
state.PauseTiming();
|
||||
CodecInOut tone_mapping_input;
|
||||
JXL_ASSIGN_OR_DIE(Image3F color2,
|
||||
Image3F::Create(color.xsize(), color.ysize()));
|
||||
CopyImageTo(color, &color2);
|
||||
tone_mapping_input.SetFromImage(std::move(color2), linear_rec2020);
|
||||
CodecInOut tone_mapping_input{memory_manager};
|
||||
JXL_ASSIGN_OR_QUIT(
|
||||
Image3F color2,
|
||||
Image3F::Create(memory_manager, color.xsize(), color.ysize()),
|
||||
"Failed to allocate color plane");
|
||||
BM_CHECK(CopyImageTo(color, &color2));
|
||||
BM_CHECK(
|
||||
tone_mapping_input.SetFromImage(std::move(color2), linear_rec2020));
|
||||
tone_mapping_input.metadata.m.SetIntensityTarget(255);
|
||||
state.ResumeTiming();
|
||||
|
||||
JXL_CHECK(ToneMapTo({0.1, 100}, &tone_mapping_input));
|
||||
BM_CHECK(ToneMapTo({0.1, 100}, &tone_mapping_input));
|
||||
}
|
||||
|
||||
state.SetItemsProcessed(state.iterations() * color.xsize() * color.ysize());
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
@ -246,7 +246,7 @@ typedef struct {
|
|||
jpegxl_cms_destroy_func destroy;
|
||||
} JxlCmsInterface;
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
@ -424,7 +424,7 @@ typedef struct {
|
|||
JxlLayerInfo layer_info;
|
||||
} JxlFrameHeader;
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -14,9 +14,7 @@
|
|||
#ifndef JXL_COLOR_ENCODING_H_
|
||||
#define JXL_COLOR_ENCODING_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
@ -34,9 +32,9 @@ typedef enum {
|
|||
JXL_COLOR_SPACE_UNKNOWN,
|
||||
} JxlColorSpace;
|
||||
|
||||
/** Built-in whitepoints for color encoding. When decoding, the numerical xy
|
||||
* whitepoint value can be read from the @ref JxlColorEncoding white_point field
|
||||
* regardless of the enum value. When encoding, enum values except
|
||||
/** Built-in white points for color encoding. When decoding, the numerical xy
|
||||
* white point value can be read from the @ref JxlColorEncoding white_point
|
||||
* field regardless of the enum value. When encoding, enum values except
|
||||
* ::JXL_WHITE_POINT_CUSTOM override the numerical fields. Some enum values
|
||||
* match a subset of CICP (Rec. ITU-T H.273 | ISO/IEC 23091-2:2019(E)), however
|
||||
* the white point and RGB primaries are separate enums here.
|
||||
|
@ -80,7 +78,7 @@ typedef enum {
|
|||
* of CICP (Rec. ITU-T H.273 | ISO/IEC 23091-2:2019(E)) unless specified
|
||||
* otherwise. */
|
||||
typedef enum {
|
||||
/** As specified in SMPTE RP 431-2 */
|
||||
/** As specified in ITU-R BT.709-6 */
|
||||
JXL_TRANSFER_FUNCTION_709 = 1,
|
||||
/** None of the other table entries describe the transfer function. */
|
||||
JXL_TRANSFER_FUNCTION_UNKNOWN = 2,
|
||||
|
@ -99,7 +97,7 @@ typedef enum {
|
|||
JXL_TRANSFER_FUNCTION_GAMMA = 65535,
|
||||
} JxlTransferFunction;
|
||||
|
||||
/** Renderig intent for color encoding, as specified in ISO 15076-1:2010 */
|
||||
/** Rendering intent for color encoding, as specified in ISO 15076-1:2010 */
|
||||
typedef enum {
|
||||
/** vendor-specific */
|
||||
JXL_RENDERING_INTENT_PERCEPTUAL = 0,
|
||||
|
@ -119,7 +117,7 @@ typedef struct {
|
|||
JxlColorSpace color_space;
|
||||
|
||||
/** Built-in white point. If this value is ::JXL_WHITE_POINT_CUSTOM, must
|
||||
* use the numerical whitepoint values from white_point_xy.
|
||||
* use the numerical white point values from white_point_xy.
|
||||
*/
|
||||
JxlWhitePoint white_point;
|
||||
|
||||
|
@ -154,7 +152,7 @@ typedef struct {
|
|||
JxlRenderingIntent rendering_intent;
|
||||
} JxlColorEncoding;
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
/* Copyright (c) the JPEG XL Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style
|
||||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
/** @addtogroup libjxl_metadata
|
||||
* @{
|
||||
* @file compressed_icc.h
|
||||
* @brief Utility functions to compress and decompress ICC streams.
|
||||
*/
|
||||
|
||||
#ifndef JXL_COMPRESSED_ICC_H_
|
||||
#define JXL_COMPRESSED_ICC_H_
|
||||
|
||||
#include <jxl/jxl_export.h>
|
||||
#include <jxl/memory_manager.h>
|
||||
#include <jxl/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Allocates a buffer using the memory manager, fills it with a compressed
|
||||
* representation of an ICC profile, returns the result through @c output_buffer
|
||||
* and indicates its size through @c output_size.
|
||||
*
|
||||
* The result must be freed using the memory manager once it is not of any more
|
||||
* use.
|
||||
*
|
||||
* @param[in] memory_manager Pointer to a JxlMemoryManager.
|
||||
* @param[in] icc Pointer to a buffer containing the uncompressed ICC profile.
|
||||
* @param[in] icc_size Size of the buffer containing the ICC profile.
|
||||
* @param[out] compressed_icc Will be set to a pointer to the buffer containing
|
||||
* the result.
|
||||
* @param[out] compressed_icc_size Will be set to the size of the buffer
|
||||
* containing the result.
|
||||
* @return Whether compressing the profile was successful.
|
||||
*/
|
||||
JXL_EXPORT JXL_BOOL JxlICCProfileEncode(const JxlMemoryManager* memory_manager,
|
||||
const uint8_t* icc, size_t icc_size,
|
||||
uint8_t** compressed_icc,
|
||||
size_t* compressed_icc_size);
|
||||
|
||||
/**
|
||||
* Allocates a buffer using the memory manager, fills it with the decompressed
|
||||
* version of the ICC profile in @c compressed_icc, returns the result through
|
||||
* @c output_buffer and indicates its size through @c output_size.
|
||||
*
|
||||
* The result must be freed using the memory manager once it is not of any more
|
||||
* use.
|
||||
*
|
||||
* @param[in] memory_manager Pointer to a JxlMemoryManager.
|
||||
* @param[in] compressed_icc Pointer to a buffer containing the compressed ICC
|
||||
* profile.
|
||||
* @param[in] compressed_icc_size Size of the buffer containing the compressed
|
||||
* ICC profile.
|
||||
* @param[out] icc Will be set to a pointer to the buffer containing the result.
|
||||
* @param[out] icc_size Will be set to the size of the buffer containing the
|
||||
* result.
|
||||
* @return Whether decompressing the profile was successful.
|
||||
*/
|
||||
JXL_EXPORT JXL_BOOL JxlICCProfileDecode(const JxlMemoryManager* memory_manager,
|
||||
const uint8_t* compressed_icc,
|
||||
size_t compressed_icc_size,
|
||||
uint8_t** icc, size_t* icc_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* JXL_COMPRESSED_ICC_H_ */
|
||||
|
||||
/** @} */
|
|
@ -24,7 +24,7 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
@ -290,12 +290,13 @@ typedef enum {
|
|||
*
|
||||
* The buffer set with @ref JxlDecoderSetBoxBuffer must be set again for each
|
||||
* next box to be obtained, or can be left unset to skip outputting this box.
|
||||
* The output buffer contains the full box data when the next ::JXL_DEC_BOX
|
||||
* event or ::JXL_DEC_SUCCESS occurs. ::JXL_DEC_BOX occurs for all
|
||||
* boxes, including non-metadata boxes such as the signature box or codestream
|
||||
* boxes. To check whether the box is a metadata type for respectively EXIF,
|
||||
* XMP or JUMBF, use @ref JxlDecoderGetBoxType and check for types "Exif",
|
||||
* "xml " and "jumb" respectively.
|
||||
* The output buffer contains the full box data when the
|
||||
* ::JXL_DEC_BOX_COMPLETE (if subscribed to) or subsequent ::JXL_DEC_SUCCESS
|
||||
* or ::JXL_DEC_BOX event occurs. ::JXL_DEC_BOX occurs for all boxes,
|
||||
* including non-metadata boxes such as the signature box or codestream boxes.
|
||||
* To check whether the box is a metadata type for respectively EXIF, XMP or
|
||||
* JUMBF, use @ref JxlDecoderGetBoxType and check for types "Exif", "xml " and
|
||||
* "jumb" respectively.
|
||||
*
|
||||
* In this case, @ref JxlDecoderReleaseInput will return all bytes from the
|
||||
* start of the box header as unprocessed.
|
||||
|
@ -318,6 +319,11 @@ typedef enum {
|
|||
* unprocessed.
|
||||
*/
|
||||
JXL_DEC_FRAME_PROGRESSION = 0x8000,
|
||||
|
||||
/** The box being decoded is now complete. This is only emitted if a buffer
|
||||
* was set for the box.
|
||||
*/
|
||||
JXL_DEC_BOX_COMPLETE = 0x10000,
|
||||
} JxlDecoderStatus;
|
||||
|
||||
/** Types of progressive detail.
|
||||
|
@ -721,7 +727,7 @@ typedef enum {
|
|||
* It is often possible to use @ref JxlDecoderGetColorAsICCProfile as an
|
||||
* alternative anyway. The following scenarios are possible:
|
||||
* - The JPEG XL image has an attached ICC Profile, in that case, the encoded
|
||||
* structured data is not available, this function will return an error
|
||||
* structured data is not available and this function will return an error
|
||||
* status. @ref JxlDecoderGetColorAsICCProfile should be called instead.
|
||||
* - The JPEG XL image has an encoded structured color profile, and it
|
||||
* represents an RGB or grayscale color space. This function will return it.
|
||||
|
@ -800,8 +806,8 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderGetICCProfileSize(
|
|||
* or the color profile of the decoded pixels.
|
||||
* @param icc_profile buffer to copy the ICC profile into
|
||||
* @param size size of the icc_profile buffer in bytes
|
||||
* @return ::JXL_DEC_SUCCESS if the profile was successfully returned is
|
||||
* available, ::JXL_DEC_NEED_MORE_INPUT if not yet available, @ref
|
||||
* @return ::JXL_DEC_SUCCESS if the profile was successfully returned,
|
||||
* ::JXL_DEC_NEED_MORE_INPUT if not yet available, @ref
|
||||
* JXL_DEC_ERROR if the profile doesn't exist or the output size is not
|
||||
* large enough.
|
||||
*/
|
||||
|
@ -869,7 +875,7 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderSetDesiredIntensityTarget(
|
|||
*
|
||||
* This function must not be called before @ref JxlDecoderSetCms.
|
||||
*
|
||||
* @param dec decoder orbject
|
||||
* @param dec decoder object
|
||||
* @param color_encoding the output color encoding
|
||||
* @param icc_data bytes of the icc profile
|
||||
* @param icc_size size of the icc profile in bytes
|
||||
|
@ -913,7 +919,7 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderPreviewOutBufferSize(
|
|||
const JxlDecoder* dec, const JxlPixelFormat* format, size_t* size);
|
||||
|
||||
/**
|
||||
* Sets the buffer to write the small resolution preview image
|
||||
* Sets the buffer to write the low-resolution preview image
|
||||
* to. The size of the buffer must be at least as large as given by @ref
|
||||
* JxlDecoderPreviewOutBufferSize. The buffer follows the format described
|
||||
* by @ref JxlPixelFormat. The preview image dimensions are given by the
|
||||
|
@ -962,10 +968,10 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderGetFrameName(const JxlDecoder* dec,
|
|||
|
||||
/**
|
||||
* Outputs the blend information for the current frame for a specific extra
|
||||
* channel. This function can be called when ::JXL_DEC_FRAME occurred for the
|
||||
* current frame, even when have_animation in the @ref JxlBasicInfo is @ref
|
||||
* JXL_FALSE. This information is only useful if coalescing is disabled;
|
||||
* otherwise the decoder will have performed blending already.
|
||||
* channel. This function can be called once the ::JXL_DEC_FRAME event occurred
|
||||
* for the current frame, even if the `have_animation` field in the @ref
|
||||
* JxlBasicInfo is @ref JXL_FALSE. This information is only useful if coalescing
|
||||
* is disabled; otherwise the decoder will have performed blending already.
|
||||
*
|
||||
* @param dec decoder object
|
||||
* @param index the index of the extra channel
|
||||
|
@ -1344,7 +1350,7 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderSetDecompressBoxes(JxlDecoder* dec,
|
|||
* animation allowing the decoder to jump to individual frames more
|
||||
* efficiently.
|
||||
* - "jbrd": JPEG reconstruction box, contains the information required to
|
||||
* byte-for-byte losslessly recontruct a JPEG-1 image. The JPEG DCT
|
||||
* byte-for-byte losslessly reconstruct a JPEG-1 image. The JPEG DCT
|
||||
* coefficients (pixel content) themselves as well as the ICC profile are
|
||||
* encoded in the JXL codestream (jxlc or jxlp) itself. EXIF, XMP and JUMBF
|
||||
* metadata is encoded in the corresponding boxes. The jbrd box itself
|
||||
|
@ -1366,7 +1372,7 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderSetDecompressBoxes(JxlDecoder* dec,
|
|||
* @param decompressed which box type to get: JXL_FALSE to get the raw box type,
|
||||
* which can be "brob", JXL_TRUE, get the underlying box type.
|
||||
* @return ::JXL_DEC_SUCCESS if the value is available, ::JXL_DEC_ERROR if
|
||||
* not, for example the JXL file does not use the container format.
|
||||
* not, for example the JPEG XL file does not use the container format.
|
||||
*/
|
||||
JXL_EXPORT JxlDecoderStatus JxlDecoderGetBoxType(JxlDecoder* dec,
|
||||
JxlBoxType type,
|
||||
|
@ -1457,7 +1463,7 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderFlushImage(JxlDecoder* dec);
|
|||
JXL_EXPORT JxlDecoderStatus
|
||||
JxlDecoderSetImageOutBitDepth(JxlDecoder* dec, const JxlBitDepth* bit_depth);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
#if !(defined(__cplusplus) || defined(c_plusplus))
|
||||
#ifndef __cplusplus
|
||||
#error "This a C++ only header. Use jxl/decode.h from C sources."
|
||||
#endif
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
@ -388,6 +388,11 @@ typedef enum {
|
|||
*/
|
||||
JXL_ENC_FRAME_SETTING_USE_FULL_IMAGE_HEURISTICS = 38,
|
||||
|
||||
/** Disable perceptual optimizations. 0 = optimizations enabled (default), 1 =
|
||||
* optimizations disabled.
|
||||
*/
|
||||
JXL_ENC_FRAME_SETTING_DISABLE_PERCEPTUAL_HEURISTICS = 39,
|
||||
|
||||
/** Enum value not to be used as an option. This value is added to force the
|
||||
* C compiler to have the enum to take a known size.
|
||||
*/
|
||||
|
@ -1588,7 +1593,7 @@ JXL_EXPORT void JxlEncoderSetDebugImageCallback(
|
|||
JXL_EXPORT void JxlEncoderCollectStats(JxlEncoderFrameSettings* frame_settings,
|
||||
JxlEncoderStats* stats);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
#if !(defined(__cplusplus) || defined(c_plusplus))
|
||||
#ifndef __cplusplus
|
||||
#error "This a C++ only header. Use jxl/encode.h from C sources."
|
||||
#endif
|
||||
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
/* Copyright (c) the JPEG XL Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style
|
||||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
/** @addtogroup libjxl_metadata
|
||||
* @{
|
||||
* @file gain_map.h
|
||||
* @brief Utility functions to manipulate jhgm (gain map) boxes.
|
||||
*/
|
||||
|
||||
#ifndef JXL_GAIN_MAP_H_
|
||||
#define JXL_GAIN_MAP_H_
|
||||
|
||||
#include <jxl/color_encoding.h>
|
||||
#include <jxl/jxl_export.h>
|
||||
#include <jxl/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Gain map bundle
|
||||
*
|
||||
* This structure is used to serialize gain map data to and from an input
|
||||
* buffer. It holds pointers to sections within the buffer, and different parts
|
||||
* of the gain map data such as metadata, ICC profile data, and the gain map
|
||||
* itself.
|
||||
*
|
||||
* The pointers in this structure do not take ownership of the memory they point
|
||||
* to. Instead, they reference specific locations within the provided buffer. It
|
||||
* is the caller's responsibility to ensure that the buffer remains valid and is
|
||||
* not deallocated as long as these pointers are in use. The structure should be
|
||||
* considered as providing a view into the buffer, not as an owner of the data.
|
||||
*/
|
||||
typedef struct {
|
||||
/** Version number of the gain map bundle. */
|
||||
uint8_t jhgm_version;
|
||||
/** Size of the gain map metadata in bytes. */
|
||||
uint16_t gain_map_metadata_size;
|
||||
/** Pointer to the gain map metadata, which is a binary
|
||||
* blob following ISO 21496-1. This pointer references data within the input
|
||||
* buffer. */
|
||||
const uint8_t* gain_map_metadata;
|
||||
/** Indicates whether a color encoding is present. */
|
||||
JXL_BOOL has_color_encoding;
|
||||
/** If has_color_encoding is true, this field contains the
|
||||
* uncompressed color encoding data. */
|
||||
JxlColorEncoding color_encoding;
|
||||
/** Size of the alternative ICC profile in bytes (compressed
|
||||
* size). */
|
||||
uint32_t alt_icc_size;
|
||||
/** Pointer to the compressed ICC profile. This pointer references
|
||||
* data within the input buffer. */
|
||||
const uint8_t* alt_icc;
|
||||
/** Size of the gain map in bytes. */
|
||||
uint32_t gain_map_size;
|
||||
/** Pointer to the gain map data, which is a JPEG XL naked
|
||||
* codestream. This pointer references data within the input buffer.*/
|
||||
const uint8_t* gain_map;
|
||||
} JxlGainMapBundle;
|
||||
|
||||
/**
|
||||
* Calculates the total size required to serialize the gain map bundle into a
|
||||
* binary buffer. This function accounts for all the necessary space to
|
||||
* serialize fields such as gain map metadata, color encoding, compressed ICC
|
||||
* profile data, and the gain map itself.
|
||||
*
|
||||
* @param[in] map_bundle Pointer to the JxlGainMapBundle containing all
|
||||
* necessary data to compute the size.
|
||||
* @param[out] bundle_size The size in bytes required to serialize the bundle.
|
||||
* @return Whether setting the size was successful.
|
||||
*/
|
||||
JXL_EXPORT JXL_BOOL JxlGainMapGetBundleSize(const JxlGainMapBundle* map_bundle,
|
||||
size_t* bundle_size);
|
||||
|
||||
/**
|
||||
* Serializes the gain map bundle into a preallocated buffer. The function
|
||||
* ensures that all parts of the bundle such as metadata, color encoding,
|
||||
* compressed ICC profile, and the gain map are correctly encoded into the
|
||||
* buffer. First call `JxlGainMapGetBundleSize` to get the size needed for
|
||||
* the buffer.
|
||||
*
|
||||
* @param[in] map_bundle Pointer to the `JxlGainMapBundle` to serialize.
|
||||
* @param[out] output_buffer Pointer to the buffer where the serialized data
|
||||
* will be written.
|
||||
* @param[in] output_buffer_size The size of the output buffer in bytes. Must be
|
||||
* large enough to hold the entire serialized data.
|
||||
* @param[out] bytes_written The number of bytes written to the output buffer.
|
||||
* @return Whether writing the bundle was successful.
|
||||
*/
|
||||
JXL_EXPORT JXL_BOOL JxlGainMapWriteBundle(const JxlGainMapBundle* map_bundle,
|
||||
uint8_t* output_buffer,
|
||||
size_t output_buffer_size,
|
||||
size_t* bytes_written);
|
||||
|
||||
/**
|
||||
* Deserializes a gain map bundle from a provided buffer and populates a
|
||||
* `JxlGainMapBundle` structure with the data extracted. This function assumes
|
||||
* the buffer contains a valid serialized gain map bundle. After successful
|
||||
* execution, the `JxlGainMapBundle` structure will reference three different
|
||||
* sections within the buffer:
|
||||
* - gain_map_metadata
|
||||
* - alt_icc
|
||||
* - gain_map
|
||||
* These sections will be accompanied by their respective sizes. Users must
|
||||
* ensure that the buffer remains valid as long as these pointers are in use.
|
||||
* @param[in,out] map_bundle Pointer to a preallocated `JxlGainMapBundle` where
|
||||
* the deserialized data will be stored.
|
||||
* @param[in] input_buffer Pointer to the buffer containing the serialized gain
|
||||
* map bundle data.
|
||||
* @param[in] input_buffer_size The size of the input buffer in bytes.
|
||||
* @param[out] bytes_read The number of bytes read from the input buffer.
|
||||
* @return Whether reading the bundle was successful.
|
||||
*/
|
||||
JXL_EXPORT JXL_BOOL JxlGainMapReadBundle(JxlGainMapBundle* map_bundle,
|
||||
const uint8_t* input_buffer,
|
||||
size_t input_buffer_size,
|
||||
size_t* bytes_read);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* JXL_GAIN_MAP_H_ */
|
||||
|
||||
/** @} */
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
@ -55,7 +55,8 @@ typedef struct JxlMemoryManagerStruct {
|
|||
|
||||
/** Memory allocation function. This can be NULL if and only if also the
|
||||
* free() member in this class is NULL. All dynamic memory will be allocated
|
||||
* and freed with these functions if they are not NULL. */
|
||||
* and freed with these functions if they are not NULL, otherwise with the
|
||||
* standard malloc/free. */
|
||||
jpegxl_alloc_func alloc;
|
||||
/** Free function matching the alloc() member. */
|
||||
jpegxl_free_func free;
|
||||
|
@ -63,7 +64,7 @@ typedef struct JxlMemoryManagerStruct {
|
|||
/* TODO(deymo): Add cache-aligned alloc/free functions here. */
|
||||
} JxlMemoryManager;
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -40,20 +40,25 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Return code used in the JxlParallel* functions as return value. A value
|
||||
* of 0 means success and any other value means error. The special value
|
||||
* ::JXL_PARALLEL_RET_RUNNER_ERROR can be used by the runner to indicate any
|
||||
* other error.
|
||||
* of ::JXL_PARALLEL_RET_SUCCESS means success and any other value means error.
|
||||
* The special value ::JXL_PARALLEL_RET_RUNNER_ERROR can be used by the runner
|
||||
* to indicate any other error.
|
||||
*/
|
||||
typedef int JxlParallelRetCode;
|
||||
|
||||
/**
|
||||
* General error returned by the @ref JxlParallelRunInit function to indicate
|
||||
* an error.
|
||||
* Code returned by the @ref JxlParallelRunInit function to indicate success.
|
||||
*/
|
||||
#define JXL_PARALLEL_RET_SUCCESS (0)
|
||||
|
||||
/**
|
||||
* Code returned by the @ref JxlParallelRunInit function to indicate a general
|
||||
* error.
|
||||
*/
|
||||
#define JXL_PARALLEL_RET_RUNNER_ERROR (-1)
|
||||
|
||||
|
@ -146,11 +151,11 @@ typedef JxlParallelRetCode (*JxlParallelRunner)(
|
|||
// order.
|
||||
(*func)(jpegxl_opaque, i, 0);
|
||||
}
|
||||
return 0;
|
||||
return JXL_PARALLEL_RET_SUCCESS;
|
||||
}
|
||||
*/
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
@ -68,7 +68,7 @@ JxlResizableParallelRunnerSuggestThreads(uint64_t xsize, uint64_t ysize);
|
|||
*/
|
||||
JXL_THREADS_EXPORT void JxlResizableParallelRunnerDestroy(void* runner_opaque);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
#if !(defined(__cplusplus) || defined(c_plusplus))
|
||||
#ifndef __cplusplus
|
||||
#error \
|
||||
"This a C++ only header. Use jxl/jxl_resizable_parallel_runner.h from C" \
|
||||
"sources."
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include <jxl/jxl_export.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
@ -94,7 +94,7 @@ JXL_EXPORT size_t JxlEncoderStatsGet(const JxlEncoderStats* stats,
|
|||
JXL_EXPORT void JxlEncoderStatsMerge(JxlEncoderStats* stats,
|
||||
const JxlEncoderStats* other);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
@ -62,7 +62,7 @@ JXL_THREADS_EXPORT void JxlThreadParallelRunnerDestroy(void* runner_opaque);
|
|||
*/
|
||||
JXL_THREADS_EXPORT size_t JxlThreadParallelRunnerDefaultNumWorkerThreads(void);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include <cstddef>
|
||||
#include <memory>
|
||||
|
||||
#if !(defined(__cplusplus) || defined(c_plusplus))
|
||||
#ifndef __cplusplus
|
||||
#error \
|
||||
"This a C++ only header. Use jxl/jxl_thread_parallel_runner.h from C" \
|
||||
"sources."
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
@ -145,7 +145,7 @@ typedef struct {
|
|||
*/
|
||||
typedef char JxlBoxType[4];
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
:warning: **Important Update:** Development continues at https://github.com/google/jpegli
|
||||
|
||||
|
||||
# Improved JPEG encoder and decoder implementation
|
||||
|
||||
This subdirectory contains a JPEG encoder and decoder implementation that is
|
||||
|
|
|
@ -279,8 +279,8 @@ V GammaModulation(const D d, const size_t x, const size_t y,
|
|||
// ideally -1.0, but likely optimal correction adds some entropy, so slightly
|
||||
// less than that.
|
||||
// ln(2) constant folded in because we want std::log but have FastLog2f.
|
||||
const auto kGam = Set(d, -0.15526878023684174f * 0.693147180559945f);
|
||||
return MulAdd(kGam, FastLog2f(d, overall_ratio), out_val);
|
||||
const auto kGamma = Set(d, -0.15526878023684174f * 0.693147180559945f);
|
||||
return MulAdd(kGamma, FastLog2f(d, overall_ratio), out_val);
|
||||
}
|
||||
|
||||
// Change precision in 8x8 blocks that have high frequency content.
|
||||
|
@ -478,11 +478,11 @@ void ComputePreErosion(const RowBuffer<float>& input, const size_t xsize,
|
|||
}
|
||||
if (iy % 4 == 3) {
|
||||
size_t y_out = y0_out + iy / 4;
|
||||
float* row_dout = pre_erosion->Row(y_out);
|
||||
float* row_d_out = pre_erosion->Row(y_out);
|
||||
for (size_t x = 0; x < xsize_out; x++) {
|
||||
row_dout[x] = (row_out[x * 4] + row_out[x * 4 + 1] +
|
||||
row_out[x * 4 + 2] + row_out[x * 4 + 3]) *
|
||||
0.25f;
|
||||
row_d_out[x] = (row_out[x * 4] + row_out[x * 4 + 1] +
|
||||
row_out[x * 4 + 2] + row_out[x * 4 + 3]) *
|
||||
0.25f;
|
||||
}
|
||||
pre_erosion->PadRow(y_out, xsize_out, border);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
#include "lib/jpegli/decode_internal.h"
|
||||
#include "lib/jpegli/error.h"
|
||||
#include "lib/jxl/base/status.h"
|
||||
|
||||
namespace jpegli {
|
||||
|
||||
|
@ -438,8 +437,8 @@ void FindCandidatesForCell(j_decompress_ptr cinfo, int ncomp, const 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);
|
||||
JPEGLI_CHECK(ncomp > 0);
|
||||
JPEGLI_CHECK(ncomp <= kMaxComponents);
|
||||
int num_cells = 1;
|
||||
for (int c = 0; c < ncomp; ++c) {
|
||||
num_cells *= (1 << kNumColorCellBits[c]);
|
||||
|
@ -474,7 +473,7 @@ int LookupColorIndex(j_decompress_ptr cinfo, const JSAMPLE* pixel) {
|
|||
cell_idx += (pixel[c] >> (8 - kNumColorCellBits[c])) * stride;
|
||||
stride <<= kNumColorCellBits[c];
|
||||
}
|
||||
JXL_ASSERT(cell_idx < m->candidate_lists_.size());
|
||||
JPEGLI_CHECK(cell_idx < m->candidate_lists_.size());
|
||||
int mindist = std::numeric_limits<int>::max();
|
||||
const auto& candidates = m->candidate_lists_[cell_idx];
|
||||
for (uint8_t i : candidates) {
|
||||
|
@ -489,7 +488,7 @@ int LookupColorIndex(j_decompress_ptr cinfo, const JSAMPLE* pixel) {
|
|||
}
|
||||
}
|
||||
}
|
||||
JXL_ASSERT(index < cinfo->actual_number_of_colors);
|
||||
JPEGLI_CHECK(index < cinfo->actual_number_of_colors);
|
||||
return index;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,11 +26,16 @@ using hwy::HWY_NAMESPACE::Mul;
|
|||
using hwy::HWY_NAMESPACE::MulAdd;
|
||||
using hwy::HWY_NAMESPACE::Sub;
|
||||
|
||||
void YCbCrToRGB(float* row[kMaxComponents], size_t xsize) {
|
||||
template <int kRed, int kGreen, int kBlue, int kAlpha>
|
||||
void YCbCrToExtRGB(float* row[kMaxComponents], size_t xsize) {
|
||||
const HWY_CAPPED(float, 8) df;
|
||||
float* JXL_RESTRICT row0 = row[0];
|
||||
float* JXL_RESTRICT row1 = row[1];
|
||||
float* JXL_RESTRICT row2 = row[2];
|
||||
const float* row_y = row[0];
|
||||
const float* row_cb = row[1];
|
||||
const float* row_cr = row[2];
|
||||
float* row_r = row[kRed];
|
||||
float* row_g = row[kGreen];
|
||||
float* row_b = row[kBlue];
|
||||
float* row_a = row[kAlpha];
|
||||
|
||||
// Full-range BT.601 as defined by JFIF Clause 7:
|
||||
// https://www.itu.int/rec/T-REC-T.871-201105-I/en
|
||||
|
@ -38,20 +43,48 @@ void YCbCrToRGB(float* row[kMaxComponents], size_t xsize) {
|
|||
const auto cgcb = Set(df, -0.114f * 1.772f / 0.587f);
|
||||
const auto cgcr = Set(df, -0.299f * 1.402f / 0.587f);
|
||||
const auto cbcb = Set(df, 1.772f);
|
||||
const auto alpha_opaque = Set(df, 127.0f / 255.0f);
|
||||
|
||||
for (size_t x = 0; x < xsize; x += Lanes(df)) {
|
||||
const auto y_vec = Load(df, row0 + x);
|
||||
const auto cb_vec = Load(df, row1 + x);
|
||||
const auto cr_vec = Load(df, row2 + x);
|
||||
const auto y_vec = Load(df, row_y + x);
|
||||
const auto cb_vec = Load(df, row_cb + x);
|
||||
const auto cr_vec = Load(df, row_cr + x);
|
||||
const auto r_vec = MulAdd(crcr, cr_vec, y_vec);
|
||||
const auto g_vec = MulAdd(cgcr, cr_vec, MulAdd(cgcb, cb_vec, y_vec));
|
||||
const auto b_vec = MulAdd(cbcb, cb_vec, y_vec);
|
||||
Store(r_vec, df, row0 + x);
|
||||
Store(g_vec, df, row1 + x);
|
||||
Store(b_vec, df, row2 + x);
|
||||
Store(r_vec, df, row_r + x);
|
||||
Store(g_vec, df, row_g + x);
|
||||
Store(b_vec, df, row_b + x);
|
||||
if (kAlpha >= 0) {
|
||||
Store(alpha_opaque, df, row_a + x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void YCbCrToRGB(float* row[kMaxComponents], size_t xsize) {
|
||||
YCbCrToExtRGB<0, 1, 2, -1>(row, xsize);
|
||||
}
|
||||
|
||||
void YCbCrToBGR(float* row[kMaxComponents], size_t xsize) {
|
||||
YCbCrToExtRGB<2, 1, 0, -1>(row, xsize);
|
||||
}
|
||||
|
||||
void YCbCrToRGBA(float* row[kMaxComponents], size_t xsize) {
|
||||
YCbCrToExtRGB<0, 1, 2, 3>(row, xsize);
|
||||
}
|
||||
|
||||
void YCbCrToBGRA(float* row[kMaxComponents], size_t xsize) {
|
||||
YCbCrToExtRGB<2, 1, 0, 3>(row, xsize);
|
||||
}
|
||||
|
||||
void YCbCrToARGB(float* row[kMaxComponents], size_t xsize) {
|
||||
YCbCrToExtRGB<1, 2, 3, 0>(row, xsize);
|
||||
}
|
||||
|
||||
void YCbCrToABGR(float* row[kMaxComponents], size_t xsize) {
|
||||
YCbCrToExtRGB<3, 2, 1, 0>(row, xsize);
|
||||
}
|
||||
|
||||
void YCCKToCMYK(float* row[kMaxComponents], size_t xsize) {
|
||||
const HWY_CAPPED(float, 8) df;
|
||||
float* JXL_RESTRICT row0 = row[0];
|
||||
|
@ -66,11 +99,15 @@ void YCCKToCMYK(float* row[kMaxComponents], size_t xsize) {
|
|||
}
|
||||
}
|
||||
|
||||
void RGBToYCbCr(float* row[kMaxComponents], size_t xsize) {
|
||||
template <int kRed, int kGreen, int kBlue>
|
||||
void ExtRGBToYCbCr(float* row[kMaxComponents], size_t xsize) {
|
||||
const HWY_CAPPED(float, 8) df;
|
||||
float* JXL_RESTRICT row0 = row[0];
|
||||
float* JXL_RESTRICT row1 = row[1];
|
||||
float* JXL_RESTRICT row2 = row[2];
|
||||
const float* row_r = row[kRed];
|
||||
const float* row_g = row[kGreen];
|
||||
const float* row_b = row[kBlue];
|
||||
float* row_y = row[0];
|
||||
float* row_cb = row[1];
|
||||
float* row_cr = row[2];
|
||||
// Full-range BT.601 as defined by JFIF Clause 7:
|
||||
// https://www.itu.int/rec/T-REC-T.871-201105-I/en
|
||||
const auto c128 = Set(df, 128.0f);
|
||||
|
@ -85,9 +122,9 @@ void RGBToYCbCr(float* row[kMaxComponents], size_t xsize) {
|
|||
const auto kNormB = Div(Set(df, 1.0f), (Add(kR, Add(kG, kAmpB))));
|
||||
|
||||
for (size_t x = 0; x < xsize; x += Lanes(df)) {
|
||||
const auto r = Load(df, row0 + x);
|
||||
const auto g = Load(df, row1 + x);
|
||||
const auto b = Load(df, row2 + x);
|
||||
const auto r = Load(df, row_r + x);
|
||||
const auto g = Load(df, row_g + x);
|
||||
const auto b = Load(df, row_b + x);
|
||||
const auto r_base = Mul(r, kR);
|
||||
const auto r_diff = Mul(r, kDiffR);
|
||||
const auto g_base = Mul(g, kG);
|
||||
|
@ -96,12 +133,28 @@ void RGBToYCbCr(float* row[kMaxComponents], size_t xsize) {
|
|||
const auto y_base = Add(r_base, Add(g_base, b_base));
|
||||
const auto cb_vec = MulAdd(Sub(b_diff, y_base), kNormB, c128);
|
||||
const auto cr_vec = MulAdd(Sub(r_diff, y_base), kNormR, c128);
|
||||
Store(y_base, df, row0 + x);
|
||||
Store(cb_vec, df, row1 + x);
|
||||
Store(cr_vec, df, row2 + x);
|
||||
Store(y_base, df, row_y + x);
|
||||
Store(cb_vec, df, row_cb + x);
|
||||
Store(cr_vec, df, row_cr + x);
|
||||
}
|
||||
}
|
||||
|
||||
void RGBToYCbCr(float* row[kMaxComponents], size_t xsize) {
|
||||
ExtRGBToYCbCr<0, 1, 2>(row, xsize);
|
||||
}
|
||||
|
||||
void BGRToYCbCr(float* row[kMaxComponents], size_t xsize) {
|
||||
ExtRGBToYCbCr<2, 1, 0>(row, xsize);
|
||||
}
|
||||
|
||||
void ARGBToYCbCr(float* row[kMaxComponents], size_t xsize) {
|
||||
ExtRGBToYCbCr<1, 2, 3>(row, xsize);
|
||||
}
|
||||
|
||||
void ABGRToYCbCr(float* row[kMaxComponents], size_t xsize) {
|
||||
ExtRGBToYCbCr<3, 2, 1>(row, xsize);
|
||||
}
|
||||
|
||||
void CMYKToYCCK(float* row[kMaxComponents], size_t xsize) {
|
||||
const HWY_CAPPED(float, 8) df;
|
||||
float* JXL_RESTRICT row0 = row[0];
|
||||
|
@ -127,7 +180,15 @@ namespace jpegli {
|
|||
HWY_EXPORT(CMYKToYCCK);
|
||||
HWY_EXPORT(YCCKToCMYK);
|
||||
HWY_EXPORT(YCbCrToRGB);
|
||||
HWY_EXPORT(YCbCrToBGR);
|
||||
HWY_EXPORT(YCbCrToRGBA);
|
||||
HWY_EXPORT(YCbCrToBGRA);
|
||||
HWY_EXPORT(YCbCrToARGB);
|
||||
HWY_EXPORT(YCbCrToABGR);
|
||||
HWY_EXPORT(RGBToYCbCr);
|
||||
HWY_EXPORT(BGRToYCbCr);
|
||||
HWY_EXPORT(ARGBToYCbCr);
|
||||
HWY_EXPORT(ABGRToYCbCr);
|
||||
|
||||
bool CheckColorSpaceComponents(int num_components, J_COLOR_SPACE colorspace) {
|
||||
switch (colorspace) {
|
||||
|
@ -135,19 +196,25 @@ bool CheckColorSpaceComponents(int num_components, J_COLOR_SPACE colorspace) {
|
|||
return num_components == 1;
|
||||
case JCS_RGB:
|
||||
case JCS_YCbCr:
|
||||
#ifdef JCS_EXTENSIONS
|
||||
case JCS_EXT_RGB:
|
||||
case JCS_EXT_BGR:
|
||||
#endif
|
||||
return num_components == 3;
|
||||
case JCS_CMYK:
|
||||
case JCS_YCCK:
|
||||
#ifdef JCS_EXTENSIONS
|
||||
case JCS_EXT_RGBX:
|
||||
case JCS_EXT_BGRX:
|
||||
case JCS_EXT_XBGR:
|
||||
case JCS_EXT_XRGB:
|
||||
#endif
|
||||
#ifdef JCS_ALPHA_EXTENSIONS
|
||||
case JCS_EXT_RGBA:
|
||||
case JCS_EXT_BGRA:
|
||||
case JCS_EXT_ABGR:
|
||||
case JCS_EXT_ARGB:
|
||||
#endif
|
||||
return num_components == 4;
|
||||
default:
|
||||
// Unrecognized colorspaces can have any number of channels, since no
|
||||
|
@ -158,16 +225,73 @@ bool CheckColorSpaceComponents(int num_components, J_COLOR_SPACE colorspace) {
|
|||
|
||||
void NullTransform(float* row[kMaxComponents], size_t len) {}
|
||||
|
||||
void FillAlpha(float* row, size_t len) {
|
||||
static const float kAlpha = 127.0f / 255.0f;
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
row[i] = kAlpha;
|
||||
}
|
||||
}
|
||||
|
||||
// Works for BGR as well.
|
||||
void GrayscaleToRGB(float* row[kMaxComponents], size_t len) {
|
||||
memcpy(row[1], row[0], len * sizeof(row[1][0]));
|
||||
memcpy(row[2], row[0], len * sizeof(row[2][0]));
|
||||
}
|
||||
|
||||
// Works for BGRA as well.
|
||||
void GrayscaleToRGBA(float* row[kMaxComponents], size_t len) {
|
||||
memcpy(row[1], row[0], len * sizeof(row[1][0]));
|
||||
memcpy(row[2], row[0], len * sizeof(row[2][0]));
|
||||
FillAlpha(row[3], len);
|
||||
}
|
||||
|
||||
// Works for ABGR as well.
|
||||
void GrayscaleToARGB(float* row[kMaxComponents], size_t len) {
|
||||
memcpy(row[1], row[0], len * sizeof(row[1][0]));
|
||||
memcpy(row[2], row[0], len * sizeof(row[2][0]));
|
||||
memcpy(row[3], row[0], len * sizeof(row[1][0]));
|
||||
FillAlpha(row[0], len);
|
||||
}
|
||||
|
||||
void GrayscaleToYCbCr(float* row[kMaxComponents], size_t len) {
|
||||
memset(row[1], 0, len * sizeof(row[1][0]));
|
||||
memset(row[2], 0, len * sizeof(row[2][0]));
|
||||
}
|
||||
|
||||
void RGBToBGR(float* row[kMaxComponents], size_t len) {
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
std::swap(row[0][i], row[2][i]);
|
||||
}
|
||||
}
|
||||
|
||||
void RGBToRGBA(float* row[kMaxComponents], size_t len) {
|
||||
FillAlpha(row[3], len);
|
||||
}
|
||||
|
||||
void RGBToBGRA(float* row[kMaxComponents], size_t len) {
|
||||
static const float kAlpha = 127.0f / 255.0f;
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
std::swap(row[0][i], row[2][i]);
|
||||
row[3][i] = kAlpha;
|
||||
}
|
||||
}
|
||||
|
||||
void RGBToARGB(float* row[kMaxComponents], size_t len) {
|
||||
memcpy(row[3], row[2], len * sizeof(row[1][0]));
|
||||
memcpy(row[2], row[1], len * sizeof(row[2][0]));
|
||||
memcpy(row[1], row[0], len * sizeof(row[1][0]));
|
||||
FillAlpha(row[0], len);
|
||||
}
|
||||
|
||||
void RGBToABGR(float* row[kMaxComponents], size_t len) {
|
||||
static const float kAlpha = 127.0f / 255.0f;
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
std::swap(row[1][i], row[2][i]);
|
||||
row[3][i] = row[0][i];
|
||||
row[0][i] = kAlpha;
|
||||
}
|
||||
}
|
||||
|
||||
void ChooseColorTransform(j_compress_ptr cinfo) {
|
||||
jpeg_comp_master* m = cinfo->master;
|
||||
if (!CheckColorSpaceComponents(cinfo->input_components,
|
||||
|
@ -220,6 +344,43 @@ void ChooseColorTransform(j_compress_ptr cinfo) {
|
|||
}
|
||||
}
|
||||
|
||||
if (cinfo->jpeg_color_space == JCS_GRAYSCALE ||
|
||||
cinfo->jpeg_color_space == JCS_YCbCr) {
|
||||
switch (cinfo->in_color_space) {
|
||||
#ifdef JCS_EXTENSIONS
|
||||
case JCS_EXT_RGB:
|
||||
case JCS_EXT_RGBX:
|
||||
m->color_transform = HWY_DYNAMIC_DISPATCH(RGBToYCbCr);
|
||||
break;
|
||||
case JCS_EXT_BGR:
|
||||
case JCS_EXT_BGRX:
|
||||
m->color_transform = HWY_DYNAMIC_DISPATCH(BGRToYCbCr);
|
||||
break;
|
||||
case JCS_EXT_XRGB:
|
||||
m->color_transform = HWY_DYNAMIC_DISPATCH(ARGBToYCbCr);
|
||||
break;
|
||||
case JCS_EXT_XBGR:
|
||||
m->color_transform = HWY_DYNAMIC_DISPATCH(ABGRToYCbCr);
|
||||
break;
|
||||
#endif
|
||||
#ifdef JCS_ALPHA_EXTENSIONS
|
||||
case JCS_EXT_RGBA:
|
||||
m->color_transform = HWY_DYNAMIC_DISPATCH(RGBToYCbCr);
|
||||
break;
|
||||
case JCS_EXT_BGRA:
|
||||
m->color_transform = HWY_DYNAMIC_DISPATCH(BGRToYCbCr);
|
||||
break;
|
||||
case JCS_EXT_ARGB:
|
||||
m->color_transform = HWY_DYNAMIC_DISPATCH(ARGBToYCbCr);
|
||||
break;
|
||||
case JCS_EXT_ABGR:
|
||||
m->color_transform = HWY_DYNAMIC_DISPATCH(ABGRToYCbCr);
|
||||
break;
|
||||
#endif
|
||||
default:; // Nothing to do.
|
||||
}
|
||||
}
|
||||
|
||||
if (m->color_transform == nullptr) {
|
||||
// TODO(szabadka) Support more color transforms.
|
||||
JPEGLI_ERROR("Unsupported color transform %d -> %d", cinfo->in_color_space,
|
||||
|
@ -251,18 +412,123 @@ void ChooseColorTransform(j_decompress_ptr cinfo) {
|
|||
|
||||
m->color_transform = nullptr;
|
||||
if (cinfo->jpeg_color_space == JCS_GRAYSCALE) {
|
||||
if (cinfo->out_color_space == JCS_RGB) {
|
||||
m->color_transform = GrayscaleToRGB;
|
||||
switch (cinfo->out_color_space) {
|
||||
case JCS_RGB:
|
||||
m->color_transform = GrayscaleToRGB;
|
||||
break;
|
||||
#ifdef JCS_EXTENSIONS
|
||||
case JCS_EXT_RGB:
|
||||
case JCS_EXT_BGR:
|
||||
m->color_transform = GrayscaleToRGB;
|
||||
break;
|
||||
case JCS_EXT_RGBX:
|
||||
case JCS_EXT_BGRX:
|
||||
m->color_transform = GrayscaleToRGBA;
|
||||
break;
|
||||
case JCS_EXT_XRGB:
|
||||
case JCS_EXT_XBGR:
|
||||
m->color_transform = GrayscaleToARGB;
|
||||
break;
|
||||
#endif
|
||||
#ifdef JCS_ALPHA_EXTENSIONS
|
||||
case JCS_EXT_RGBA:
|
||||
case JCS_EXT_BGRA:
|
||||
m->color_transform = GrayscaleToRGBA;
|
||||
break;
|
||||
case JCS_EXT_ARGB:
|
||||
case JCS_EXT_ABGR:
|
||||
m->color_transform = GrayscaleToARGB;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
m->color_transform = nullptr;
|
||||
}
|
||||
} else if (cinfo->jpeg_color_space == JCS_RGB) {
|
||||
if (cinfo->out_color_space == JCS_GRAYSCALE) {
|
||||
m->color_transform = HWY_DYNAMIC_DISPATCH(RGBToYCbCr);
|
||||
switch (cinfo->out_color_space) {
|
||||
case JCS_GRAYSCALE:
|
||||
m->color_transform = HWY_DYNAMIC_DISPATCH(RGBToYCbCr);
|
||||
break;
|
||||
#ifdef JCS_EXTENSIONS
|
||||
case JCS_EXT_RGB:
|
||||
m->color_transform = NullTransform;
|
||||
break;
|
||||
case JCS_EXT_BGR:
|
||||
m->color_transform = RGBToBGR;
|
||||
break;
|
||||
case JCS_EXT_RGBX:
|
||||
m->color_transform = RGBToRGBA;
|
||||
break;
|
||||
case JCS_EXT_BGRX:
|
||||
m->color_transform = RGBToBGRA;
|
||||
break;
|
||||
case JCS_EXT_XRGB:
|
||||
m->color_transform = RGBToARGB;
|
||||
break;
|
||||
case JCS_EXT_XBGR:
|
||||
m->color_transform = RGBToABGR;
|
||||
break;
|
||||
#endif
|
||||
#ifdef JCS_ALPHA_EXTENSIONS
|
||||
case JCS_EXT_RGBA:
|
||||
m->color_transform = RGBToRGBA;
|
||||
break;
|
||||
case JCS_EXT_BGRA:
|
||||
m->color_transform = RGBToBGRA;
|
||||
break;
|
||||
case JCS_EXT_ARGB:
|
||||
m->color_transform = RGBToARGB;
|
||||
break;
|
||||
case JCS_EXT_ABGR:
|
||||
m->color_transform = RGBToABGR;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
m->color_transform = nullptr;
|
||||
}
|
||||
} else if (cinfo->jpeg_color_space == JCS_YCbCr) {
|
||||
if (cinfo->out_color_space == JCS_RGB) {
|
||||
m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToRGB);
|
||||
} else if (cinfo->out_color_space == JCS_GRAYSCALE) {
|
||||
m->color_transform = NullTransform;
|
||||
switch (cinfo->out_color_space) {
|
||||
case JCS_GRAYSCALE:
|
||||
m->color_transform = NullTransform;
|
||||
break;
|
||||
case JCS_RGB:
|
||||
m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToRGB);
|
||||
break;
|
||||
#ifdef JCS_EXTENSIONS
|
||||
case JCS_EXT_RGB:
|
||||
m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToRGB);
|
||||
break;
|
||||
case JCS_EXT_BGR:
|
||||
m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToBGR);
|
||||
break;
|
||||
case JCS_EXT_RGBX:
|
||||
m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToRGBA);
|
||||
break;
|
||||
case JCS_EXT_BGRX:
|
||||
m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToBGRA);
|
||||
break;
|
||||
case JCS_EXT_XRGB:
|
||||
m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToARGB);
|
||||
break;
|
||||
case JCS_EXT_XBGR:
|
||||
m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToABGR);
|
||||
break;
|
||||
#endif
|
||||
#ifdef JCS_ALPHA_EXTENSIONS
|
||||
case JCS_EXT_RGBA:
|
||||
m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToRGBA);
|
||||
break;
|
||||
case JCS_EXT_BGRA:
|
||||
m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToBGRA);
|
||||
break;
|
||||
case JCS_EXT_ARGB:
|
||||
m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToARGB);
|
||||
break;
|
||||
case JCS_EXT_ABGR:
|
||||
m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToABGR);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
m->color_transform = nullptr;
|
||||
}
|
||||
} else if (cinfo->jpeg_color_space == JCS_YCCK) {
|
||||
if (cinfo->out_color_space == JCS_CMYK) {
|
||||
|
|
|
@ -20,14 +20,9 @@
|
|||
#ifndef LIB_JPEGLI_COMMON_H_
|
||||
#define LIB_JPEGLI_COMMON_H_
|
||||
|
||||
/* clang-format off */
|
||||
#include <stdio.h>
|
||||
#include <jpeglib.h>
|
||||
/* clang-format on */
|
||||
#include "lib/jxl/base/include_jpeglib.h" // NOLINT
|
||||
|
||||
#include "lib/jpegli/types.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
@ -41,7 +36,7 @@ JQUANT_TBL* jpegli_alloc_quant_table(j_common_ptr cinfo);
|
|||
|
||||
JHUFF_TBL* jpegli_alloc_huff_table(j_common_ptr cinfo);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
|
|
|
@ -6,17 +6,33 @@
|
|||
#ifndef LIB_JPEGLI_COMMON_INTERNAL_H_
|
||||
#define LIB_JPEGLI_COMMON_INTERNAL_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
// Suppress any -Wdeprecated-declarations warning that might be emitted by
|
||||
// GCC or Clang by std::stable_sort in C++17 or later mode
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC push_options
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC pop_options
|
||||
#endif
|
||||
|
||||
#include <hwy/aligned_allocator.h>
|
||||
|
||||
#include "lib/jpegli/memory_manager.h"
|
||||
#include "lib/jpegli/simd.h"
|
||||
#include "lib/jxl/base/compiler_specific.h" // for ssize_t
|
||||
#include "lib/jxl/base/status.h" // for JXL_CHECK
|
||||
|
||||
namespace jpegli {
|
||||
|
||||
|
@ -94,8 +110,8 @@ class RowBuffer {
|
|||
public:
|
||||
template <typename CInfoType>
|
||||
void Allocate(CInfoType cinfo, size_t num_rows, size_t rowsize) {
|
||||
static_assert(sizeof(T) == 4);
|
||||
size_t vec_size = std::max(VectorSize(), sizeof(T));
|
||||
JXL_CHECK(vec_size % sizeof(T) == 0);
|
||||
size_t alignment = std::max<size_t>(HWY_ALIGNMENT, vec_size);
|
||||
size_t min_memstride = alignment + rowsize * sizeof(T) + vec_size;
|
||||
size_t memstride = RoundUpTo(min_memstride, alignment);
|
||||
|
|
|
@ -35,24 +35,24 @@ using D = HWY_FULL(float);
|
|||
using DI = HWY_FULL(int32_t);
|
||||
|
||||
template <size_t N>
|
||||
void AddReverse(const float* JXL_RESTRICT ain1, const float* JXL_RESTRICT ain2,
|
||||
float* JXL_RESTRICT aout) {
|
||||
void AddReverse(const float* JXL_RESTRICT a_in1,
|
||||
const float* JXL_RESTRICT a_in2, float* JXL_RESTRICT a_out) {
|
||||
HWY_CAPPED(float, 8) d8;
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
auto in1 = Load(d8, ain1 + i * 8);
|
||||
auto in2 = Load(d8, ain2 + (N - i - 1) * 8);
|
||||
Store(Add(in1, in2), d8, aout + i * 8);
|
||||
auto in1 = Load(d8, a_in1 + i * 8);
|
||||
auto in2 = Load(d8, a_in2 + (N - i - 1) * 8);
|
||||
Store(Add(in1, in2), d8, a_out + i * 8);
|
||||
}
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
void SubReverse(const float* JXL_RESTRICT ain1, const float* JXL_RESTRICT ain2,
|
||||
float* JXL_RESTRICT aout) {
|
||||
void SubReverse(const float* JXL_RESTRICT a_in1,
|
||||
const float* JXL_RESTRICT a_in2, float* JXL_RESTRICT a_out) {
|
||||
HWY_CAPPED(float, 8) d8;
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
auto in1 = Load(d8, ain1 + i * 8);
|
||||
auto in2 = Load(d8, ain2 + (N - i - 1) * 8);
|
||||
Store(Sub(in1, in2), d8, aout + i * 8);
|
||||
auto in1 = Load(d8, a_in1 + i * 8);
|
||||
auto in2 = Load(d8, a_in2 + (N - i - 1) * 8);
|
||||
Store(Sub(in1, in2), d8, a_out + i * 8);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,15 +73,15 @@ void B(float* JXL_RESTRICT coeff) {
|
|||
|
||||
// Ideally optimized away by compiler (except the multiply).
|
||||
template <size_t N>
|
||||
void InverseEvenOdd(const float* JXL_RESTRICT ain, float* JXL_RESTRICT aout) {
|
||||
void InverseEvenOdd(const float* JXL_RESTRICT a_in, float* JXL_RESTRICT a_out) {
|
||||
HWY_CAPPED(float, 8) d8;
|
||||
for (size_t i = 0; i < N / 2; i++) {
|
||||
auto in1 = Load(d8, ain + i * 8);
|
||||
Store(in1, d8, aout + 2 * i * 8);
|
||||
auto in1 = Load(d8, a_in + i * 8);
|
||||
Store(in1, d8, a_out + 2 * i * 8);
|
||||
}
|
||||
for (size_t i = N / 2; i < N; i++) {
|
||||
auto in1 = Load(d8, ain + i * 8);
|
||||
Store(in1, d8, aout + (2 * (i - N / 2) + 1) * 8);
|
||||
auto in1 = Load(d8, a_in + i * 8);
|
||||
Store(in1, d8, a_out + (2 * (i - N / 2) + 1) * 8);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,8 +109,10 @@ struct WcMultipliers<8> {
|
|||
};
|
||||
};
|
||||
|
||||
#if JXL_CXX_LANG < JXL_CXX_17
|
||||
constexpr float WcMultipliers<4>::kMultipliers[];
|
||||
constexpr float WcMultipliers<8>::kMultipliers[];
|
||||
#endif
|
||||
|
||||
// Invoked on full vector.
|
||||
template <size_t N>
|
||||
|
|
|
@ -54,6 +54,7 @@ void InitializeImage(j_decompress_ptr cinfo) {
|
|||
m->found_soi_ = false;
|
||||
m->found_dri_ = false;
|
||||
m->found_sof_ = false;
|
||||
m->found_sos_ = false;
|
||||
m->found_eoi_ = false;
|
||||
m->icc_index_ = 0;
|
||||
m->icc_total_ = 0;
|
||||
|
@ -177,7 +178,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;
|
||||
|
@ -225,7 +226,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);
|
||||
}
|
||||
|
@ -235,7 +236,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);
|
||||
}
|
||||
|
@ -243,10 +244,14 @@ void PrepareForScan(j_decompress_ptr cinfo) {
|
|||
// Copy quantization tables into comp_info.
|
||||
for (int i = 0; i < cinfo->comps_in_scan; ++i) {
|
||||
jpeg_component_info* comp = cinfo->cur_comp_info[i];
|
||||
int quant_tbl_idx = comp->quant_tbl_no;
|
||||
JQUANT_TBL* quant_table = cinfo->quant_tbl_ptrs[quant_tbl_idx];
|
||||
if (!quant_table) {
|
||||
JPEGLI_ERROR("Quantization table with index %d not found", quant_tbl_idx);
|
||||
}
|
||||
if (comp->quant_table == nullptr) {
|
||||
comp->quant_table = Allocate<JQUANT_TBL>(cinfo, 1, JPOOL_IMAGE);
|
||||
memcpy(comp->quant_table, cinfo->quant_tbl_ptrs[comp->quant_tbl_no],
|
||||
sizeof(JQUANT_TBL));
|
||||
memcpy(comp->quant_table, quant_table, sizeof(JQUANT_TBL));
|
||||
}
|
||||
}
|
||||
if (cinfo->comps_in_scan == 1) {
|
||||
|
@ -723,16 +728,36 @@ void jpegli_calc_output_dimensions(j_decompress_ptr cinfo) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (cinfo->out_color_space == JCS_GRAYSCALE) {
|
||||
cinfo->out_color_components = 1;
|
||||
} else if (cinfo->out_color_space == JCS_RGB ||
|
||||
cinfo->out_color_space == JCS_YCbCr) {
|
||||
cinfo->out_color_components = 3;
|
||||
} else if (cinfo->out_color_space == JCS_CMYK ||
|
||||
cinfo->out_color_space == JCS_YCCK) {
|
||||
cinfo->out_color_components = 4;
|
||||
} else {
|
||||
cinfo->out_color_components = cinfo->num_components;
|
||||
switch (cinfo->out_color_space) {
|
||||
case JCS_GRAYSCALE:
|
||||
cinfo->out_color_components = 1;
|
||||
break;
|
||||
case JCS_RGB:
|
||||
case JCS_YCbCr:
|
||||
#ifdef JCS_EXTENSIONS
|
||||
case JCS_EXT_RGB:
|
||||
case JCS_EXT_BGR:
|
||||
#endif
|
||||
cinfo->out_color_components = 3;
|
||||
break;
|
||||
case JCS_CMYK:
|
||||
case JCS_YCCK:
|
||||
#ifdef JCS_EXTENSIONS
|
||||
case JCS_EXT_RGBX:
|
||||
case JCS_EXT_BGRX:
|
||||
case JCS_EXT_XBGR:
|
||||
case JCS_EXT_XRGB:
|
||||
#endif
|
||||
#ifdef JCS_ALPHA_EXTENSIONS
|
||||
case JCS_EXT_RGBA:
|
||||
case JCS_EXT_BGRA:
|
||||
case JCS_EXT_ABGR:
|
||||
case JCS_EXT_ARGB:
|
||||
#endif
|
||||
cinfo->out_color_components = 4;
|
||||
break;
|
||||
default:
|
||||
cinfo->out_color_components = cinfo->num_components;
|
||||
}
|
||||
cinfo->output_components =
|
||||
cinfo->quantize_colors ? 1 : cinfo->out_color_components;
|
||||
|
@ -740,8 +765,11 @@ 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 TO_JXL_BOOL(cinfo->master->is_multiscan_);
|
||||
}
|
||||
|
|
|
@ -21,8 +21,9 @@
|
|||
#define LIB_JPEGLI_DECODE_H_
|
||||
|
||||
#include "lib/jpegli/common.h"
|
||||
#include "lib/jpegli/types.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
@ -36,7 +37,7 @@ void jpegli_CreateDecompress(j_decompress_ptr cinfo, int version,
|
|||
void jpegli_stdio_src(j_decompress_ptr cinfo, FILE *infile);
|
||||
|
||||
void jpegli_mem_src(j_decompress_ptr cinfo, const unsigned char *inbuffer,
|
||||
unsigned long insize);
|
||||
unsigned long insize /* NOLINT */);
|
||||
|
||||
int jpegli_read_header(j_decompress_ptr cinfo, boolean require_image);
|
||||
|
||||
|
@ -99,7 +100,7 @@ void jpegli_new_colormap(j_decompress_ptr cinfo);
|
|||
void jpegli_set_output_format(j_decompress_ptr cinfo, JpegliDataType data_type,
|
||||
JpegliEndianness endianness);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
|
|
|
@ -3,17 +3,27 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include <cmath>
|
||||
#include <jxl/types.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "lib/jpegli/decode.h"
|
||||
#include "lib/jpegli/encode.h"
|
||||
#include "lib/jpegli/libjpeg_test_util.h"
|
||||
#include "lib/jpegli/test_params.h"
|
||||
#include "lib/jpegli/test_utils.h"
|
||||
#include "lib/jpegli/testing.h"
|
||||
#include "lib/jxl/base/byte_order.h"
|
||||
#include "lib/jpegli/types.h"
|
||||
#include "lib/jxl/base/status.h"
|
||||
#include "lib/jxl/sanitizers.h"
|
||||
|
||||
namespace jpegli {
|
||||
namespace {
|
||||
|
@ -78,7 +88,8 @@ class SourceManager {
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
|
||||
static void skip_input_data(j_decompress_ptr cinfo,
|
||||
long num_bytes /* NOLINT */) {
|
||||
auto* src = reinterpret_cast<SourceManager*>(cinfo->src);
|
||||
if (num_bytes <= 0) {
|
||||
return;
|
||||
|
@ -219,13 +230,14 @@ struct TestConfig {
|
|||
float max_diff = 35.0f;
|
||||
};
|
||||
|
||||
std::vector<uint8_t> GetTestJpegData(TestConfig& config) {
|
||||
jxl::StatusOr<std::vector<uint8_t>> GetTestJpegData(TestConfig& config) {
|
||||
std::vector<uint8_t> compressed;
|
||||
if (!config.fn.empty()) {
|
||||
compressed = ReadTestData(config.fn);
|
||||
JXL_ASSIGN_OR_RETURN(compressed, ReadTestData(config.fn));
|
||||
} else {
|
||||
GeneratePixels(&config.input);
|
||||
JXL_CHECK(EncodeWithJpegli(config.input, config.jparams, &compressed));
|
||||
JXL_RETURN_IF_ERROR(
|
||||
EncodeWithJpegli(config.input, config.jparams, &compressed));
|
||||
}
|
||||
if (config.dparams.size_factor < 1.0f) {
|
||||
compressed.resize(compressed.size() * config.dparams.size_factor);
|
||||
|
@ -256,8 +268,8 @@ void TestAPINonBuffered(const CompressParams& jparams,
|
|||
if (!jparams.icc.empty()) {
|
||||
uint8_t* icc_data = nullptr;
|
||||
unsigned int icc_len;
|
||||
JXL_CHECK(jpegli_read_icc_profile(cinfo, &icc_data, &icc_len));
|
||||
JXL_CHECK(icc_data);
|
||||
ASSERT_TRUE(jpegli_read_icc_profile(cinfo, &icc_data, &icc_len));
|
||||
ASSERT_TRUE(icc_data);
|
||||
EXPECT_EQ(0, memcmp(jparams.icc.data(), icc_data, icc_len));
|
||||
free(icc_data);
|
||||
}
|
||||
|
@ -278,7 +290,7 @@ void TestAPINonBuffered(const CompressParams& jparams,
|
|||
}
|
||||
if (dparams.output_mode == COEFFICIENTS) {
|
||||
jvirt_barray_ptr* coef_arrays = jpegli_read_coefficients(cinfo);
|
||||
JXL_CHECK(coef_arrays != nullptr);
|
||||
ASSERT_TRUE(coef_arrays != nullptr);
|
||||
CopyCoefficients(cinfo, coef_arrays, output);
|
||||
} else {
|
||||
jpegli_start_decompress(cinfo);
|
||||
|
@ -297,10 +309,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 = FROM_JXL_BOOL(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)) {
|
||||
|
@ -330,7 +342,7 @@ void TestAPIBuffered(const CompressParams& jparams,
|
|||
++sos_marker_cnt; // finish output reads the next SOS marker or EOI
|
||||
if (dparams.output_mode == COEFFICIENTS) {
|
||||
jvirt_barray_ptr* coef_arrays = jpegli_read_coefficients(cinfo);
|
||||
JXL_CHECK(coef_arrays != nullptr);
|
||||
ASSERT_TRUE(coef_arrays != nullptr);
|
||||
CopyCoefficients(cinfo, coef_arrays, &output_progression->back());
|
||||
}
|
||||
}
|
||||
|
@ -366,7 +378,8 @@ TEST(DecodeAPITest, ReuseCinfo) {
|
|||
"Generating input with %dx%d chroma subsampling "
|
||||
"progressive level %d\n",
|
||||
h_samp, v_samp, progr);
|
||||
JXL_CHECK(EncodeWithJpegli(input, jparams, &compressed));
|
||||
JPEGLI_TEST_ENSURE_TRUE(
|
||||
EncodeWithJpegli(input, jparams, &compressed));
|
||||
for (JpegIOMode output_mode : {PIXELS, RAW_DATA, COEFFICIENTS}) {
|
||||
for (bool crop : {true, false}) {
|
||||
if (crop && output_mode != PIXELS) continue;
|
||||
|
@ -408,8 +421,8 @@ TEST(DecodeAPITest, ReuseCinfo) {
|
|||
output_progression.clear();
|
||||
src.Reset();
|
||||
TestAPIBuffered(jparams, dparams, &cinfo, &output_progression);
|
||||
JXL_CHECK(output_progression.size() ==
|
||||
expected_output_progression.size());
|
||||
JPEGLI_TEST_ENSURE_TRUE(output_progression.size() ==
|
||||
expected_output_progression.size());
|
||||
for (size_t i = 0; i < output_progression.size(); ++i) {
|
||||
const TestImage& output = output_progression[i];
|
||||
const TestImage& expected = expected_output_progression[i];
|
||||
|
@ -447,7 +460,7 @@ std::vector<TestConfig> GenerateBasicConfigs() {
|
|||
TEST(DecodeAPITest, ReuseCinfoSameMemSource) {
|
||||
std::vector<TestConfig> all_configs = GenerateBasicConfigs();
|
||||
uint8_t* buffer = nullptr;
|
||||
unsigned long buffer_size = 0;
|
||||
unsigned long buffer_size = 0; // NOLINT
|
||||
{
|
||||
jpeg_compress_struct cinfo;
|
||||
const auto try_catch_block = [&]() -> bool {
|
||||
|
@ -487,7 +500,7 @@ TEST(DecodeAPITest, ReuseCinfoSameMemSource) {
|
|||
TEST(DecodeAPITest, ReuseCinfoSameStdSource) {
|
||||
std::vector<TestConfig> all_configs = GenerateBasicConfigs();
|
||||
FILE* tmpf = tmpfile();
|
||||
JXL_CHECK(tmpf);
|
||||
ASSERT_TRUE(tmpf);
|
||||
{
|
||||
jpeg_compress_struct cinfo;
|
||||
const auto try_catch_block = [&]() -> bool {
|
||||
|
@ -502,7 +515,7 @@ TEST(DecodeAPITest, ReuseCinfoSameStdSource) {
|
|||
EXPECT_TRUE(try_catch_block());
|
||||
jpegli_destroy_compress(&cinfo);
|
||||
}
|
||||
rewind(tmpf);
|
||||
fseek(tmpf, 0, SEEK_SET);
|
||||
std::vector<TestImage> all_outputs(all_configs.size());
|
||||
{
|
||||
jpeg_decompress_struct cinfo;
|
||||
|
@ -527,9 +540,9 @@ TEST(DecodeAPITest, ReuseCinfoSameStdSource) {
|
|||
|
||||
TEST(DecodeAPITest, AbbreviatedStreams) {
|
||||
uint8_t* table_stream = nullptr;
|
||||
unsigned long table_stream_size = 0;
|
||||
unsigned long table_stream_size = 0; // NOLINT
|
||||
uint8_t* data_stream = nullptr;
|
||||
unsigned long data_stream_size = 0;
|
||||
unsigned long data_stream_size = 0; // NOLINT
|
||||
{
|
||||
jpeg_compress_struct cinfo;
|
||||
const auto try_catch_block = [&]() -> bool {
|
||||
|
@ -591,7 +604,8 @@ TEST_P(DecodeAPITestParam, TestAPI) {
|
|||
TestConfig config = GetParam();
|
||||
const DecompressParams& dparams = config.dparams;
|
||||
if (dparams.skip_scans) return;
|
||||
const std::vector<uint8_t> compressed = GetTestJpegData(config);
|
||||
JXL_ASSIGN_OR_QUIT(std::vector<uint8_t> compressed, GetTestJpegData(config),
|
||||
"Failed to create test data");
|
||||
SourceManager src(compressed.data(), compressed.size(), dparams.chunk_size);
|
||||
|
||||
TestImage output1;
|
||||
|
@ -625,7 +639,8 @@ class DecodeAPITestParamBuffered : public ::testing::TestWithParam<TestConfig> {
|
|||
TEST_P(DecodeAPITestParamBuffered, TestAPI) {
|
||||
TestConfig config = GetParam();
|
||||
const DecompressParams& dparams = config.dparams;
|
||||
const std::vector<uint8_t> compressed = GetTestJpegData(config);
|
||||
JXL_ASSIGN_OR_QUIT(std::vector<uint8_t> compressed, GetTestJpegData(config),
|
||||
"Failed to create test data.");
|
||||
SourceManager src(compressed.data(), compressed.size(), dparams.chunk_size);
|
||||
|
||||
std::vector<TestImage> output_progression1;
|
||||
|
@ -893,7 +908,9 @@ std::vector<TestConfig> GenerateTests(bool buffered) {
|
|||
all_tests.push_back(config);
|
||||
}
|
||||
// Tests for color transforms.
|
||||
for (J_COLOR_SPACE out_color_space : {JCS_RGB, JCS_GRAYSCALE}) {
|
||||
for (J_COLOR_SPACE out_color_space :
|
||||
{JCS_RGB, JCS_GRAYSCALE, JCS_EXT_RGB, JCS_EXT_BGR, JCS_EXT_RGBA,
|
||||
JCS_EXT_BGRA, JCS_EXT_ARGB, JCS_EXT_ABGR}) {
|
||||
TestConfig config;
|
||||
config.input.xsize = config.input.ysize = 256;
|
||||
config.input.color_space = JCS_GRAYSCALE;
|
||||
|
@ -902,7 +919,9 @@ std::vector<TestConfig> GenerateTests(bool buffered) {
|
|||
all_tests.push_back(config);
|
||||
}
|
||||
for (J_COLOR_SPACE jpeg_color_space : {JCS_RGB, JCS_YCbCr}) {
|
||||
for (J_COLOR_SPACE out_color_space : {JCS_RGB, JCS_YCbCr, JCS_GRAYSCALE}) {
|
||||
for (J_COLOR_SPACE out_color_space :
|
||||
{JCS_RGB, JCS_YCbCr, JCS_GRAYSCALE, JCS_EXT_RGB, JCS_EXT_BGR,
|
||||
JCS_EXT_RGBA, JCS_EXT_BGRA, JCS_EXT_ARGB, JCS_EXT_ABGR}) {
|
||||
if (jpeg_color_space == JCS_RGB && out_color_space == JCS_YCbCr) continue;
|
||||
TestConfig config;
|
||||
config.input.xsize = config.input.ysize = 256;
|
||||
|
@ -1107,6 +1126,8 @@ std::vector<TestConfig> GenerateTests(bool buffered) {
|
|||
TestConfig config;
|
||||
config.input.xsize = xsize;
|
||||
config.input.ysize = ysize;
|
||||
config.jparams.h_sampling = {1, 1, 1};
|
||||
config.jparams.v_sampling = {1, 1, 1};
|
||||
all_tests.push_back(config);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,14 +6,15 @@
|
|||
#ifndef LIB_JPEGLI_DECODE_INTERNAL_H_
|
||||
#define LIB_JPEGLI_DECODE_INTERNAL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "lib/jpegli/common.h"
|
||||
#include "lib/jpegli/common_internal.h"
|
||||
#include "lib/jpegli/huffman.h"
|
||||
#include "lib/jpegli/types.h"
|
||||
|
||||
namespace jpegli {
|
||||
|
||||
|
@ -45,19 +46,26 @@ 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.
|
||||
//
|
||||
bool found_soi_;
|
||||
bool found_dri_;
|
||||
bool found_sof_;
|
||||
bool found_sos_;
|
||||
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,16 +74,13 @@ 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_;
|
||||
int h_factor[jpegli::kMaxComponents];
|
||||
int v_factor[jpegli::kMaxComponents];
|
||||
|
||||
// Initialized at strat of frame.
|
||||
// Initialized at start of frame.
|
||||
uint16_t scan_progression_[jpegli::kMaxComponents][DCTSIZE2];
|
||||
|
||||
//
|
||||
|
@ -96,9 +101,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 +134,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 +151,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_
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче