diff --git a/media/libjxl/moz.build b/media/libjxl/moz.build index 886c2319ad60d..b493386d4113d 100644 --- a/media/libjxl/moz.build +++ b/media/libjxl/moz.build @@ -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", ] diff --git a/media/libjxl/moz.yaml b/media/libjxl/moz.yaml index c2767f88facbd..d9984f43d2c0d 100644 --- a/media/libjxl/moz.yaml +++ b/media/libjxl/moz.yaml @@ -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 diff --git a/third_party/jpeg-xl/.clang-tidy b/third_party/jpeg-xl/.clang-tidy index 42d386276be68..11c6d2bcdd6e7 100644 --- a/third_party/jpeg-xl/.clang-tidy +++ b/third_party/jpeg-xl/.clang-tidy @@ -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, diff --git a/third_party/jpeg-xl/AUTHORS b/third_party/jpeg-xl/AUTHORS index ed6d72db66116..44387a01c461a 100644 --- a/third_party/jpeg-xl/AUTHORS +++ b/third_party/jpeg-xl/AUTHORS @@ -39,9 +39,11 @@ Alistair Barrow Andrius Lukas Narbutas Aous Naman Artem Selishchev +Aryan Pingle Biswapriyo Nath CanadianBaconBoi Damiano Albani +Damon Townsend Daniel Novomeský David Burnett dependabot[bot] @@ -53,17 +55,20 @@ Dong Xu estrogently <41487185+estrogently@users.noreply.github.com> Even Rouault Fred Brennan +Gerhard Huber gi-man Gilles Devillers (GilDev) Heiko Becker Ivan Kokorev Jim Robinson +John Platts Jonathan Brown (Jonnyawsom3) Joshua Root Kai Hollberg Kerry Su Kleis Auke Wolthuizen L. E. Segovia +ledoge Leo Izen Lovell Fuller Maarten DB diff --git a/third_party/jpeg-xl/BUILD.bazel b/third_party/jpeg-xl/BUILD.bazel index d419e3d9969b4..45c5261a2ea47 100644 --- a/third_party/jpeg-xl/BUILD.bazel +++ b/third_party/jpeg-xl/BUILD.bazel @@ -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( diff --git a/third_party/jpeg-xl/CHANGELOG.md b/third_party/jpeg-xl/CHANGELOG.md index 24aa25fae33ff..d67fbe0f5e38a 100644 --- a/third_party/jpeg-xl/CHANGELOG.md +++ b/third_party/jpeg-xl/CHANGELOG.md @@ -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 diff --git a/third_party/jpeg-xl/CMakeLists.txt b/third_party/jpeg-xl/CMakeLists.txt index d6891ef79d66f..8b2ccb5719891 100644 --- a/third_party/jpeg-xl/CMakeLists.txt +++ b/third_party/jpeg-xl/CMakeLists.txt @@ -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}") diff --git a/third_party/jpeg-xl/MODULE.bazel b/third_party/jpeg-xl/MODULE.bazel index c83838418536e..cc2397538dfbf 100644 --- a/third_party/jpeg-xl/MODULE.bazel +++ b/third_party/jpeg-xl/MODULE.bazel @@ -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") diff --git a/third_party/jpeg-xl/MODULE.bazel.lock b/third_party/jpeg-xl/MODULE.bazel.lock index 660e64e473a69..7ea00d853cbed 100644 --- a/third_party/jpeg-xl/MODULE.bazel.lock +++ b/third_party/jpeg-xl/MODULE.bazel.lock @@ -1,1438 +1,131 @@ { - "lockFileVersion": 3, - "moduleFileHash": "988082051d7ff14f970486f378ca8eb29edb2bb7e97a5cb2715f2794ab6b5d53", - "flags": { - "cmdRegistries": [ - "https://bcr.bazel.build/" - ], - "cmdModuleOverrides": {}, - "allowedYankedVersions": [], - "envVarAllowedYankedVersions": "", - "ignoreDevDependency": false, - "directDependenciesMode": "WARNING", - "compatibilityMode": "ERROR" - }, - "localOverrideHashes": { - "bazel_tools": "922ea6752dc9105de5af957f7a99a6933c0a6a712d23df6aad16a9c399f7e787" - }, - "moduleDepGraph": { - "": { - "name": "", - "version": "", - "key": "", - "repoName": "", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "bazel_skylib": "bazel_skylib@1.5.0", - "googletest": "googletest@1.14.0", - "openexr": "openexr@3.2.1", - "libpng": "libpng@1.6.40", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - } - }, - "bazel_skylib@1.5.0": { - "name": "bazel_skylib", - "version": "1.5.0", - "key": "bazel_skylib@1.5.0", - "repoName": "bazel_skylib", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [ - "//toolchains/unittest:cmd_toolchain", - "//toolchains/unittest:bash_toolchain" - ], - "extensionUsages": [], - "deps": { - "platforms": "platforms@0.0.7", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "bazel_skylib~1.5.0", - "urls": [ - "https://github.com/bazelbuild/bazel-skylib/releases/download/1.5.0/bazel-skylib-1.5.0.tar.gz" - ], - "integrity": "sha256-zVWgYudjuTSZIfD124w5MyiNyLpPdt2UFqrGis7jy5Q=", - "strip_prefix": "", - "remote_patches": {}, - "remote_patch_strip": 0 - } - } - }, - "googletest@1.14.0": { - "name": "googletest", - "version": "1.14.0", - "key": "googletest@1.14.0", - "repoName": "googletest", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "com_google_absl": "abseil-cpp@20230125.1", - "platforms": "platforms@0.0.7", - "rules_cc": "rules_cc@0.0.9", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "googletest~1.14.0", - "urls": [ - "https://github.com/google/googletest/archive/refs/tags/v1.14.0.tar.gz" - ], - "integrity": "sha256-itWYxzrXluDYKAsILOvYKmMNc+c808cAV5OKZQG7pdc=", - "strip_prefix": "googletest-1.14.0", - "remote_patches": { - "https://bcr.bazel.build/modules/googletest/1.14.0/patches/module_dot_bazel.patch": "sha256-CSomzvti38LCuURDG5EEoa3O1tQF3cKKt/mknnP1qcc=" - }, - "remote_patch_strip": 0 - } - } - }, - "openexr@3.2.1": { - "name": "openexr", - "version": "3.2.1", - "key": "openexr@3.2.1", - "repoName": "openexr", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "bazel_skylib": "bazel_skylib@1.5.0", - "Imath": "imath@3.1.9", - "libdeflate": "libdeflate@1.19", - "platforms": "platforms@0.0.7", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "openexr~3.2.1", - "urls": [ - "https://github.com/AcademySoftwareFoundation/openexr/archive/refs/tags/v3.2.1.tar.gz" - ], - "integrity": "sha256-YeF1qiIDOZ+zyMIoh1L76jwmN2gNULbjBupfj/3Uaps=", - "strip_prefix": "openexr-3.2.1", - "remote_patches": { - "https://bcr.bazel.build/modules/openexr/3.2.1/patches/module_dot_bazel.patch": "sha256-vrTXqfriDPsjzpyEyU3vrkgFesn3i1NKSmSMJ0bQ//0=" - }, - "remote_patch_strip": 0 - } - } - }, - "libpng@1.6.40": { - "name": "libpng", - "version": "1.6.40", - "key": "libpng@1.6.40", - "repoName": "libpng", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "platforms": "platforms@0.0.7", - "zlib": "zlib@1.3", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "libpng~1.6.40", - "urls": [ - "https://download.sourceforge.net/libpng/libpng-1.6.40.tar.gz" - ], - "integrity": "sha256-j3ILNjqghoPJvypWMjb0UxOvLFXVQrVIGuF92NGDu0I=", - "strip_prefix": "libpng-1.6.40", - "remote_patches": { - "https://bcr.bazel.build/modules/libpng/1.6.40/patches/add_build_file.patch": "sha256-IKBdDmPuuugv3ZFYMxKbKbJEdKd9c9FPxr5BBjkYnmI=", - "https://bcr.bazel.build/modules/libpng/1.6.40/patches/module_dot_bazel.patch": "sha256-I4/ZDMvlGjXSTRyHy9dvW8idDHIInWXZ8e6jDW0mq6o=" - }, - "remote_patch_strip": 0 - } - } - }, - "bazel_tools@_": { - "name": "bazel_tools", - "version": "", - "key": "bazel_tools@_", - "repoName": "bazel_tools", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [ - "@local_config_cc_toolchains//:all", - "@local_config_sh//:local_sh_toolchain" - ], - "extensionUsages": [ - { - "extensionBzlFile": "@bazel_tools//tools/cpp:cc_configure.bzl", - "extensionName": "cc_configure_extension", - "usingModule": "bazel_tools@_", - "location": { - "file": "@@bazel_tools//:MODULE.bazel", - "line": 17, - "column": 29 - }, - "imports": { - "local_config_cc": "local_config_cc", - "local_config_cc_toolchains": "local_config_cc_toolchains" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - }, - { - "extensionBzlFile": "@bazel_tools//tools/osx:xcode_configure.bzl", - "extensionName": "xcode_configure_extension", - "usingModule": "bazel_tools@_", - "location": { - "file": "@@bazel_tools//:MODULE.bazel", - "line": 21, - "column": 32 - }, - "imports": { - "local_config_xcode": "local_config_xcode" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - }, - { - "extensionBzlFile": "@rules_java//java:extensions.bzl", - "extensionName": "toolchains", - "usingModule": "bazel_tools@_", - "location": { - "file": "@@bazel_tools//:MODULE.bazel", - "line": 24, - "column": 32 - }, - "imports": { - "local_jdk": "local_jdk", - "remote_java_tools": "remote_java_tools", - "remote_java_tools_linux": "remote_java_tools_linux", - "remote_java_tools_windows": "remote_java_tools_windows", - "remote_java_tools_darwin_x86_64": "remote_java_tools_darwin_x86_64", - "remote_java_tools_darwin_arm64": "remote_java_tools_darwin_arm64" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - }, - { - "extensionBzlFile": "@bazel_tools//tools/sh:sh_configure.bzl", - "extensionName": "sh_configure_extension", - "usingModule": "bazel_tools@_", - "location": { - "file": "@@bazel_tools//:MODULE.bazel", - "line": 35, - "column": 39 - }, - "imports": { - "local_config_sh": "local_config_sh" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - }, - { - "extensionBzlFile": "@bazel_tools//tools/test:extensions.bzl", - "extensionName": "remote_coverage_tools_extension", - "usingModule": "bazel_tools@_", - "location": { - "file": "@@bazel_tools//:MODULE.bazel", - "line": 39, - "column": 48 - }, - "imports": { - "remote_coverage_tools": "remote_coverage_tools" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - }, - { - "extensionBzlFile": "@bazel_tools//tools/android:android_extensions.bzl", - "extensionName": "remote_android_tools_extensions", - "usingModule": "bazel_tools@_", - "location": { - "file": "@@bazel_tools//:MODULE.bazel", - "line": 42, - "column": 42 - }, - "imports": { - "android_gmaven_r8": "android_gmaven_r8", - "android_tools": "android_tools" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - } - ], - "deps": { - "rules_cc": "rules_cc@0.0.9", - "rules_java": "rules_java@7.1.0", - "rules_license": "rules_license@0.0.7", - "rules_proto": "rules_proto@4.0.0", - "rules_python": "rules_python@0.4.0", - "platforms": "platforms@0.0.7", - "com_google_protobuf": "protobuf@3.19.6", - "zlib": "zlib@1.3", - "build_bazel_apple_support": "apple_support@1.5.0", - "local_config_platform": "local_config_platform@_" - } - }, - "local_config_platform@_": { - "name": "local_config_platform", - "version": "", - "key": "local_config_platform@_", - "repoName": "local_config_platform", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "platforms": "platforms@0.0.7", - "bazel_tools": "bazel_tools@_" - } - }, - "platforms@0.0.7": { - "name": "platforms", - "version": "0.0.7", - "key": "platforms@0.0.7", - "repoName": "platforms", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "rules_license": "rules_license@0.0.7", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "platforms", - "urls": [ - "https://github.com/bazelbuild/platforms/releases/download/0.0.7/platforms-0.0.7.tar.gz" - ], - "integrity": "sha256-OlYcmee9vpFzqmU/1Xn+hJ8djWc5V4CrR3Cx84FDHVE=", - "strip_prefix": "", - "remote_patches": {}, - "remote_patch_strip": 0 - } - } - }, - "abseil-cpp@20230125.1": { - "name": "abseil-cpp", - "version": "20230125.1", - "key": "abseil-cpp@20230125.1", - "repoName": "abseil-cpp", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "rules_cc": "rules_cc@0.0.9", - "platforms": "platforms@0.0.7", - "bazel_skylib": "bazel_skylib@1.5.0", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "abseil-cpp~20230125.1", - "urls": [ - "https://github.com/abseil/abseil-cpp/archive/refs/tags/20230125.1.tar.gz" - ], - "integrity": "sha256-gTEcF1mbNxIGne0gzKCaYqsL8qid+haZN4bIeCt+0UU=", - "strip_prefix": "abseil-cpp-20230125.1", - "remote_patches": { - "https://bcr.bazel.build/modules/abseil-cpp/20230125.1/patches/module_dot_bazel.patch": "sha256-L1wChhBmDOnRbPbD4MENVXHjOBT2KFrDxT6D+aoThxk=" - }, - "remote_patch_strip": 0 - } - } - }, - "rules_cc@0.0.9": { - "name": "rules_cc", - "version": "0.0.9", - "key": "rules_cc@0.0.9", - "repoName": "rules_cc", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [ - "@local_config_cc_toolchains//:all" - ], - "extensionUsages": [ - { - "extensionBzlFile": "@bazel_tools//tools/cpp:cc_configure.bzl", - "extensionName": "cc_configure_extension", - "usingModule": "rules_cc@0.0.9", - "location": { - "file": "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel", - "line": 9, - "column": 29 - }, - "imports": { - "local_config_cc_toolchains": "local_config_cc_toolchains" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - } - ], - "deps": { - "platforms": "platforms@0.0.7", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_cc~0.0.9", - "urls": [ - "https://github.com/bazelbuild/rules_cc/releases/download/0.0.9/rules_cc-0.0.9.tar.gz" - ], - "integrity": "sha256-IDeHW5pEVtzkp50RKorohbvEqtlo5lh9ym5k86CQDN8=", - "strip_prefix": "rules_cc-0.0.9", - "remote_patches": { - "https://bcr.bazel.build/modules/rules_cc/0.0.9/patches/module_dot_bazel_version.patch": "sha256-mM+qzOI0SgAdaJBlWOSMwMPKpaA9b7R37Hj/tp5bb4g=" - }, - "remote_patch_strip": 0 - } - } - }, - "imath@3.1.9": { - "name": "imath", - "version": "3.1.9", - "key": "imath@3.1.9", - "repoName": "imath", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "bazel_skylib": "bazel_skylib@1.5.0", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "imath~3.1.9", - "urls": [ - "https://github.com/AcademySoftwareFoundation/Imath/archive/refs/tags/v3.1.9.tar.gz" - ], - "integrity": "sha256-8diqzUav7ZWLq/ztMZDS08ggm2baRR9Var1tqUwWXPM=", - "strip_prefix": "Imath-3.1.9", - "remote_patches": { - "https://bcr.bazel.build/modules/imath/3.1.9/patches/add_build_file.patch": "sha256-hpm7m6W5MmXfxyJyZYcxHd4gHz93hu1jj5c8EHtM4WI=", - "https://bcr.bazel.build/modules/imath/3.1.9/patches/module_dot_bazel.patch": "sha256-Ze6qnPdaaDfi9Q+PlprFVGYxRfdlRfzsozWWnEGi9mc=" - }, - "remote_patch_strip": 0 - } - } - }, - "libdeflate@1.19": { - "name": "libdeflate", - "version": "1.19", - "key": "libdeflate@1.19", - "repoName": "libdeflate", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "libdeflate~1.19", - "urls": [ - "https://github.com/ebiggers/libdeflate/archive/refs/tags/v1.19.tar.gz" - ], - "integrity": "sha256-J79i1xzWRyj/Q6n+uS8qwvK/dImG2FYTPMHlGZJCjCU=", - "strip_prefix": "libdeflate-1.19", - "remote_patches": { - "https://bcr.bazel.build/modules/libdeflate/1.19/patches/add_build_file.patch": "sha256-L5cLd/VE0kOH29ifL5KdRkGX2KOldCTgKqTmNTWOTjg=", - "https://bcr.bazel.build/modules/libdeflate/1.19/patches/module_dot_bazel.patch": "sha256-GcCZeZoaXO2+nzQQlv8TqMYlyiAyoz1/f/CjSpUbd8Q=" - }, - "remote_patch_strip": 0 - } - } - }, - "zlib@1.3": { - "name": "zlib", - "version": "1.3", - "key": "zlib@1.3", - "repoName": "zlib", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "platforms": "platforms@0.0.7", - "rules_cc": "rules_cc@0.0.9", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "zlib~1.3", - "urls": [ - "https://github.com/madler/zlib/releases/download/v1.3/zlib-1.3.tar.gz" - ], - "integrity": "sha256-/wukwpIBPbwnUws6geH5qBPNOd4Byl4Pi/NVcC76WT4=", - "strip_prefix": "zlib-1.3", - "remote_patches": { - "https://bcr.bazel.build/modules/zlib/1.3/patches/add_build_file.patch": "sha256-Ei+FYaaOo7A3jTKunMEodTI0Uw5NXQyZEcboMC8JskY=", - "https://bcr.bazel.build/modules/zlib/1.3/patches/module_dot_bazel.patch": "sha256-fPWLM+2xaF/kuy+kZc1YTfW6hNjrkG400Ho7gckuyJk=" - }, - "remote_patch_strip": 0 - } - } - }, - "rules_java@7.1.0": { - "name": "rules_java", - "version": "7.1.0", - "key": "rules_java@7.1.0", - "repoName": "rules_java", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [ - "//toolchains:all", - "@local_jdk//:runtime_toolchain_definition", - "@local_jdk//:bootstrap_runtime_toolchain_definition", - "@remotejdk11_linux_toolchain_config_repo//:all", - "@remotejdk11_linux_aarch64_toolchain_config_repo//:all", - "@remotejdk11_linux_ppc64le_toolchain_config_repo//:all", - "@remotejdk11_linux_s390x_toolchain_config_repo//:all", - "@remotejdk11_macos_toolchain_config_repo//:all", - "@remotejdk11_macos_aarch64_toolchain_config_repo//:all", - "@remotejdk11_win_toolchain_config_repo//:all", - "@remotejdk11_win_arm64_toolchain_config_repo//:all", - "@remotejdk17_linux_toolchain_config_repo//:all", - "@remotejdk17_linux_aarch64_toolchain_config_repo//:all", - "@remotejdk17_linux_ppc64le_toolchain_config_repo//:all", - "@remotejdk17_linux_s390x_toolchain_config_repo//:all", - "@remotejdk17_macos_toolchain_config_repo//:all", - "@remotejdk17_macos_aarch64_toolchain_config_repo//:all", - "@remotejdk17_win_toolchain_config_repo//:all", - "@remotejdk17_win_arm64_toolchain_config_repo//:all", - "@remotejdk21_linux_toolchain_config_repo//:all", - "@remotejdk21_linux_aarch64_toolchain_config_repo//:all", - "@remotejdk21_macos_toolchain_config_repo//:all", - "@remotejdk21_macos_aarch64_toolchain_config_repo//:all", - "@remotejdk21_win_toolchain_config_repo//:all" - ], - "extensionUsages": [ - { - "extensionBzlFile": "@rules_java//java:extensions.bzl", - "extensionName": "toolchains", - "usingModule": "rules_java@7.1.0", - "location": { - "file": "https://bcr.bazel.build/modules/rules_java/7.1.0/MODULE.bazel", - "line": 19, - "column": 27 - }, - "imports": { - "remote_java_tools": "remote_java_tools", - "remote_java_tools_linux": "remote_java_tools_linux", - "remote_java_tools_windows": "remote_java_tools_windows", - "remote_java_tools_darwin_x86_64": "remote_java_tools_darwin_x86_64", - "remote_java_tools_darwin_arm64": "remote_java_tools_darwin_arm64", - "local_jdk": "local_jdk", - "remotejdk11_linux_toolchain_config_repo": "remotejdk11_linux_toolchain_config_repo", - "remotejdk11_linux_aarch64_toolchain_config_repo": "remotejdk11_linux_aarch64_toolchain_config_repo", - "remotejdk11_linux_ppc64le_toolchain_config_repo": "remotejdk11_linux_ppc64le_toolchain_config_repo", - "remotejdk11_linux_s390x_toolchain_config_repo": "remotejdk11_linux_s390x_toolchain_config_repo", - "remotejdk11_macos_toolchain_config_repo": "remotejdk11_macos_toolchain_config_repo", - "remotejdk11_macos_aarch64_toolchain_config_repo": "remotejdk11_macos_aarch64_toolchain_config_repo", - "remotejdk11_win_toolchain_config_repo": "remotejdk11_win_toolchain_config_repo", - "remotejdk11_win_arm64_toolchain_config_repo": "remotejdk11_win_arm64_toolchain_config_repo", - "remotejdk17_linux_toolchain_config_repo": "remotejdk17_linux_toolchain_config_repo", - "remotejdk17_linux_aarch64_toolchain_config_repo": "remotejdk17_linux_aarch64_toolchain_config_repo", - "remotejdk17_linux_ppc64le_toolchain_config_repo": "remotejdk17_linux_ppc64le_toolchain_config_repo", - "remotejdk17_linux_s390x_toolchain_config_repo": "remotejdk17_linux_s390x_toolchain_config_repo", - "remotejdk17_macos_toolchain_config_repo": "remotejdk17_macos_toolchain_config_repo", - "remotejdk17_macos_aarch64_toolchain_config_repo": "remotejdk17_macos_aarch64_toolchain_config_repo", - "remotejdk17_win_toolchain_config_repo": "remotejdk17_win_toolchain_config_repo", - "remotejdk17_win_arm64_toolchain_config_repo": "remotejdk17_win_arm64_toolchain_config_repo", - "remotejdk21_linux_toolchain_config_repo": "remotejdk21_linux_toolchain_config_repo", - "remotejdk21_linux_aarch64_toolchain_config_repo": "remotejdk21_linux_aarch64_toolchain_config_repo", - "remotejdk21_macos_toolchain_config_repo": "remotejdk21_macos_toolchain_config_repo", - "remotejdk21_macos_aarch64_toolchain_config_repo": "remotejdk21_macos_aarch64_toolchain_config_repo", - "remotejdk21_win_toolchain_config_repo": "remotejdk21_win_toolchain_config_repo" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - } - ], - "deps": { - "platforms": "platforms@0.0.7", - "rules_cc": "rules_cc@0.0.9", - "bazel_skylib": "bazel_skylib@1.5.0", - "rules_proto": "rules_proto@4.0.0", - "rules_license": "rules_license@0.0.7", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0", - "urls": [ - "https://github.com/bazelbuild/rules_java/releases/download/7.1.0/rules_java-7.1.0.tar.gz" - ], - "integrity": "sha256-o3pOX2OrgnFuXdau75iO2EYcegC46TYnImKJn1h81OE=", - "strip_prefix": "", - "remote_patches": {}, - "remote_patch_strip": 0 - } - } - }, - "rules_license@0.0.7": { - "name": "rules_license", - "version": "0.0.7", - "key": "rules_license@0.0.7", - "repoName": "rules_license", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_license~0.0.7", - "urls": [ - "https://github.com/bazelbuild/rules_license/releases/download/0.0.7/rules_license-0.0.7.tar.gz" - ], - "integrity": "sha256-RTHezLkTY5ww5cdRKgVNXYdWmNrrddjPkPKEN1/nw2A=", - "strip_prefix": "", - "remote_patches": {}, - "remote_patch_strip": 0 - } - } - }, - "rules_proto@4.0.0": { - "name": "rules_proto", - "version": "4.0.0", - "key": "rules_proto@4.0.0", - "repoName": "rules_proto", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "bazel_skylib": "bazel_skylib@1.5.0", - "rules_cc": "rules_cc@0.0.9", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_proto~4.0.0", - "urls": [ - "https://github.com/bazelbuild/rules_proto/archive/refs/tags/4.0.0.zip" - ], - "integrity": "sha256-Lr5z6xyuRA19pNtRYMGjKaynwQpck4H/lwYyVjyhoq4=", - "strip_prefix": "rules_proto-4.0.0", - "remote_patches": { - "https://bcr.bazel.build/modules/rules_proto/4.0.0/patches/module_dot_bazel.patch": "sha256-MclJO7tIAM2ElDAmscNId9pKTpOuDGHgVlW/9VBOIp0=" - }, - "remote_patch_strip": 0 - } - } - }, - "rules_python@0.4.0": { - "name": "rules_python", - "version": "0.4.0", - "key": "rules_python@0.4.0", - "repoName": "rules_python", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [ - "@bazel_tools//tools/python:autodetecting_toolchain" - ], - "extensionUsages": [ - { - "extensionBzlFile": "@rules_python//bzlmod:extensions.bzl", - "extensionName": "pip_install", - "usingModule": "rules_python@0.4.0", - "location": { - "file": "https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel", - "line": 7, - "column": 28 - }, - "imports": { - "pypi__click": "pypi__click", - "pypi__pip": "pypi__pip", - "pypi__pip_tools": "pypi__pip_tools", - "pypi__pkginfo": "pypi__pkginfo", - "pypi__setuptools": "pypi__setuptools", - "pypi__wheel": "pypi__wheel" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - } - ], - "deps": { - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_python~0.4.0", - "urls": [ - "https://github.com/bazelbuild/rules_python/releases/download/0.4.0/rules_python-0.4.0.tar.gz" - ], - "integrity": "sha256-lUqom0kb5KCDMEosuDgBnIuMNyCnq7nEy4GseiQjDOo=", - "strip_prefix": "", - "remote_patches": { - "https://bcr.bazel.build/modules/rules_python/0.4.0/patches/propagate_pip_install_dependencies.patch": "sha256-v7S/dem/mixg63MF4KoRGDA4KEol9ab/tIVp+6Xq0D0=", - "https://bcr.bazel.build/modules/rules_python/0.4.0/patches/module_dot_bazel.patch": "sha256-kG4VIfWxQazzTuh50mvsx6pmyoRVA4lfH5rkto/Oq+Y=" - }, - "remote_patch_strip": 1 - } - } - }, - "protobuf@3.19.6": { - "name": "protobuf", - "version": "3.19.6", - "key": "protobuf@3.19.6", - "repoName": "protobuf", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "bazel_skylib": "bazel_skylib@1.5.0", - "zlib": "zlib@1.3", - "rules_python": "rules_python@0.4.0", - "rules_cc": "rules_cc@0.0.9", - "rules_proto": "rules_proto@4.0.0", - "rules_java": "rules_java@7.1.0", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "protobuf~3.19.6", - "urls": [ - "https://github.com/protocolbuffers/protobuf/archive/refs/tags/v3.19.6.zip" - ], - "integrity": "sha256-OH4sVZuyx8G8N5jE5s/wFTgaebJ1hpavy/johzC0c4k=", - "strip_prefix": "protobuf-3.19.6", - "remote_patches": { - "https://bcr.bazel.build/modules/protobuf/3.19.6/patches/relative_repo_names.patch": "sha256-w/5gw/zGv8NFId+669hcdw1Uus2lxgYpulATHIwIByI=", - "https://bcr.bazel.build/modules/protobuf/3.19.6/patches/remove_dependency_on_rules_jvm_external.patch": "sha256-THUTnVgEBmjA0W7fKzIyZOVG58DnW9HQTkr4D2zKUUc=", - "https://bcr.bazel.build/modules/protobuf/3.19.6/patches/add_module_dot_bazel_for_examples.patch": "sha256-s/b1gi3baK3LsXefI2rQilhmkb2R5jVJdnT6zEcdfHY=", - "https://bcr.bazel.build/modules/protobuf/3.19.6/patches/module_dot_bazel.patch": "sha256-S0DEni8zgx7rHscW3z/rCEubQnYec0XhNet640cw0h4=" - }, - "remote_patch_strip": 1 - } - } - }, - "apple_support@1.5.0": { - "name": "apple_support", - "version": "1.5.0", - "key": "apple_support@1.5.0", - "repoName": "build_bazel_apple_support", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [ - "@local_config_apple_cc_toolchains//:all" - ], - "extensionUsages": [ - { - "extensionBzlFile": "@build_bazel_apple_support//crosstool:setup.bzl", - "extensionName": "apple_cc_configure_extension", - "usingModule": "apple_support@1.5.0", - "location": { - "file": "https://bcr.bazel.build/modules/apple_support/1.5.0/MODULE.bazel", - "line": 17, - "column": 35 - }, - "imports": { - "local_config_apple_cc": "local_config_apple_cc", - "local_config_apple_cc_toolchains": "local_config_apple_cc_toolchains" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - } - ], - "deps": { - "bazel_skylib": "bazel_skylib@1.5.0", - "platforms": "platforms@0.0.7", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "apple_support~1.5.0", - "urls": [ - "https://github.com/bazelbuild/apple_support/releases/download/1.5.0/apple_support.1.5.0.tar.gz" - ], - "integrity": "sha256-miM41vja0yRPgj8txghKA+TQ+7J8qJLclw5okNW0gYQ=", - "strip_prefix": "", - "remote_patches": {}, - "remote_patch_strip": 0 - } - } - } + "lockFileVersion": 11, + "registryFileHashes": { + "https://bcr.bazel.build/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497", + "https://bcr.bazel.build/modules/abseil-cpp/20210324.2/MODULE.bazel": "7cd0312e064fde87c8d1cd79ba06c876bd23630c83466e9500321be55c96ace2", + "https://bcr.bazel.build/modules/abseil-cpp/20211102.0/MODULE.bazel": "70390338f7a5106231d20620712f7cccb659cd0e9d073d1991c038eb9fc57589", + "https://bcr.bazel.build/modules/abseil-cpp/20230125.1/MODULE.bazel": "89047429cb0207707b2dface14ba7f8df85273d484c2572755be4bab7ce9c3a0", + "https://bcr.bazel.build/modules/abseil-cpp/20230125.1/source.json": "06cc0842d241da0c5edc755edb3c7d0d008d304330e57ecf2d6449fb0b633a82", + "https://bcr.bazel.build/modules/apple_support/1.5.0/MODULE.bazel": "50341a62efbc483e8a2a6aec30994a58749bd7b885e18dd96aa8c33031e558ef", + "https://bcr.bazel.build/modules/apple_support/1.5.0/source.json": "eb98a7627c0bc486b57f598ad8da50f6625d974c8f723e9ea71bd39f709c9862", + "https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8", + "https://bcr.bazel.build/modules/bazel_features/1.11.0/source.json": "c9320aa53cd1c441d24bd6b716da087ad7e4ff0d9742a9884587596edfe53015", + "https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8", + "https://bcr.bazel.build/modules/bazel_skylib/1.2.1/MODULE.bazel": "f35baf9da0efe45fa3da1696ae906eea3d615ad41e2e3def4aeb4e8bc0ef9a7a", + "https://bcr.bazel.build/modules/bazel_skylib/1.3.0/MODULE.bazel": "20228b92868bf5cfc41bda7afc8a8ba2a543201851de39d990ec957b513579c5", + "https://bcr.bazel.build/modules/bazel_skylib/1.4.1/MODULE.bazel": "a0dcb779424be33100dcae821e9e27e4f2901d9dfd5333efe5ac6a8d7ab75e1d", + "https://bcr.bazel.build/modules/bazel_skylib/1.4.2/MODULE.bazel": "3bd40978e7a1fac911d5989e6b09d8f64921865a45822d8b09e815eaa726a651", + "https://bcr.bazel.build/modules/bazel_skylib/1.5.0/MODULE.bazel": "32880f5e2945ce6a03d1fbd588e9198c0a959bb42297b2cfaf1685b7bc32e138", + "https://bcr.bazel.build/modules/bazel_skylib/1.6.1/MODULE.bazel": "8fdee2dbaace6c252131c00e1de4b165dc65af02ea278476187765e1a617b917", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/MODULE.bazel": "3120d80c5861aa616222ec015332e5f8d3171e062e3e804a2a0253e1be26e59b", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/source.json": "f121b43eeefc7c29efbd51b83d08631e2347297c95aac9764a701f2a6a2bb953", + "https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84", + "https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8", + "https://bcr.bazel.build/modules/giflib/5.2.1/MODULE.bazel": "810dbc4275425c89ffe648dd78c537fe2eb1d2a9704d10e950b295263af03366", + "https://bcr.bazel.build/modules/giflib/5.2.1/source.json": "94215af981976c329eaec0083727b155ea89607e61debea50ed508e7963ef9a6", + "https://bcr.bazel.build/modules/googletest/1.11.0/MODULE.bazel": "3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4", + "https://bcr.bazel.build/modules/googletest/1.14.0/MODULE.bazel": "cfbcbf3e6eac06ef9d85900f64424708cc08687d1b527f0ef65aa7517af8118f", + "https://bcr.bazel.build/modules/googletest/1.14.0/source.json": "2478949479000fdd7de9a3d0107ba2c85bb5f961c3ecb1aa448f52549ce310b5", + "https://bcr.bazel.build/modules/imath/3.1.9/MODULE.bazel": "26fe47ee8137a4c605667fb0d26a5c12b8fb2e758824a376789b287b2f9d424d", + "https://bcr.bazel.build/modules/imath/3.1.9/source.json": "22b7d9e617d4d26626f5ac8fba3cd2bd7a87f7501c99fa847f8d9e2980416e8f", + "https://bcr.bazel.build/modules/libdeflate/1.19/MODULE.bazel": "b7396a2edfd5ce6669509fbdd10db5e8731d60954063699c546c3126c8156824", + "https://bcr.bazel.build/modules/libdeflate/1.19/source.json": "d4604a526efba9b5347309de49673bbe152da465f7c80c7f7ffe6800d8b504d1", + "https://bcr.bazel.build/modules/libjpeg_turbo/2.1.91/MODULE.bazel": "bcc23b7c4866af2d7777ee49db435603ca1e35b90ea0689f8051900fa8c73c6b", + "https://bcr.bazel.build/modules/libjpeg_turbo/2.1.91/source.json": "42ea85708058e2408f229075e1cbeaad13fa2719918ff9c505be5e22b57ef17b", + "https://bcr.bazel.build/modules/libpng/1.6.40/MODULE.bazel": "cc1952a9b5efd4df3dfdb9f9ba2b1c8d88b4fd9b0e474185cb81d90a31c7c453", + "https://bcr.bazel.build/modules/libpng/1.6.40/source.json": "2fe294bf161c2d3f1e04e7cecb6eb2e6c0c198698b23cabc1c4e6ff77d82a86a", + "https://bcr.bazel.build/modules/libwebp/1.3.2/MODULE.bazel": "c60edf34a913daebac9bd2cbe17b84048e4a7a5d3571f70be93c1b1227a69659", + "https://bcr.bazel.build/modules/libwebp/1.3.2/source.json": "e7b8d3047ad9758fda22fcf46bd8b57414b0eb5e7903f4ce888683d778633cf7", + "https://bcr.bazel.build/modules/openexr/3.2.1/MODULE.bazel": "5665fa95490825760943601d618e2d70eb45378ea3f2961c5ec18f23ae8a2106", + "https://bcr.bazel.build/modules/openexr/3.2.1/source.json": "afc17dda6614ff723cc1def634fa4f33534d3d29514b089fa4aa5eb47ba1c65b", + "https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": "9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee", + "https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": "5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37", + "https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": "ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615", + "https://bcr.bazel.build/modules/platforms/0.0.7/MODULE.bazel": "72fd4a0ede9ee5c021f6a8dd92b503e089f46c227ba2813ff183b71616034814", + "https://bcr.bazel.build/modules/platforms/0.0.8/MODULE.bazel": "9f142c03e348f6d263719f5074b21ef3adf0b139ee4c5133e2aa35664da9eb2d", + "https://bcr.bazel.build/modules/platforms/0.0.9/MODULE.bazel": "4a87a60c927b56ddd67db50c89acaa62f4ce2a1d2149ccb63ffd871d5ce29ebc", + "https://bcr.bazel.build/modules/platforms/0.0.9/source.json": "cd74d854bf16a9e002fb2ca7b1a421f4403cda29f824a765acd3a8c56f8d43e6", + "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": "a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7", + "https://bcr.bazel.build/modules/protobuf/21.7/source.json": "bbe500720421e582ff2d18b0802464205138c06056f443184de39fbb8187b09b", + "https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0", + "https://bcr.bazel.build/modules/protobuf/3.19.6/MODULE.bazel": "9233edc5e1f2ee276a60de3eaa47ac4132302ef9643238f23128fea53ea12858", + "https://bcr.bazel.build/modules/rules_cc/0.0.1/MODULE.bazel": "cb2aa0747f84c6c3a78dad4e2049c154f08ab9d166b1273835a8174940365647", + "https://bcr.bazel.build/modules/rules_cc/0.0.2/MODULE.bazel": "6915987c90970493ab97393024c156ea8fb9f3bea953b2f3ec05c34f19b5695c", + "https://bcr.bazel.build/modules/rules_cc/0.0.6/MODULE.bazel": "abf360251023dfe3efcef65ab9d56beefa8394d4176dd29529750e1c57eaa33f", + "https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e", + "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5", + "https://bcr.bazel.build/modules/rules_cc/0.0.9/source.json": "1f1ba6fea244b616de4a554a0f4983c91a9301640c8fe0dd1d410254115c8430", + "https://bcr.bazel.build/modules/rules_java/4.0.0/MODULE.bazel": "5a78a7ae82cd1a33cef56dc578c7d2a46ed0dca12643ee45edbb8417899e6f74", + "https://bcr.bazel.build/modules/rules_java/7.6.1/MODULE.bazel": "2f14b7e8a1aa2f67ae92bc69d1ec0fa8d9f827c4e17ff5e5f02e91caa3b2d0fe", + "https://bcr.bazel.build/modules/rules_java/7.6.1/source.json": "8f3f3076554e1558e8e468b2232991c510ecbcbed9e6f8c06ac31c93bcf38362", + "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel": "a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7", + "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/source.json": "a075731e1b46bc8425098512d038d416e966ab19684a10a34f4741295642fc35", + "https://bcr.bazel.build/modules/rules_license/0.0.3/MODULE.bazel": "627e9ab0247f7d1e05736b59dbb1b6871373de5ad31c3011880b4133cafd4bd0", + "https://bcr.bazel.build/modules/rules_license/0.0.7/MODULE.bazel": "088fbeb0b6a419005b89cf93fe62d9517c0a2b8bb56af3244af65ecfe37e7d5d", + "https://bcr.bazel.build/modules/rules_license/0.0.7/source.json": "355cc5737a0f294e560d52b1b7a6492d4fff2caf0bef1a315df5a298fca2d34a", + "https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc", + "https://bcr.bazel.build/modules/rules_pkg/0.7.0/source.json": "c2557066e0c0342223ba592510ad3d812d4963b9024831f7f66fd0584dd8c66c", + "https://bcr.bazel.build/modules/rules_proto/4.0.0/MODULE.bazel": "a7a7b6ce9bee418c1a760b3d84f83a299ad6952f9903c67f19e4edd964894e06", + "https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/MODULE.bazel": "e8dff86b0971688790ae75528fe1813f71809b5afd57facb44dad9e8eca631b7", + "https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/source.json": "d57902c052424dfda0e71646cb12668d39c4620ee0544294d9d941e7d12bc3a9", + "https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f", + "https://bcr.bazel.build/modules/rules_python/0.22.1/MODULE.bazel": "26114f0c0b5e93018c0c066d6673f1a2c3737c7e90af95eff30cfee38d0bbac7", + "https://bcr.bazel.build/modules/rules_python/0.22.1/source.json": "57226905e783bae7c37c2dd662be078728e48fa28ee4324a7eabcafb5a43d014", + "https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c", + "https://bcr.bazel.build/modules/stardoc/0.5.1/MODULE.bazel": "1a05d92974d0c122f5ccf09291442580317cdd859f07a8655f1db9a60374f9f8", + "https://bcr.bazel.build/modules/stardoc/0.5.1/source.json": "a96f95e02123320aa015b956f29c00cb818fa891ef823d55148e1a362caacf29", + "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43", + "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/source.json": "f1ef7d3f9e0e26d4b23d1c39b5f5de71f584dd7d1b4ef83d9bbba6ec7a6a6459", + "https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0", + "https://bcr.bazel.build/modules/zlib/1.2.12/MODULE.bazel": "3b1a8834ada2a883674be8cbd36ede1b6ec481477ada359cd2d3ddc562340b27", + "https://bcr.bazel.build/modules/zlib/1.3/MODULE.bazel": "6a9c02f19a24dcedb05572b2381446e27c272cd383aed11d41d99da9e3167a72", + "https://bcr.bazel.build/modules/zlib/1.3/source.json": "b6b43d0737af846022636e6e255fd4a96fee0d34f08f3830e6e0bac51465c37c" }, + "selectedYankedVersions": {}, "moduleExtensions": { - "@@apple_support~1.5.0//crosstool:setup.bzl%apple_cc_configure_extension": { + "@@apple_support~//crosstool:setup.bzl%apple_cc_configure_extension": { "general": { - "bzlTransitiveDigest": "pMLFCYaRPkgXPQ8vtuNkMfiHfPmRBy6QJfnid4sWfv0=", - "accumulatedFileDigests": {}, + "bzlTransitiveDigest": "PjIds3feoYE8SGbbIq2SFTZy3zmxeO2tQevJZNDo7iY=", + "usagesDigest": "aLmqbvowmHkkBPve05yyDNGN7oh7QE9kBADr3QIZTZs=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, "envVariables": {}, "generatedRepoSpecs": { "local_config_apple_cc": { - "bzlFile": "@@apple_support~1.5.0//crosstool:setup.bzl", + "bzlFile": "@@apple_support~//crosstool:setup.bzl", "ruleClassName": "_apple_cc_autoconf", - "attributes": { - "name": "apple_support~1.5.0~apple_cc_configure_extension~local_config_apple_cc" - } + "attributes": {} }, "local_config_apple_cc_toolchains": { - "bzlFile": "@@apple_support~1.5.0//crosstool:setup.bzl", + "bzlFile": "@@apple_support~//crosstool:setup.bzl", "ruleClassName": "_apple_cc_autoconf_toolchains", - "attributes": { - "name": "apple_support~1.5.0~apple_cc_configure_extension~local_config_apple_cc_toolchains" - } - } - } - } - }, - "@@bazel_tools//tools/cpp:cc_configure.bzl%cc_configure_extension": { - "general": { - "bzlTransitiveDigest": "O9sf6ilKWU9Veed02jG9o2HM/xgV/UAyciuFBuxrFRY=", - "accumulatedFileDigests": {}, - "envVariables": {}, - "generatedRepoSpecs": { - "local_config_cc": { - "bzlFile": "@@bazel_tools//tools/cpp:cc_configure.bzl", - "ruleClassName": "cc_autoconf", - "attributes": { - "name": "bazel_tools~cc_configure_extension~local_config_cc" - } - }, - "local_config_cc_toolchains": { - "bzlFile": "@@bazel_tools//tools/cpp:cc_configure.bzl", - "ruleClassName": "cc_autoconf_toolchains", - "attributes": { - "name": "bazel_tools~cc_configure_extension~local_config_cc_toolchains" - } - } - } - } - }, - "@@bazel_tools//tools/osx:xcode_configure.bzl%xcode_configure_extension": { - "general": { - "bzlTransitiveDigest": "Qh2bWTU6QW6wkrd87qrU4YeY+SG37Nvw3A0PR4Y0L2Y=", - "accumulatedFileDigests": {}, - "envVariables": {}, - "generatedRepoSpecs": { - "local_config_xcode": { - "bzlFile": "@@bazel_tools//tools/osx:xcode_configure.bzl", - "ruleClassName": "xcode_autoconf", - "attributes": { - "name": "bazel_tools~xcode_configure_extension~local_config_xcode", - "xcode_locator": "@bazel_tools//tools/osx:xcode_locator.m", - "remote_xcode": "" - } - } - } - } - }, - "@@bazel_tools//tools/sh:sh_configure.bzl%sh_configure_extension": { - "general": { - "bzlTransitiveDigest": "hp4NgmNjEg5+xgvzfh6L83bt9/aiiWETuNpwNuF1MSU=", - "accumulatedFileDigests": {}, - "envVariables": {}, - "generatedRepoSpecs": { - "local_config_sh": { - "bzlFile": "@@bazel_tools//tools/sh:sh_configure.bzl", - "ruleClassName": "sh_config", - "attributes": { - "name": "bazel_tools~sh_configure_extension~local_config_sh" - } + "attributes": {} } - } + }, + "recordedRepoMappingEntries": [ + [ + "apple_support~", + "bazel_tools", + "bazel_tools" + ] + ] } }, - "@@rules_java~7.1.0//java:extensions.bzl%toolchains": { + "@@platforms//host:extension.bzl%host_platform": { "general": { - "bzlTransitiveDigest": "iUIRqCK7tkhvcDJCAfPPqSd06IHG0a8HQD0xeQyVAqw=", - "accumulatedFileDigests": {}, + "bzlTransitiveDigest": "xelQcPZH8+tmuOHVjL9vDxMnnQNMlwj0SlvgoqBkm4U=", + "usagesDigest": "meSzxn3DUCcYEhq4HQwExWkWtU4EjriRBQLsZN+Q0SU=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, "envVariables": {}, "generatedRepoSpecs": { - "remotejdk21_linux_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_linux_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux//:jdk\",\n)\n" - } - }, - "remotejdk17_linux_s390x_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_s390x_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_s390x//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_s390x//:jdk\",\n)\n" - } - }, - "remotejdk17_macos_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_macos_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos//:jdk\",\n)\n" - } - }, - "remotejdk21_macos_aarch64_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_macos_aarch64_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos_aarch64//:jdk\",\n)\n" - } - }, - "remotejdk17_linux_aarch64_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_aarch64_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_aarch64//:jdk\",\n)\n" - } - }, - "remotejdk21_macos_aarch64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_macos_aarch64", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", - "sha256": "2a7a99a3ea263dbd8d32a67d1e6e363ba8b25c645c826f5e167a02bbafaff1fa", - "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-macosx_aarch64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-macosx_aarch64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-macosx_aarch64.tar.gz" - ] - } - }, - "remotejdk17_linux_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux//:jdk\",\n)\n" - } - }, - "remotejdk17_macos_aarch64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_macos_aarch64", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", - "sha256": "314b04568ec0ae9b36ba03c9cbd42adc9e1265f74678923b19297d66eb84dcca", - "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-macosx_aarch64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_aarch64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_aarch64.tar.gz" - ] - } - }, - "remote_java_tools_windows": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remote_java_tools_windows", - "sha256": "c5c70c214a350f12cbf52da8270fa43ba629b795f3dd328028a38f8f0d39c2a1", - "urls": [ - "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools_windows-v13.1.zip", - "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools_windows-v13.1.zip" - ] - } - }, - "remotejdk11_win": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_win", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", - "sha256": "43408193ce2fa0862819495b5ae8541085b95660153f2adcf91a52d3a1710e83", - "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-win_x64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-win_x64.zip", - "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-win_x64.zip" - ] - } - }, - "remotejdk11_win_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_win_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win//:jdk\",\n)\n" - } - }, - "remotejdk11_linux_aarch64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_aarch64", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", - "sha256": "54174439f2b3fddd11f1048c397fe7bb45d4c9d66d452d6889b013d04d21c4de", - "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-linux_aarch64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_aarch64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_aarch64.tar.gz" - ] - } - }, - "remotejdk17_linux": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_linux", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", - "sha256": "b9482f2304a1a68a614dfacddcf29569a72f0fac32e6c74f83dc1b9a157b8340", - "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-linux_x64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_x64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_x64.tar.gz" - ] - } - }, - "remotejdk11_linux_s390x_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_s390x_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_s390x//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_s390x//:jdk\",\n)\n" - } - }, - "remotejdk11_linux_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux//:jdk\",\n)\n" - } - }, - "remotejdk11_macos": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_macos", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", - "sha256": "bcaab11cfe586fae7583c6d9d311c64384354fb2638eb9a012eca4c3f1a1d9fd", - "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-macosx_x64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_x64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_x64.tar.gz" - ] - } - }, - "remotejdk11_win_arm64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_win_arm64", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", - "sha256": "b8a28e6e767d90acf793ea6f5bed0bb595ba0ba5ebdf8b99f395266161e53ec2", - "strip_prefix": "jdk-11.0.13+8", - "urls": [ - "https://mirror.bazel.build/aka.ms/download-jdk/microsoft-jdk-11.0.13.8.1-windows-aarch64.zip" - ] - } - }, - "remotejdk17_macos": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_macos", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", - "sha256": "640453e8afe8ffe0fb4dceb4535fb50db9c283c64665eebb0ba68b19e65f4b1f", - "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-macosx_x64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_x64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_x64.tar.gz" - ] - } - }, - "remotejdk21_macos": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_macos", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", - "sha256": "9639b87db586d0c89f7a9892ae47f421e442c64b97baebdff31788fbe23265bd", - "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-macosx_x64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-macosx_x64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-macosx_x64.tar.gz" - ] - } - }, - "remotejdk21_macos_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_macos_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos//:jdk\",\n)\n" - } - }, - "remotejdk17_macos_aarch64_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_macos_aarch64_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos_aarch64//:jdk\",\n)\n" - } - }, - "remotejdk17_win": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_win", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", - "sha256": "192f2afca57701de6ec496234f7e45d971bf623ff66b8ee4a5c81582054e5637", - "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-win_x64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_x64.zip", - "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_x64.zip" - ] - } - }, - "remotejdk11_macos_aarch64_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_macos_aarch64_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos_aarch64//:jdk\",\n)\n" - } - }, - "remotejdk11_linux_ppc64le_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_ppc64le_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_ppc64le//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_ppc64le//:jdk\",\n)\n" - } - }, - "remotejdk21_linux": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_linux", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", - "sha256": "0c0eadfbdc47a7ca64aeab51b9c061f71b6e4d25d2d87674512e9b6387e9e3a6", - "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-linux_x64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-linux_x64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-linux_x64.tar.gz" - ] - } - }, - "remote_java_tools_linux": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remote_java_tools_linux", - "sha256": "d134da9b04c9023fb6e56a5d4bffccee73f7bc9572ddc4e747778dacccd7a5a7", - "urls": [ - "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools_linux-v13.1.zip", - "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools_linux-v13.1.zip" - ] - } - }, - "remotejdk21_win": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_win", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", - "sha256": "e9959d500a0d9a7694ac243baf657761479da132f0f94720cbffd092150bd802", - "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-win_x64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-win_x64.zip", - "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-win_x64.zip" - ] - } - }, - "remotejdk21_linux_aarch64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_linux_aarch64", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", - "sha256": "1fb64b8036c5d463d8ab59af06bf5b6b006811e6012e3b0eb6bccf57f1c55835", - "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-linux_aarch64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-linux_aarch64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-linux_aarch64.tar.gz" - ] - } - }, - "remotejdk11_linux_aarch64_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_aarch64_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_aarch64//:jdk\",\n)\n" - } - }, - "remotejdk11_linux_s390x": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_s390x", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", - "sha256": "a58fc0361966af0a5d5a31a2d8a208e3c9bb0f54f345596fd80b99ea9a39788b", - "strip_prefix": "jdk-11.0.15+10", - "urls": [ - "https://mirror.bazel.build/github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_s390x_linux_hotspot_11.0.15_10.tar.gz", - "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_s390x_linux_hotspot_11.0.15_10.tar.gz" - ] - } - }, - "remotejdk17_linux_aarch64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_aarch64", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", - "sha256": "6531cef61e416d5a7b691555c8cf2bdff689201b8a001ff45ab6740062b44313", - "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-linux_aarch64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_aarch64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_aarch64.tar.gz" - ] - } - }, - "remotejdk17_win_arm64_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_win_arm64_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win_arm64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win_arm64//:jdk\",\n)\n" - } - }, - "remotejdk11_linux": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_linux", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", - "sha256": "a34b404f87a08a61148b38e1416d837189e1df7a040d949e743633daf4695a3c", - "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-linux_x64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_x64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_x64.tar.gz" - ] - } - }, - "remotejdk11_macos_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_macos_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos//:jdk\",\n)\n" - } - }, - "remotejdk17_linux_ppc64le_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_ppc64le_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_ppc64le//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_ppc64le//:jdk\",\n)\n" - } - }, - "remotejdk17_win_arm64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_win_arm64", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", - "sha256": "6802c99eae0d788e21f52d03cab2e2b3bf42bc334ca03cbf19f71eb70ee19f85", - "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-win_aarch64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_aarch64.zip", - "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_aarch64.zip" - ] - } - }, - "remote_java_tools_darwin_arm64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remote_java_tools_darwin_arm64", - "sha256": "dab5bb87ec43e980faea6e1cec14bafb217b8e2f5346f53aa784fd715929a930", - "urls": [ - "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools_darwin_arm64-v13.1.zip", - "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools_darwin_arm64-v13.1.zip" - ] - } - }, - "remotejdk17_linux_ppc64le": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_ppc64le", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", - "sha256": "00a4c07603d0218cd678461b5b3b7e25b3253102da4022d31fc35907f21a2efd", - "strip_prefix": "jdk-17.0.8.1+1", - "urls": [ - "https://mirror.bazel.build/github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_ppc64le_linux_hotspot_17.0.8.1_1.tar.gz", - "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_ppc64le_linux_hotspot_17.0.8.1_1.tar.gz" - ] - } - }, - "remotejdk21_linux_aarch64_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_linux_aarch64_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux_aarch64//:jdk\",\n)\n" - } - }, - "remotejdk11_win_arm64_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_win_arm64_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win_arm64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win_arm64//:jdk\",\n)\n" - } - }, - "local_jdk": { - "bzlFile": "@@rules_java~7.1.0//toolchains:local_java_repository.bzl", - "ruleClassName": "_local_java_repository_rule", - "attributes": { - "name": "rules_java~7.1.0~toolchains~local_jdk", - "java_home": "", - "version": "", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = {RUNTIME_VERSION},\n)\n" - } - }, - "remote_java_tools_darwin_x86_64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remote_java_tools_darwin_x86_64", - "sha256": "0db40d8505a2b65ef0ed46e4256757807db8162f7acff16225be57c1d5726dbc", - "urls": [ - "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools_darwin_x86_64-v13.1.zip", - "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools_darwin_x86_64-v13.1.zip" - ] - } - }, - "remote_java_tools": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remote_java_tools", - "sha256": "286bdbbd66e616fc4ed3f90101418729a73baa7e8c23a98ffbef558f74c0ad14", - "urls": [ - "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools-v13.1.zip", - "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools-v13.1.zip" - ] - } - }, - "remotejdk17_linux_s390x": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_s390x", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", - "sha256": "ffacba69c6843d7ca70d572489d6cc7ab7ae52c60f0852cedf4cf0d248b6fc37", - "strip_prefix": "jdk-17.0.8.1+1", - "urls": [ - "https://mirror.bazel.build/github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_s390x_linux_hotspot_17.0.8.1_1.tar.gz", - "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_s390x_linux_hotspot_17.0.8.1_1.tar.gz" - ] - } - }, - "remotejdk17_win_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_win_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win//:jdk\",\n)\n" - } - }, - "remotejdk11_linux_ppc64le": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_ppc64le", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", - "sha256": "a8fba686f6eb8ae1d1a9566821dbd5a85a1108b96ad857fdbac5c1e4649fc56f", - "strip_prefix": "jdk-11.0.15+10", - "urls": [ - "https://mirror.bazel.build/github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_ppc64le_linux_hotspot_11.0.15_10.tar.gz", - "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_ppc64le_linux_hotspot_11.0.15_10.tar.gz" - ] - } - }, - "remotejdk11_macos_aarch64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_macos_aarch64", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", - "sha256": "7632bc29f8a4b7d492b93f3bc75a7b61630894db85d136456035ab2a24d38885", - "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-macosx_aarch64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_aarch64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_aarch64.tar.gz" - ] - } - }, - "remotejdk21_win_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_win_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_win//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_win//:jdk\",\n)\n" - } + "host_platform": { + "bzlFile": "@@platforms//host:extension.bzl", + "ruleClassName": "host_platform_repo", + "attributes": {} } - } + }, + "recordedRepoMappingEntries": [] } } } diff --git a/third_party/jpeg-xl/README.md b/third_party/jpeg-xl/README.md index bcea13ff23b31..877eabac8f94d 100644 --- a/third_party/jpeg-xl/README.md +++ b/third_party/jpeg-xl/README.md @@ -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 diff --git a/third_party/jpeg-xl/WORKSPACE b/third_party/jpeg-xl/WORKSPACE index 2d8c24b5bda35..d8cd9a7495762 100644 --- a/third_party/jpeg-xl/WORKSPACE +++ b/third_party/jpeg-xl/WORKSPACE @@ -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", -) diff --git a/third_party/jpeg-xl/bash_test.sh b/third_party/jpeg-xl/bash_test.sh index 9bd28f413b9b9..9472c85970bf6 100755 --- a/third_party/jpeg-xl/bash_test.sh +++ b/third_party/jpeg-xl/bash_test.sh @@ -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 diff --git a/third_party/jpeg-xl/ci.sh b/third_party/jpeg-xl/ci.sh index f33efd9693ff3..a2ad829cb7371 100755 --- a/third_party/jpeg-xl/ci.sh +++ b/third_party/jpeg-xl/ci.sh @@ -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 diff --git a/third_party/jpeg-xl/cmake/FindHWY.cmake b/third_party/jpeg-xl/cmake/FindHWY.cmake index c5a90fbc81e81..eab306a8b7826 100644 --- a/third_party/jpeg-xl/cmake/FindHWY.cmake +++ b/third_party/jpeg-xl/cmake/FindHWY.cmake @@ -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) diff --git a/third_party/jpeg-xl/debian/changelog b/third_party/jpeg-xl/debian/changelog index b4bd9b02b3cbb..06ae73f7921e7 100644 --- a/third_party/jpeg-xl/debian/changelog +++ b/third_party/jpeg-xl/debian/changelog @@ -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 Thu, 27 Jun 2024 12:23:45 +0200 + -- JPEG XL Maintainers Tue, 06 Aug 2024 14:35:34 +0200 jpeg-xl (0.10.2) unstable; urgency=medium diff --git a/third_party/jpeg-xl/debian/control b/third_party/jpeg-xl/debian/control index f5dc5ce0cc058..e0169a3488474 100644 --- a/third_party/jpeg-xl/debian/control +++ b/third_party/jpeg-xl/debian/control @@ -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), diff --git a/third_party/jpeg-xl/deps.sh b/third_party/jpeg-xl/deps.sh index 6c51a5cd4a21d..069c721de1500 100755 --- a/third_party/jpeg-xl/deps.sh +++ b/third_party/jpeg-xl/deps.sh @@ -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 \ diff --git a/third_party/jpeg-xl/examples/CMakeLists.txt b/third_party/jpeg-xl/examples/CMakeLists.txt index 8cdb09217e791..6b2b99c12459b 100644 --- a/third_party/jpeg-xl/examples/CMakeLists.txt +++ b/third_party/jpeg-xl/examples/CMakeLists.txt @@ -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) diff --git a/third_party/jpeg-xl/examples/decode_exif_metadata.cc b/third_party/jpeg-xl/examples/decode_exif_metadata.cc index d5f11705bd046..c1609edde326a 100644 --- a/third_party/jpeg-xl/examples/decode_exif_metadata.cc +++ b/third_party/jpeg-xl/examples/decode_exif_metadata.cc @@ -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* 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); diff --git a/third_party/jpeg-xl/examples/decode_oneshot.cc b/third_party/jpeg-xl/examples/decode_oneshot.cc index a24bd73bfbd12..b7e17c21a497a 100644 --- a/third_party/jpeg-xl/examples/decode_oneshot.cc +++ b/third_party/jpeg-xl/examples/decode_oneshot.cc @@ -169,7 +169,7 @@ bool LoadFile(const char* filename, std::vector* 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); diff --git a/third_party/jpeg-xl/examples/decode_progressive.cc b/third_party/jpeg-xl/examples/decode_progressive.cc index fa7f3df663428..7a3a9aa33b702 100644 --- a/third_party/jpeg-xl/examples/decode_progressive.cc +++ b/third_party/jpeg-xl/examples/decode_progressive.cc @@ -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 +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + #include #include #include #include #include -#include -#include -#include +#include // PRIu64 +#include +#include +#include #include 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* 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; diff --git a/third_party/jpeg-xl/examples/encode_oneshot.cc b/third_party/jpeg-xl/examples/encode_oneshot.cc index 1582570432c44..6c45a70411e63 100644 --- a/third_party/jpeg-xl/examples/encode_oneshot.cc +++ b/third_party/jpeg-xl/examples/encode_oneshot.cc @@ -48,7 +48,7 @@ bool ReadPFM(const char* filename, std::vector* 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* pixels, uint32_t* xsize, data.resize(size); size_t readsize = fread(data.data(), 1, size, file); - if (static_cast(readsize) != size) { + if (static_cast(readsize) != size) { // NOLINT fclose(file); return false; } diff --git a/third_party/jpeg-xl/examples/examples.cmake b/third_party/jpeg-xl/examples/examples.cmake index fd159578bce1a..b13731ca3c1eb 100644 --- a/third_party/jpeg-xl/examples/examples.cmake +++ b/third_party/jpeg-xl/examples/examples.cmake @@ -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) diff --git a/third_party/jpeg-xl/flake.nix b/third_party/jpeg-xl/flake.nix index 4832f5b144ad8..64a36311ab13b 100644 --- a/third_party/jpeg-xl/flake.nix +++ b/third_party/jpeg-xl/flake.nix @@ -19,7 +19,6 @@ cmake pkg-config gtest - gmock doxygen graphviz python3 diff --git a/third_party/jpeg-xl/lib/BUILD b/third_party/jpeg-xl/lib/BUILD index 1c08b11c3635c..3d48919f7775e 100644 --- a/third_party/jpeg-xl/lib/BUILD +++ b/third_party/jpeg-xl/lib/BUILD @@ -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"]) diff --git a/third_party/jpeg-xl/lib/CMakeLists.txt b/third_party/jpeg-xl/lib/CMakeLists.txt index 0f5c7c81797b5..8dff542f1f01e 100644 --- a/third_party/jpeg-xl/lib/CMakeLists.txt +++ b/third_party/jpeg-xl/lib/CMakeLists.txt @@ -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}") diff --git a/third_party/jpeg-xl/lib/extras/alpha_blend.cc b/third_party/jpeg-xl/lib/extras/alpha_blend.cc index eca5f5dd69d46..8e34d56cecbb9 100644 --- a/third_party/jpeg-xl/lib/extras/alpha_blend.cc +++ b/third_party/jpeg-xl/lib/extras/alpha_blend.cc @@ -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 diff --git a/third_party/jpeg-xl/lib/extras/alpha_blend.h b/third_party/jpeg-xl/lib/extras/alpha_blend.h index e49349393c97c..b388a5e22aa48 100644 --- a/third_party/jpeg-xl/lib/extras/alpha_blend.h +++ b/third_party/jpeg-xl/lib/extras/alpha_blend.h @@ -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 diff --git a/third_party/jpeg-xl/lib/extras/codec.cc b/third_party/jpeg-xl/lib/extras/codec.cc index 3a1172125b83e..ba4bcfebbc475 100644 --- a/third_party/jpeg-xl/lib/extras/codec.cc +++ b/third_party/jpeg-xl/lib/extras/codec.cc @@ -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; diff --git a/third_party/jpeg-xl/lib/extras/codec_test.cc b/third_party/jpeg-xl/lib/extras/codec_test.cc index c97e1b1d8c230..6cbed220975ef 100644 --- a/third_party/jpeg-xl/lib/extras/codec_test.cc +++ b/third_party/jpeg-xl/lib/extras/codec_test.cc @@ -7,11 +7,12 @@ #include #include #include -#include #include +#include #include #include +#include #include #include #include @@ -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 MakeSpan(const char* str) { + return Bytes(reinterpret_cast(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 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 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()), diff --git a/third_party/jpeg-xl/lib/extras/common.cc b/third_party/jpeg-xl/lib/extras/common.cc index e85b43a49800a..56abd13ea6699 100644 --- a/third_party/jpeg-xl/lib/extras/common.cc +++ b/third_party/jpeg-xl/lib/extras/common.cc @@ -27,6 +27,7 @@ Status SelectFormat(const std::vector& 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 ( diff --git a/third_party/jpeg-xl/lib/extras/compressed_icc.cc b/third_party/jpeg-xl/lib/extras/compressed_icc.cc new file mode 100644 index 0000000000000..52d433d4f9d30 --- /dev/null +++ b/third_party/jpeg-xl/lib/extras/compressed_icc.cc @@ -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 + +#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(icc, icc_size), + &writer, jxl::LayerType::Header, nullptr)); + writer.ZeroPadToByte(); + jxl::Bytes bytes = writer.GetSpan(); + *compressed_icc_size = bytes.size(); + *compressed_icc = static_cast( + 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(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( + jxl::MemoryManagerAlloc(&local_memory_manager, *icc_size)); + memcpy(*icc, decompressed.data(), *icc_size); + return JXL_TRUE; +} diff --git a/third_party/jpeg-xl/lib/extras/compressed_icc_test.cc b/third_party/jpeg-xl/lib/extras/compressed_icc_test.cc new file mode 100644 index 0000000000000..2aa994d6e69e8 --- /dev/null +++ b/third_party/jpeg-xl/lib/extras/compressed_icc_test.cc @@ -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 + +#include +#include +#include + +#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 diff --git a/third_party/jpeg-xl/lib/extras/dec/apng.cc b/third_party/jpeg-xl/lib/extras/dec/apng.cc index 46508ac683652..24b4795d03dc6 100644 --- a/third_party/jpeg-xl/lib/extras/dec/apng.cc +++ b/third_party/jpeg-xl/lib/extras/dec/apng.cc @@ -38,19 +38,27 @@ #include #include -#include +#include +#include +#include +#include +#include +#include #include #include #include +#include "lib/extras/packed_image.h" #include "lib/extras/size_constraints.h" #include "lib/jxl/base/byte_order.h" #include "lib/jxl/base/common.h" #include "lib/jxl/base/compiler_specific.h" #include "lib/jxl/base/printf_macros.h" -#include "lib/jxl/base/scope_guard.h" -#include "lib/jxl/sanitizers.h" +#include "lib/jxl/base/rect.h" +#include "lib/jxl/base/sanitizers.h" +#include "lib/jxl/base/span.h" +#include "lib/jxl/base/status.h" #if JPEGXL_ENABLE_APNG #include "png.h" /* original (unpatched) libpng is ok */ #endif @@ -58,39 +66,46 @@ namespace jxl { namespace extras { -#if JPEGXL_ENABLE_APNG -namespace { +#if !JPEGXL_ENABLE_APNG -constexpr unsigned char kExifSignature[6] = {0x45, 0x78, 0x69, - 0x66, 0x00, 0x00}; +bool CanDecodeAPNG() { return false; } +Status DecodeImageAPNG(const Span bytes, + const ColorHints& color_hints, PackedPixelFile* ppf, + const SizeConstraints* constraints) { + return false; +} -/* hIST chunk tail is not proccesed properly; skip this chunk completely; - see https://github.com/glennrp/libpng/pull/413 */ -const png_byte kIgnoredPngChunks[] = { - 104, 73, 83, 84, '\0' /* hIST */ -}; +#else // JPEGXL_ENABLE_APNG + +namespace { + +constexpr std::array kPngSignature = {137, 'P', 'N', 'G', + '\r', '\n', 26, '\n'}; // Returns floating-point value from the PNG encoding (times 10^5). double F64FromU32(const uint32_t x) { return static_cast(x) * 1E-5; } -Status DecodeSRGB(const unsigned char* payload, const size_t payload_size, - JxlColorEncoding* color_encoding) { - if (payload_size != 1) return JXL_FAILURE("Wrong sRGB size"); +/** Extract information from 'sRGB' chunk. */ +Status DecodeSrgbChunk(const Bytes payload, JxlColorEncoding* color_encoding) { + if (payload.size() != 1) return JXL_FAILURE("Wrong sRGB size"); + uint8_t ri = payload[0]; // (PNG uses the same values as ICC.) - if (payload[0] >= 4) return JXL_FAILURE("Invalid Rendering Intent"); + if (ri >= 4) return JXL_FAILURE("Invalid Rendering Intent"); color_encoding->white_point = JXL_WHITE_POINT_D65; color_encoding->primaries = JXL_PRIMARIES_SRGB; color_encoding->transfer_function = JXL_TRANSFER_FUNCTION_SRGB; - color_encoding->rendering_intent = - static_cast(payload[0]); + color_encoding->rendering_intent = static_cast(ri); return true; } -// If the cICP profile is not fully supported, return false and leave -// color_encoding unmodified. -Status DecodeCICP(const unsigned char* payload, const size_t payload_size, - JxlColorEncoding* color_encoding) { - if (payload_size != 4) return JXL_FAILURE("Wrong cICP size"); +/** + * Extract information from 'cICP' chunk. + * + * If the cICP profile is not fully supported, return `false` and leave + * `color_encoding` unmodified. + */ +Status DecodeCicpChunk(const Bytes payload, JxlColorEncoding* color_encoding) { + if (payload.size() != 4) return JXL_FAILURE("Wrong cICP size"); JxlColorEncoding color_enc = *color_encoding; // From https://www.itu.int/rec/T-REC-H.273-202107-I/en @@ -217,242 +232,294 @@ Status DecodeCICP(const unsigned char* payload, const size_t payload_size, return true; } -Status DecodeGAMA(const unsigned char* payload, const size_t payload_size, - JxlColorEncoding* color_encoding) { - if (payload_size != 4) return JXL_FAILURE("Wrong gAMA size"); +/** Extract information from 'gAMA' chunk. */ +Status DecodeGamaChunk(Bytes payload, JxlColorEncoding* color_encoding) { + if (payload.size() != 4) return JXL_FAILURE("Wrong gAMA size"); color_encoding->transfer_function = JXL_TRANSFER_FUNCTION_GAMMA; - color_encoding->gamma = F64FromU32(LoadBE32(payload)); + color_encoding->gamma = F64FromU32(LoadBE32(payload.data())); return true; } -Status DecodeCHRM(const unsigned char* payload, const size_t payload_size, - JxlColorEncoding* color_encoding) { - if (payload_size != 32) return JXL_FAILURE("Wrong cHRM size"); - +/** Extract information from 'cHTM' chunk. */ +Status DecodeChrmChunk(Bytes payload, JxlColorEncoding* color_encoding) { + if (payload.size() != 32) return JXL_FAILURE("Wrong cHRM size"); + const uint8_t* data = payload.data(); color_encoding->white_point = JXL_WHITE_POINT_CUSTOM; - color_encoding->white_point_xy[0] = F64FromU32(LoadBE32(payload + 0)); - color_encoding->white_point_xy[1] = F64FromU32(LoadBE32(payload + 4)); + color_encoding->white_point_xy[0] = F64FromU32(LoadBE32(data + 0)); + color_encoding->white_point_xy[1] = F64FromU32(LoadBE32(data + 4)); color_encoding->primaries = JXL_PRIMARIES_CUSTOM; - color_encoding->primaries_red_xy[0] = F64FromU32(LoadBE32(payload + 8)); - color_encoding->primaries_red_xy[1] = F64FromU32(LoadBE32(payload + 12)); - color_encoding->primaries_green_xy[0] = F64FromU32(LoadBE32(payload + 16)); - color_encoding->primaries_green_xy[1] = F64FromU32(LoadBE32(payload + 20)); - color_encoding->primaries_blue_xy[0] = F64FromU32(LoadBE32(payload + 24)); - color_encoding->primaries_blue_xy[1] = F64FromU32(LoadBE32(payload + 28)); + color_encoding->primaries_red_xy[0] = F64FromU32(LoadBE32(data + 8)); + color_encoding->primaries_red_xy[1] = F64FromU32(LoadBE32(data + 12)); + color_encoding->primaries_green_xy[0] = F64FromU32(LoadBE32(data + 16)); + color_encoding->primaries_green_xy[1] = F64FromU32(LoadBE32(data + 20)); + color_encoding->primaries_blue_xy[0] = F64FromU32(LoadBE32(data + 24)); + color_encoding->primaries_blue_xy[1] = F64FromU32(LoadBE32(data + 28)); return true; } -// Retrieves XMP and EXIF/IPTC from itext and text. -class BlobsReaderPNG { - public: - static Status Decode(const png_text_struct& info, PackedMetadata* metadata) { - // We trust these are properly null-terminated by libpng. - const char* key = info.key; - const char* value = info.text; - if (strstr(key, "XML:com.adobe.xmp")) { - metadata->xmp.resize(strlen(value)); // safe, see above - memcpy(metadata->xmp.data(), value, metadata->xmp.size()); - } - - std::string type; - std::vector bytes; +/** Extracts information from 'cLLi' chunk. */ +Status DecodeClliChunk(Bytes payload, float* max_content_light_level) { + if (payload.size() != 8) return JXL_FAILURE("Wrong cLLi size"); + const uint8_t* data = payload.data(); + const uint32_t maxcll_png = + Clamp1(png_get_uint_32(data), uint32_t{0}, uint32_t{10000 * 10000}); + // Ignore MaxFALL value. + *max_content_light_level = static_cast(maxcll_png) / 10000.f; + return true; +} - // Handle text chunks annotated with key "Raw profile type ####", with - // #### a type, which may contain metadata. - const char* kKey = "Raw profile type "; - if (strncmp(key, kKey, strlen(kKey)) != 0) return false; +/** Returns false if invalid. */ +JXL_INLINE Status DecodeHexNibble(const char c, uint32_t* JXL_RESTRICT nibble) { + if ('a' <= c && c <= 'f') { + *nibble = 10 + c - 'a'; + } else if ('0' <= c && c <= '9') { + *nibble = c - '0'; + } else { + *nibble = 0; + return JXL_FAILURE("Invalid metadata nibble"); + } + JXL_ENSURE(*nibble < 16); + return true; +} - if (!MaybeDecodeBase16(key, value, &type, &bytes)) { - JXL_WARNING("Couldn't parse 'Raw format type' text chunk"); - return false; - } - if (type == "exif") { - // Remove "Exif\0\0" prefix if present - if (bytes.size() >= sizeof kExifSignature && - memcmp(bytes.data(), kExifSignature, sizeof kExifSignature) == 0) { - bytes.erase(bytes.begin(), bytes.begin() + sizeof kExifSignature); - } - if (!metadata->exif.empty()) { - JXL_WARNING("overwriting EXIF (%" PRIuS " bytes) with base16 (%" PRIuS - " bytes)", - metadata->exif.size(), bytes.size()); - } - metadata->exif = std::move(bytes); - } else if (type == "iptc") { - // TODO(jon): Deal with IPTC in some way - } else if (type == "8bim") { - // TODO(jon): Deal with 8bim in some way - } else if (type == "xmp") { - if (!metadata->xmp.empty()) { - JXL_WARNING("overwriting XMP (%" PRIuS " bytes) with base16 (%" PRIuS - " bytes)", - metadata->xmp.size(), bytes.size()); +/** Returns false if invalid. */ +JXL_INLINE Status DecodeDecimal(const char** pos, const char* end, + uint32_t* JXL_RESTRICT value) { + size_t len = 0; + *value = 0; + while (*pos < end) { + char next = **pos; + if (next >= '0' && next <= '9') { + *value = (*value * 10) + static_cast(next - '0'); + len++; + if (len > 8) { + break; } - metadata->xmp = std::move(bytes); } else { - JXL_WARNING("Unknown type in 'Raw format type' text chunk: %s: %" PRIuS - " bytes", - type.c_str(), bytes.size()); + // Do not consume terminator (non-decimal digit). + break; } - return true; + (*pos)++; } + if (len == 0 || len > 8) { + return JXL_FAILURE("Failed to parse decimal"); + } + return true; +} - private: - // Returns false if invalid. - static JXL_INLINE Status DecodeNibble(const char c, - uint32_t* JXL_RESTRICT nibble) { - if ('a' <= c && c <= 'f') { - *nibble = 10 + c - 'a'; - } else if ('0' <= c && c <= '9') { - *nibble = c - '0'; - } else { - *nibble = 0; - return JXL_FAILURE("Invalid metadata nibble"); +/** + * Parses a PNG text chunk with key of the form "Raw profile type ####", with + * #### a type. + * + * Returns whether it could successfully parse the content. + * We trust key and encoded are null-terminated because they come from + * libpng. + */ +Status MaybeDecodeBase16(const char* key, const char* encoded, + std::string* type, std::vector* bytes) { + const char* encoded_end = encoded + strlen(encoded); + + const char* kKey = "Raw profile type "; + if (strncmp(key, kKey, strlen(kKey)) != 0) return false; + *type = key + strlen(kKey); + const size_t kMaxTypeLen = 20; + if (type->length() > kMaxTypeLen) return false; // Type too long + + // Header: freeform string and number of bytes + // Expected format is: + // \n + // profile name/description\n + // 40\n (the number of bytes after hex-decoding) + // 01234566789abcdef....\n (72 bytes per line max). + // 012345667\n (last line) + const char* pos = encoded; + + if (*(pos++) != '\n') return false; + while (pos < encoded_end && *pos != '\n') { + pos++; + } + if (pos == encoded_end) return false; + // We parsed so far a \n, some number of non \n characters and are now + // pointing at a \n. + if (*(pos++) != '\n') return false; + // Skip leading spaces + while (pos < encoded_end && *pos == ' ') { + pos++; + } + uint32_t bytes_to_decode = 0; + JXL_RETURN_IF_ERROR(DecodeDecimal(&pos, encoded_end, &bytes_to_decode)); + + // We need 2*bytes for the hex values plus 1 byte every 36 values, + // plus terminal \n for length. + size_t tail = static_cast(encoded_end - pos); + bool ok = ((tail / 2) >= bytes_to_decode); + if (ok) tail -= 2 * static_cast(bytes_to_decode); + ok = ok && (tail == 1 + DivCeil(bytes_to_decode, 36)); + if (!ok) { + return JXL_FAILURE("Not enough bytes to parse %d bytes in hex", + bytes_to_decode); + } + JXL_ENSURE(bytes->empty()); + bytes->reserve(bytes_to_decode); + + // Encoding: base16 with newline after 72 chars. + // pos points to the \n before the first line of hex values. + for (size_t i = 0; i < bytes_to_decode; ++i) { + if (i % 36 == 0) { + if (pos + 1 >= encoded_end) return false; // Truncated base16 1 + if (*pos != '\n') return false; // Expected newline + ++pos; } - JXL_ASSERT(*nibble < 16); - return true; + + if (pos + 2 >= encoded_end) return false; // Truncated base16 2; + uint32_t nibble0; + uint32_t nibble1; + JXL_RETURN_IF_ERROR(DecodeHexNibble(pos[0], &nibble0)); + JXL_RETURN_IF_ERROR(DecodeHexNibble(pos[1], &nibble1)); + bytes->push_back(static_cast((nibble0 << 4) + nibble1)); + pos += 2; } + if (pos + 1 != encoded_end) return false; // Too many encoded bytes + if (pos[0] != '\n') return false; // Incorrect metadata terminator + return true; +} - // Returns false if invalid. - static JXL_INLINE Status DecodeDecimal(const char** pos, const char* end, - uint32_t* JXL_RESTRICT value) { - size_t len = 0; - *value = 0; - while (*pos < end) { - char next = **pos; - if (next >= '0' && next <= '9') { - *value = (*value * 10) + static_cast(next - '0'); - len++; - if (len > 8) { - break; - } - } else { - // Do not consume terminator (non-decimal digit). - break; - } - (*pos)++; - } - if (len == 0 || len > 8) { - return JXL_FAILURE("Failed to parse decimal"); - } - return true; +/** Retrieves XMP and EXIF/IPTC from itext and text. */ +Status DecodeBlob(const png_text_struct& info, PackedMetadata* metadata) { + // We trust these are properly null-terminated by libpng. + const char* key = info.key; + const char* value = info.text; + if (strstr(key, "XML:com.adobe.xmp")) { + metadata->xmp.resize(strlen(value)); // safe, see above + memcpy(metadata->xmp.data(), value, metadata->xmp.size()); } - // Parses a PNG text chunk with key of the form "Raw profile type ####", with - // #### a type. - // Returns whether it could successfully parse the content. - // We trust key and encoded are null-terminated because they come from - // libpng. - static Status MaybeDecodeBase16(const char* key, const char* encoded, - std::string* type, - std::vector* bytes) { - const char* encoded_end = encoded + strlen(encoded); - - const char* kKey = "Raw profile type "; - if (strncmp(key, kKey, strlen(kKey)) != 0) return false; - *type = key + strlen(kKey); - const size_t kMaxTypeLen = 20; - if (type->length() > kMaxTypeLen) return false; // Type too long - - // Header: freeform string and number of bytes - // Expected format is: - // \n - // profile name/description\n - // 40\n (the number of bytes after hex-decoding) - // 01234566789abcdef....\n (72 bytes per line max). - // 012345667\n (last line) - const char* pos = encoded; - - if (*(pos++) != '\n') return false; - while (pos < encoded_end && *pos != '\n') { - pos++; - } - if (pos == encoded_end) return false; - // We parsed so far a \n, some number of non \n characters and are now - // pointing at a \n. - if (*(pos++) != '\n') return false; - // Skip leading spaces - while (pos < encoded_end && *pos == ' ') { - pos++; + std::string type; + std::vector bytes; + + // Handle text chunks annotated with key "Raw profile type ####", with + // #### a type, which may contain metadata. + const char* kKey = "Raw profile type "; + if (strncmp(key, kKey, strlen(kKey)) != 0) return false; + + if (!MaybeDecodeBase16(key, value, &type, &bytes)) { + JXL_WARNING("Couldn't parse 'Raw format type' text chunk"); + return false; + } + if (type == "exif") { + // Remove prefix if present. + constexpr std::array kExifPrefix = {'E', 'x', 'i', 'f', 0, 0}; + if (bytes.size() >= kExifPrefix.size() && + memcmp(bytes.data(), kExifPrefix.data(), kExifPrefix.size()) == 0) { + bytes.erase(bytes.begin(), bytes.begin() + kExifPrefix.size()); } - uint32_t bytes_to_decode = 0; - JXL_RETURN_IF_ERROR(DecodeDecimal(&pos, encoded_end, &bytes_to_decode)); - - // We need 2*bytes for the hex values plus 1 byte every 36 values, - // plus terminal \n for length. - const unsigned long needed_bytes = - bytes_to_decode * 2 + 1 + DivCeil(bytes_to_decode, 36); - if (needed_bytes != static_cast(encoded_end - pos)) { - return JXL_FAILURE("Not enough bytes to parse %d bytes in hex", - bytes_to_decode); + if (!metadata->exif.empty()) { + JXL_DEBUG_V(2, + "overwriting EXIF (%" PRIuS " bytes) with base16 (%" PRIuS + " bytes)", + metadata->exif.size(), bytes.size()); } - JXL_ASSERT(bytes->empty()); - bytes->reserve(bytes_to_decode); - - // Encoding: base16 with newline after 72 chars. - // pos points to the \n before the first line of hex values. - for (size_t i = 0; i < bytes_to_decode; ++i) { - if (i % 36 == 0) { - if (pos + 1 >= encoded_end) return false; // Truncated base16 1 - if (*pos != '\n') return false; // Expected newline - ++pos; - } - - if (pos + 2 >= encoded_end) return false; // Truncated base16 2; - uint32_t nibble0; - uint32_t nibble1; - JXL_RETURN_IF_ERROR(DecodeNibble(pos[0], &nibble0)); - JXL_RETURN_IF_ERROR(DecodeNibble(pos[1], &nibble1)); - bytes->push_back(static_cast((nibble0 << 4) + nibble1)); - pos += 2; + metadata->exif = std::move(bytes); + } else if (type == "iptc") { + // TODO(jon): Deal with IPTC in some way + } else if (type == "8bim") { + // TODO(jon): Deal with 8bim in some way + } else if (type == "xmp") { + if (!metadata->xmp.empty()) { + JXL_DEBUG_V(2, + "overwriting XMP (%" PRIuS " bytes) with base16 (%" PRIuS + " bytes)", + metadata->xmp.size(), bytes.size()); } - if (pos + 1 != encoded_end) return false; // Too many encoded bytes - if (pos[0] != '\n') return false; // Incorrect metadata terminator - return true; + metadata->xmp = std::move(bytes); + } else { + JXL_DEBUG_V( + 2, "Unknown type in 'Raw format type' text chunk: %s: %" PRIuS " bytes", + type.c_str(), bytes.size()); } -}; + return true; +} constexpr bool isAbc(char c) { return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); } -constexpr uint32_t kId_IHDR = 0x52444849; -constexpr uint32_t kId_acTL = 0x4C546361; -constexpr uint32_t kId_fcTL = 0x4C546366; -constexpr uint32_t kId_IDAT = 0x54414449; -constexpr uint32_t kId_fdAT = 0x54416466; -constexpr uint32_t kId_IEND = 0x444E4549; -constexpr uint32_t kId_cICP = 0x50434963; -constexpr uint32_t kId_iCCP = 0x50434369; -constexpr uint32_t kId_sRGB = 0x42475273; -constexpr uint32_t kId_gAMA = 0x414D4167; -constexpr uint32_t kId_cHRM = 0x4D524863; -constexpr uint32_t kId_eXIf = 0x66495865; - -struct APNGFrame { - std::vector pixels; +/** Wrap 4-char tag name into ID. */ +constexpr uint32_t MakeTag(uint8_t a, uint8_t b, uint8_t c, uint8_t d) { + return a | (b << 8) | (c << 16) | (d << 24); +} + +/** Reusable image data container. */ +struct Pixels { + // Use array instead of vector to avoid memory initialization. + std::unique_ptr pixels; + size_t pixels_size = 0; std::vector rows; - unsigned int w, h, delay_num, delay_den; + std::atomic has_error{false}; + + Status Resize(size_t row_bytes, size_t num_rows) { + size_t new_size = row_bytes * num_rows; // it is assumed size is sane + if (new_size > pixels_size) { + pixels.reset(new uint8_t[new_size]); + if (!pixels) { + // TODO(szabadka): use specialized OOM error code + return JXL_FAILURE("Failed to allocate memory for image buffer"); + } + pixels_size = new_size; + } + rows.resize(num_rows); + for (size_t y = 0; y < num_rows; y++) { + rows[y] = pixels.get() + y * row_bytes; + } + return true; + } }; +/** + * Helper that chunks in-memory input. + */ struct Reader { - const uint8_t* next; - const uint8_t* last; - bool Read(void* data, size_t len) { - size_t cap = last - next; + explicit Reader(Span data) : data_(data) {} + + const Span data_; + size_t offset_ = 0; + + Bytes Peek(size_t len) const { + size_t cap = data_.size() - offset_; size_t to_copy = std::min(cap, len); - memcpy(data, next, to_copy); - next += to_copy; - return (len == to_copy); + return {data_.data() + offset_, to_copy}; + } + + Bytes Read(size_t len) { + Bytes result = Peek(len); + offset_ += result.size(); + return result; + } + + /* Returns empty Span on error. */ + Bytes ReadChunk() { + Bytes len = Peek(4); + if (len.size() != 4) { + return Bytes(); + } + const auto size = png_get_uint_32(len.data()); + // NB: specification allows 2^31 - 1 + constexpr size_t kMaxPNGChunkSize = 1u << 30; // 1 GB + // Check first, to avoid overflow. + if (size > kMaxPNGChunkSize) { + JXL_WARNING("APNG chunk size is too big"); + return Bytes(); + } + size_t full_size = size + 12; // size does not include itself, tag and CRC. + Bytes result = Read(full_size); + return (result.size() == full_size) ? result : Bytes(); } - bool Eof() const { return next == last; } -}; -const unsigned long cMaxPNGSize = 1000000UL; -const size_t kMaxPNGChunkSize = 1lu << 30; // 1 GB + bool Eof() const { return offset_ == data_.size(); } +}; -void info_fn(png_structp png_ptr, png_infop info_ptr) { +void ProgressiveRead_OnInfo(png_structp png_ptr, png_infop info_ptr) { png_set_expand(png_ptr); png_set_palette_to_rgb(png_ptr); png_set_tRNS_to_alpha(png_ptr); @@ -460,319 +527,486 @@ void info_fn(png_structp png_ptr, png_infop info_ptr) { png_read_update_info(png_ptr, info_ptr); } -void row_fn(png_structp png_ptr, png_bytep new_row, png_uint_32 row_num, - int pass) { - APNGFrame* frame = - reinterpret_cast(png_get_progressive_ptr(png_ptr)); - JXL_CHECK(frame); - JXL_CHECK(row_num < frame->rows.size()); - JXL_CHECK(frame->rows[row_num] < frame->pixels.data() + frame->pixels.size()); +void ProgressiveRead_OnRow(png_structp png_ptr, png_bytep new_row, + png_uint_32 row_num, int pass) { + Pixels* frame = reinterpret_cast(png_get_progressive_ptr(png_ptr)); + if (!frame) { + JXL_DEBUG_ABORT("Internal logic error"); + return; + } + if (row_num >= frame->rows.size()) { + frame->has_error = true; + return; + } png_progressive_combine_row(png_ptr, frame->rows[row_num], new_row); } -inline unsigned int read_chunk(Reader* r, std::vector* pChunk) { - unsigned char len[4]; - if (r->Read(&len, 4)) { - const auto size = png_get_uint_32(len); - // Check first, to avoid overflow. - if (size > kMaxPNGChunkSize) { - JXL_WARNING("APNG chunk size is too big"); - return 0; - } - pChunk->resize(size + 12); - memcpy(pChunk->data(), len, 4); - if (r->Read(pChunk->data() + 4, pChunk->size() - 4)) { - return LoadLE32(pChunk->data() + 4); - } +// Holds intermediate state during parsing APNG file. +struct Context { + ~Context() { + // Make sure png memory is released in any case. + ResetPngDecoder(); } - return 0; -} -int processing_start(png_structp& png_ptr, png_infop& info_ptr, void* frame_ptr, - bool hasInfo, std::vector& chunkIHDR, - std::vector>& chunksInfo) { - unsigned char header[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + bool CreatePngDecoder() { + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, + nullptr); + info_ptr = png_create_info_struct(png_ptr); + return (png_ptr != nullptr && info_ptr != nullptr); + } - // Cleanup prior decoder, if any. - png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); - // Just in case. Not all versions on libpng wipe-out the pointers. - png_ptr = nullptr; - info_ptr = nullptr; + /** + * Initialize PNG decoder. + * + * TODO(eustas): add details + */ + bool InitPngDecoder(const std::vector& chunksInfo, + const RectT& viewport) { + ResetPngDecoder(); + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, + nullptr); + info_ptr = png_create_info_struct(png_ptr); + if (png_ptr == nullptr || info_ptr == nullptr) { + return false; + } - png_ptr = - png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); - info_ptr = png_create_info_struct(png_ptr); - if (!png_ptr || !info_ptr) return 1; + if (setjmp(png_jmpbuf(png_ptr))) { + return false; + } - if (setjmp(png_jmpbuf(png_ptr))) { - return 1; - } + /* hIST chunk tail is not processed properly; skip this chunk completely; + see https://github.com/glennrp/libpng/pull/413 */ + constexpr std::array kIgnoredChunks = {'h', 'I', 'S', 'T', 0}; + png_set_keep_unknown_chunks(png_ptr, 1, kIgnoredChunks.data(), + static_cast(kIgnoredChunks.size() / 5)); + + png_set_crc_action(png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE); + png_set_progressive_read_fn(png_ptr, static_cast(&frameRaw), + ProgressiveRead_OnInfo, ProgressiveRead_OnRow, + nullptr); + + png_process_data(png_ptr, info_ptr, + const_cast(kPngSignature.data()), + kPngSignature.size()); + + // Patch dimensions. + png_save_uint_32(ihdr.data() + 8, static_cast(viewport.xsize())); + png_save_uint_32(ihdr.data() + 12, static_cast(viewport.ysize())); + png_process_data(png_ptr, info_ptr, ihdr.data(), ihdr.size()); + + for (const auto& chunk : chunksInfo) { + png_process_data(png_ptr, info_ptr, const_cast(chunk.data()), + chunk.size()); + } - png_set_keep_unknown_chunks(png_ptr, 1, kIgnoredPngChunks, - static_cast(sizeof(kIgnoredPngChunks) / 5)); + return true; + } - png_set_crc_action(png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE); - png_set_progressive_read_fn(png_ptr, frame_ptr, info_fn, row_fn, nullptr); + /** + * Pass chunk to PNG decoder. + */ + bool FeedChunks(const Bytes& chunk1, const Bytes& chunk2 = Bytes()) { + // TODO(eustas): turn to DCHECK + if (!png_ptr || !info_ptr) return false; - png_process_data(png_ptr, info_ptr, header, 8); - png_process_data(png_ptr, info_ptr, chunkIHDR.data(), chunkIHDR.size()); + if (setjmp(png_jmpbuf(png_ptr))) { + return false; + } - if (hasInfo) { - for (auto& chunk : chunksInfo) { - png_process_data(png_ptr, info_ptr, chunk.data(), chunk.size()); + for (const auto& chunk : {chunk1, chunk2}) { + if (!chunk.empty()) { + png_process_data(png_ptr, info_ptr, const_cast(chunk.data()), + chunk.size()); + } } + return true; } - return 0; -} -int processing_data(png_structp png_ptr, png_infop info_ptr, unsigned char* p, - unsigned int size) { - if (!png_ptr || !info_ptr) return 1; + bool FinalizeStream(PackedMetadata* metadata) { + // TODO(eustas): turn to DCHECK + if (!png_ptr || !info_ptr) return false; + + if (setjmp(png_jmpbuf(png_ptr))) { + return false; + } + + const std::array kFooter = {0, 0, 0, 0, 73, 69, + 78, 68, 174, 66, 96, 130}; + png_process_data(png_ptr, info_ptr, const_cast(kFooter.data()), + kFooter.size()); + // before destroying: check if we encountered any metadata chunks + png_textp text_ptr = nullptr; + int num_text = 0; + if (png_get_text(png_ptr, info_ptr, &text_ptr, &num_text) != 0) { + msan::UnpoisonMemory(text_ptr, sizeof(png_text_struct) * num_text); + for (int i = 0; i < num_text; i++) { + Status result = DecodeBlob(text_ptr[i], metadata); + // Ignore unknown / malformed blob. + (void)result; + } + } - if (setjmp(png_jmpbuf(png_ptr))) { - return 1; + return true; } - png_process_data(png_ptr, info_ptr, p, size); - return 0; -} + void ResetPngDecoder() { + png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); + // Just in case. Not all versions on libpng wipe-out the pointers. + png_ptr = nullptr; + info_ptr = nullptr; + } -int processing_finish(png_structp png_ptr, png_infop info_ptr, - PackedMetadata* metadata) { - unsigned char footer[12] = {0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130}; + std::array ihdr; // (modified) copy of file IHDR chunk + png_structp png_ptr = nullptr; + png_infop info_ptr = nullptr; + Pixels frameRaw = {}; +}; - if (!png_ptr || !info_ptr) return 1; +enum class DisposeOp : uint8_t { NONE = 0, BACKGROUND = 1, PREVIOUS = 2 }; - if (setjmp(png_jmpbuf(png_ptr))) { - return 1; - } +constexpr uint8_t kLastDisposeOp = static_cast(DisposeOp::PREVIOUS); - png_process_data(png_ptr, info_ptr, footer, 12); - // before destroying: check if we encountered any metadata chunks - png_textp text_ptr; - int num_text; - png_get_text(png_ptr, info_ptr, &text_ptr, &num_text); - for (int i = 0; i < num_text; i++) { - (void)BlobsReaderPNG::Decode(text_ptr[i], metadata); +enum class BlendOp : uint8_t { SOURCE = 0, OVER = 1 }; + +constexpr uint8_t kLastBlendOp = static_cast(BlendOp::OVER); + +// fcTL +struct FrameControl { + uint32_t delay_num; + uint32_t delay_den; + RectT viewport; + DisposeOp dispose_op; + BlendOp blend_op; +}; + +struct Frame { + PackedImage pixels; + FrameControl metadata; +}; + +bool ValidateViewport(const RectT& r) { + constexpr uint32_t kMaxPngDim = 1000000UL; + return (r.xsize() <= kMaxPngDim) && (r.ysize() <= kMaxPngDim); +} + +/** + * Setup #channels, bpp, colorspace, etc. from PNG values. + */ +void SetColorData(PackedPixelFile* ppf, uint8_t color_type, uint8_t bit_depth, + png_color_8p sig_bits, uint32_t has_transparency) { + bool palette_used = ((color_type & 1) != 0); + bool color_used = ((color_type & 2) != 0); + bool alpha_channel_used = ((color_type & 4) != 0); + if (palette_used) { + if (!color_used || alpha_channel_used) { + JXL_DEBUG_V(2, "Unexpected PNG color type"); + } } - return 0; + ppf->info.bits_per_sample = bit_depth; + + if (palette_used) { + // palette will actually be 8-bit regardless of the index bitdepth + ppf->info.bits_per_sample = 8; + } + if (color_used) { + ppf->info.num_color_channels = 3; + ppf->color_encoding.color_space = JXL_COLOR_SPACE_RGB; + if (sig_bits) { + if (sig_bits->red == sig_bits->green && + sig_bits->green == sig_bits->blue) { + ppf->info.bits_per_sample = sig_bits->red; + } else { + int maxbps = + std::max(sig_bits->red, std::max(sig_bits->green, sig_bits->blue)); + JXL_DEBUG_V(2, + "sBIT chunk: bit depths for R, G, and B are not the same " + "(%i %i %i), while in JPEG XL they have to be the same. " + "Setting RGB bit depth to %i.", + sig_bits->red, sig_bits->green, sig_bits->blue, maxbps); + ppf->info.bits_per_sample = maxbps; + } + } + } else { + ppf->info.num_color_channels = 1; + ppf->color_encoding.color_space = JXL_COLOR_SPACE_GRAY; + if (sig_bits) ppf->info.bits_per_sample = sig_bits->gray; + } + if (alpha_channel_used || has_transparency) { + ppf->info.alpha_bits = ppf->info.bits_per_sample; + if (sig_bits && sig_bits->alpha != ppf->info.bits_per_sample) { + JXL_DEBUG_V(2, + "sBIT chunk: bit depths for RGBA are inconsistent " + "(%i %i %i %i). Setting A bitdepth to %i.", + sig_bits->red, sig_bits->green, sig_bits->blue, + sig_bits->alpha, ppf->info.bits_per_sample); + } + } else { + ppf->info.alpha_bits = 0; + } + ppf->color_encoding.color_space = (ppf->info.num_color_channels == 1) + ? JXL_COLOR_SPACE_GRAY + : JXL_COLOR_SPACE_RGB; } +// Color profile chunks: cICP has the highest priority, followed by +// iCCP and sRGB (which shouldn't co-exist, but if they do, we use +// iCCP), followed finally by gAMA and cHRM. +enum class ColorInfoType { + NONE = 0, + GAMA_OR_CHRM = 1, + ICCP_OR_SRGB = 2, + CICP = 3 +}; + } // namespace -#endif -bool CanDecodeAPNG() { -#if JPEGXL_ENABLE_APNG - return true; -#else - return false; -#endif -} +bool CanDecodeAPNG() { return true; } +/** + * Parse and decode PNG file. + * + * Useful PNG chunks: + * acTL : animation control (#frames, loop count) + * fcTL : frame control (seq#, viewport, delay, disposal blending) + * bKGD : preferable background + * IDAT : "default image" + * if single fcTL goes before IDAT, then it is also first frame + * fdAT : seq# + IDAT-like content + * PLTE : palette + * cICP : coding-independent code points for video signal type identification + * iCCP : embedded ICC profile + * sRGB : standard RGB colour space + * eXIf : exchangeable image file profile + * gAMA : image gamma + * cHRM : primary chromaticities and white point + * tRNS : transparency + * + * PNG chunk ordering: + * - IHDR first + * - IEND last + * - acTL, cHRM, cICP, gAMA, iCCP, sRGB, bKGD, eXIf, PLTE before IDAT + * - fdAT after IDAT + * + * More rules: + * - iCCP and sRGB are exclusive + * - fcTL and fdAT seq# must be in order fro 0, with no gaps or duplicates + * - fcTL before corresponding IDAT / fdAT + */ Status DecodeImageAPNG(const Span bytes, const ColorHints& color_hints, PackedPixelFile* ppf, const SizeConstraints* constraints) { -#if JPEGXL_ENABLE_APNG - Reader r; - unsigned char sig[8]; - png_structp png_ptr = nullptr; - png_infop info_ptr = nullptr; - std::vector chunk; - std::vector chunkIHDR; - std::vector> chunksInfo; - bool isAnimated = false; - bool hasInfo = false; - bool seenFctl = false; - APNGFrame frameRaw = {}; - uint32_t num_channels; - JxlPixelFormat format; - unsigned int bytes_per_pixel = 0; - - struct FrameInfo { - PackedImage data; - uint32_t duration; - size_t x0, xsize; - size_t y0, ysize; - uint32_t dispose_op; - uint32_t blend_op; - }; - - std::vector frames; + // Initialize output (default settings in case e.g. only gAMA is given). + ppf->frames.clear(); + ppf->info.exponent_bits_per_sample = 0; + ppf->info.alpha_exponent_bits = 0; + ppf->info.orientation = JXL_ORIENT_IDENTITY; + ppf->color_encoding.color_space = JXL_COLOR_SPACE_RGB; + ppf->color_encoding.white_point = JXL_WHITE_POINT_D65; + ppf->color_encoding.primaries = JXL_PRIMARIES_SRGB; + ppf->color_encoding.transfer_function = JXL_TRANSFER_FUNCTION_SRGB; + ppf->color_encoding.rendering_intent = JXL_RENDERING_INTENT_RELATIVE; + + Reader input(bytes); + + // Check signature. + Bytes sig = input.Read(kPngSignature.size()); + if (sig.size() != 8 || + memcmp(sig.data(), kPngSignature.data(), kPngSignature.size()) != 0) { + return false; // Return silently if it is not a PNG + } - // Make sure png memory is released in any case. - auto scope_guard = MakeScopeGuard([&]() { - png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); - // Just in case. Not all versions on libpng wipe-out the pointers. - png_ptr = nullptr; - info_ptr = nullptr; - }); + // Check IHDR chunk. + Context ctx; + Bytes ihdr = input.ReadChunk(); + if (ihdr.size() != ctx.ihdr.size()) { + return JXL_FAILURE("Unexpected first chunk payload size"); + } + memcpy(ctx.ihdr.data(), ihdr.data(), ihdr.size()); + uint32_t id = LoadLE32(ihdr.data() + 4); + if (id != MakeTag('I', 'H', 'D', 'R')) { + return JXL_FAILURE("First chunk is not IHDR"); + } + const RectT image_rect(0, 0, png_get_uint_32(ihdr.data() + 8), + png_get_uint_32(ihdr.data() + 12)); + if (!ValidateViewport(image_rect)) { + return JXL_FAILURE("PNG image dimensions are too large"); + } - r = {bytes.data(), bytes.data() + bytes.size()}; - // Not a PNG => not an error - unsigned char png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; - if (!r.Read(sig, 8) || memcmp(sig, png_signature, 8) != 0) { - return false; + // Chunks we supply to PNG decoder for every animation frame. + std::vector passthrough_chunks; + if (!ctx.InitPngDecoder(passthrough_chunks, image_rect)) { + return JXL_FAILURE("Failed to initialize PNG decoder"); } - unsigned int id = read_chunk(&r, &chunkIHDR); - ppf->info.exponent_bits_per_sample = 0; - ppf->info.alpha_exponent_bits = 0; - ppf->info.orientation = JXL_ORIENT_IDENTITY; + // Marker that this PNG is animated. + bool seen_actl = false; + // First IDAT is a very important milestone; at this moment we freeze + // gathered metadata. + bool seen_idat = false; + // fCTL can occur multiple times, but only once before IDAT. + bool seen_fctl = false; + // Logical EOF. + bool seen_iend = false; - ppf->frames.clear(); + ColorInfoType color_info_type = ColorInfoType::NONE; - bool have_color = false; - bool have_cicp = false; - bool have_iccp = false; - bool have_srgb = false; - bool errorstate = true; - if (id == kId_IHDR && chunkIHDR.size() == 25) { - unsigned int x0 = 0; - unsigned int y0 = 0; - unsigned int delay_num = 1; - unsigned int delay_den = 10; - unsigned int dop = 0; - unsigned int bop = 0; - - unsigned int w = png_get_uint_32(chunkIHDR.data() + 8); - unsigned int h = png_get_uint_32(chunkIHDR.data() + 12); - unsigned int w0 = w; - unsigned int h0 = h; - if (w > cMaxPNGSize || h > cMaxPNGSize) { - return false; + // Flag that we processed some IDAT / fDAT after image / frame start. + bool seen_pixel_data = false; + + uint32_t num_channels; + JxlPixelFormat format = {}; + size_t bytes_per_pixel = 0; + std::vector frames; + FrameControl current_frame = {/*delay_num=*/1, /*delay_den=*/10, image_rect, + DisposeOp::NONE, BlendOp::SOURCE}; + + // Copies frame pixels / metadata from temporary storage. + // TODO(eustas): avoid copying. + const auto finalize_frame = [&]() -> Status { + if (!seen_pixel_data) { + return JXL_FAILURE("Frame / image without fdAT / IDAT chunks"); + } + if (!ctx.FinalizeStream(&ppf->metadata)) { + return JXL_FAILURE("Failed to finalize PNG substream"); + } + if (ctx.frameRaw.has_error) { + return JXL_FAILURE("Internal error"); } + // Allocates the frame buffer. + const RectT& vp = current_frame.viewport; + size_t xsize = static_cast(vp.xsize()); + size_t ysize = static_cast(vp.ysize()); + JXL_ASSIGN_OR_RETURN(PackedImage image, + PackedImage::Create(xsize, ysize, format)); + for (size_t y = 0; y < ysize; ++y) { + // TODO(eustas): ensure multiplication is safe + memcpy(static_cast(image.pixels()) + image.stride * y, + ctx.frameRaw.rows[y], bytes_per_pixel * xsize); + } + frames.push_back(Frame{std::move(image), current_frame}); + seen_pixel_data = false; + return true; + }; - // default settings in case e.g. only gAMA is given - ppf->color_encoding.color_space = JXL_COLOR_SPACE_RGB; - ppf->color_encoding.white_point = JXL_WHITE_POINT_D65; - ppf->color_encoding.primaries = JXL_PRIMARIES_SRGB; - ppf->color_encoding.transfer_function = JXL_TRANSFER_FUNCTION_SRGB; - ppf->color_encoding.rendering_intent = JXL_RENDERING_INTENT_RELATIVE; - - if (!processing_start(png_ptr, info_ptr, static_cast(&frameRaw), - hasInfo, chunkIHDR, chunksInfo)) { - while (!r.Eof()) { - id = read_chunk(&r, &chunk); - if (!id) break; - seenFctl |= (id == kId_fcTL); - - if (id == kId_acTL && !hasInfo && !isAnimated) { - isAnimated = true; - ppf->info.have_animation = JXL_TRUE; - ppf->info.animation.tps_numerator = 1000; - ppf->info.animation.tps_denominator = 1; - } else if (id == kId_IEND || - (id == kId_fcTL && (!hasInfo || isAnimated))) { - if (hasInfo) { - if (!processing_finish(png_ptr, info_ptr, &ppf->metadata)) { - // Allocates the frame buffer. - uint32_t duration = delay_num * 1000 / delay_den; - frames.push_back(FrameInfo{PackedImage(w0, h0, format), duration, - x0, w0, y0, h0, dop, bop}); - auto& frame = frames.back().data; - for (size_t y = 0; y < h0; ++y) { - memcpy(static_cast(frame.pixels()) + frame.stride * y, - frameRaw.rows[y], bytes_per_pixel * w0); - } - } else { - break; - } - } + while (!input.Eof()) { + if (seen_iend) { + return JXL_FAILURE("Exuberant input after IEND chunk"); + } + Bytes chunk = input.ReadChunk(); + if (chunk.empty()) { + return JXL_FAILURE("Malformed chunk"); + } + Bytes type(chunk.data() + 4, 4); + id = LoadLE32(type.data()); + // Cut 'size' and 'type' at front and 'CRC' at the end. + Bytes payload(chunk.data() + 8, chunk.size() - 12); + + if (!isAbc(type[0]) || !isAbc(type[1]) || !isAbc(type[2]) || + !isAbc(type[3])) { + return JXL_FAILURE("Exotic PNG chunk"); + } - if (id == kId_IEND) { - errorstate = false; - break; - } - if (chunk.size() < 34) { - return JXL_FAILURE("Received a chunk that is too small (%" PRIuS - "B)", - chunk.size()); - } - // At this point the old frame is done. Let's start a new one. - w0 = png_get_uint_32(chunk.data() + 12); - h0 = png_get_uint_32(chunk.data() + 16); - x0 = png_get_uint_32(chunk.data() + 20); - y0 = png_get_uint_32(chunk.data() + 24); - delay_num = png_get_uint_16(chunk.data() + 28); - delay_den = png_get_uint_16(chunk.data() + 30); - dop = chunk[32]; - bop = chunk[33]; - - if (!delay_den) delay_den = 100; - - if (w0 > cMaxPNGSize || h0 > cMaxPNGSize || x0 > cMaxPNGSize || - y0 > cMaxPNGSize || x0 + w0 > w || y0 + h0 > h || dop > 2 || - bop > 1) { - break; - } + switch (id) { + case MakeTag('a', 'c', 'T', 'L'): + if (seen_idat) { + JXL_DEBUG_V(2, "aCTL after IDAT ignored"); + continue; + } + if (seen_actl) { + JXL_DEBUG_V(2, "Duplicate aCTL chunk ignored"); + continue; + } + seen_actl = true; + ppf->info.have_animation = JXL_TRUE; + // TODO(eustas): decode from chunk? + ppf->info.animation.tps_numerator = 1000; + ppf->info.animation.tps_denominator = 1; + continue; + + case MakeTag('I', 'E', 'N', 'D'): + seen_iend = true; + JXL_RETURN_IF_ERROR(finalize_frame()); + continue; + + case MakeTag('f', 'c', 'T', 'L'): { + if (payload.size() != 26) { + return JXL_FAILURE("Unexpected fcTL payload size: %u", + static_cast(payload.size())); + } + if (seen_fctl && !seen_idat) { + return JXL_FAILURE("More than one fcTL before IDAT"); + } + if (seen_idat && !seen_actl) { + return JXL_FAILURE("fcTL after IDAT, but without acTL"); + } + seen_fctl = true; + + // TODO(eustas): check order? + // sequence_number = png_get_uint_32(payload.data()); + RectT raw_viewport(png_get_uint_32(payload.data() + 12), + png_get_uint_32(payload.data() + 16), + png_get_uint_32(payload.data() + 4), + png_get_uint_32(payload.data() + 8)); + uint8_t dispose_op = payload[24]; + if (dispose_op > kLastDisposeOp) { + return JXL_FAILURE("Invalid DisposeOp"); + } + uint8_t blend_op = payload[25]; + if (blend_op > kLastBlendOp) { + return JXL_FAILURE("Invalid BlendOp"); + } + FrameControl next_frame = { + /*delay_num=*/png_get_uint_16(payload.data() + 20), + /*delay_den=*/png_get_uint_16(payload.data() + 22), raw_viewport, + static_cast(dispose_op), static_cast(blend_op)}; + + if (!raw_viewport.Intersection(image_rect).IsSame(raw_viewport)) { + // Cropping happened. + return JXL_FAILURE("PNG frame is outside of image rect"); + } - if (hasInfo) { - memcpy(chunkIHDR.data() + 8, chunk.data() + 12, 8); - if (processing_start(png_ptr, info_ptr, - static_cast(&frameRaw), hasInfo, - chunkIHDR, chunksInfo)) { - break; - } + if (!seen_idat) { + // "Default" image is the first animation frame. Its viewport must + // cover the whole image area. + if (!raw_viewport.IsSame(image_rect)) { + return JXL_FAILURE( + "If the first animation frame is default image, its viewport " + "must cover full image"); } - } else if (id == kId_IDAT) { - // First IDAT chunk means we now have all header info - if (seenFctl) { - // `fcTL` chunk must appear after all `IDAT` chunks - return JXL_FAILURE("IDAT chunk after fcTL chunk"); - } - hasInfo = true; - JXL_CHECK(w == png_get_image_width(png_ptr, info_ptr)); - JXL_CHECK(h == png_get_image_height(png_ptr, info_ptr)); - int colortype = png_get_color_type(png_ptr, info_ptr); - int png_bit_depth = png_get_bit_depth(png_ptr, info_ptr); - ppf->info.bits_per_sample = png_bit_depth; - png_color_8p sigbits = nullptr; - png_get_sBIT(png_ptr, info_ptr, &sigbits); - if (colortype & 1) { - // palette will actually be 8-bit regardless of the index bitdepth - ppf->info.bits_per_sample = 8; - } - if (colortype & 2) { - ppf->info.num_color_channels = 3; - ppf->color_encoding.color_space = JXL_COLOR_SPACE_RGB; - if (sigbits && sigbits->red == sigbits->green && - sigbits->green == sigbits->blue) { - ppf->info.bits_per_sample = sigbits->red; - } else if (sigbits) { - int maxbps = std::max(sigbits->red, - std::max(sigbits->green, sigbits->blue)); - JXL_WARNING( - "sBIT chunk: bit depths for R, G, and B are not the same (%i " - "%i %i), while in JPEG XL they have to be the same. Setting " - "RGB bit depth to %i.", - sigbits->red, sigbits->green, sigbits->blue, maxbps); - ppf->info.bits_per_sample = maxbps; - } - } else { - ppf->info.num_color_channels = 1; - ppf->color_encoding.color_space = JXL_COLOR_SPACE_GRAY; - if (sigbits) ppf->info.bits_per_sample = sigbits->gray; - } - if (colortype & 4 || - png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { - ppf->info.alpha_bits = ppf->info.bits_per_sample; - if (sigbits && sigbits->alpha != ppf->info.bits_per_sample) { - JXL_WARNING( - "sBIT chunk: bit depths for RGBA are inconsistent " - "(%i %i %i %i). Setting A bitdepth to %i.", - sigbits->red, sigbits->green, sigbits->blue, sigbits->alpha, - ppf->info.bits_per_sample); - } - } else { - ppf->info.alpha_bits = 0; + } else { + JXL_RETURN_IF_ERROR(finalize_frame()); + if (!ctx.InitPngDecoder(passthrough_chunks, next_frame.viewport)) { + return JXL_FAILURE("Failed to initialize PNG decoder"); } - ppf->color_encoding.color_space = - (ppf->info.num_color_channels == 1 ? JXL_COLOR_SPACE_GRAY - : JXL_COLOR_SPACE_RGB); - ppf->info.xsize = w; - ppf->info.ysize = h; - JXL_RETURN_IF_ERROR(VerifyDimensions(constraints, w, h)); + } + current_frame = next_frame; + continue; + } + + case MakeTag('I', 'D', 'A', 'T'): { + if (!frames.empty()) { + return JXL_FAILURE("IDAT after default image is over"); + } + if (!seen_idat) { + // First IDAT means that all metadata is ready. + seen_idat = true; + JXL_ENSURE(image_rect.xsize() == + png_get_image_width(ctx.png_ptr, ctx.info_ptr)); + JXL_ENSURE(image_rect.ysize() == + png_get_image_height(ctx.png_ptr, ctx.info_ptr)); + JXL_RETURN_IF_ERROR(VerifyDimensions(constraints, image_rect.xsize(), + image_rect.ysize())); + ppf->info.xsize = image_rect.xsize(); + ppf->info.ysize = image_rect.ysize(); + + png_color_8p sig_bits = nullptr; + // Error is OK -> sig_bits remains nullptr. + png_get_sBIT(ctx.png_ptr, ctx.info_ptr, &sig_bits); + SetColorData(ppf, png_get_color_type(ctx.png_ptr, ctx.info_ptr), + png_get_bit_depth(ctx.png_ptr, ctx.info_ptr), sig_bits, + png_get_valid(ctx.png_ptr, ctx.info_ptr, PNG_INFO_tRNS)); num_channels = ppf->info.num_color_channels + (ppf->info.alpha_bits ? 1 : 0); format = { @@ -782,165 +1016,219 @@ Status DecodeImageAPNG(const Span bytes, /*endianness=*/JXL_BIG_ENDIAN, /*align=*/0, }; - if (png_bit_depth > 8 && format.data_type == JXL_TYPE_UINT8) { - png_set_strip_16(png_ptr); - } bytes_per_pixel = num_channels * (format.data_type == JXL_TYPE_UINT16 ? 2 : 1); - unsigned int rowbytes = w * bytes_per_pixel; - unsigned int imagesize = h * rowbytes; - frameRaw.pixels.resize(imagesize); - frameRaw.rows.resize(h); - for (unsigned int j = 0; j < h; j++) { - frameRaw.rows[j] = frameRaw.pixels.data() + j * rowbytes; + // TODO(eustas): ensure multiplication is safe + uint64_t row_bytes = + static_cast(image_rect.xsize()) * bytes_per_pixel; + uint64_t max_rows = std::numeric_limits::max() / row_bytes; + if (image_rect.ysize() > max_rows) { + return JXL_FAILURE("Image too big."); } + // TODO(eustas): drop frameRaw + JXL_RETURN_IF_ERROR( + ctx.frameRaw.Resize(row_bytes, image_rect.ysize())); + } - if (processing_data(png_ptr, info_ptr, chunk.data(), chunk.size())) { - break; - } - } else if (id == kId_fdAT && isAnimated) { - if (!hasInfo) { - return JXL_FAILURE("fDAT chunk before iDAT"); - } - png_save_uint_32(chunk.data() + 4, chunk.size() - 16); - memcpy(chunk.data() + 8, "IDAT", 4); - if (processing_data(png_ptr, info_ptr, chunk.data() + 4, - chunk.size() - 4)) { - break; - } - } else if (id == kId_cICP) { - // Color profile chunks: cICP has the highest priority, followed by - // iCCP and sRGB (which shouldn't co-exist, but if they do, we use - // iCCP), followed finally by gAMA and cHRM. - if (DecodeCICP(chunk.data() + 8, chunk.size() - 12, - &ppf->color_encoding)) { - have_cicp = true; - have_color = true; - ppf->icc.clear(); - ppf->primary_color_representation = - PackedPixelFile::kColorEncodingIsPrimary; - } - } else if (!have_cicp && id == kId_iCCP) { - if (processing_data(png_ptr, info_ptr, chunk.data(), chunk.size())) { - JXL_WARNING("Corrupt iCCP chunk"); - break; - } + if (!ctx.FeedChunks(chunk)) { + return JXL_FAILURE("Decoding IDAT failed"); + } + seen_pixel_data = true; + continue; + } - // TODO(jon): catch special case of PQ and synthesize color encoding - // in that case - int compression_type; - png_bytep profile; - png_charp name; - png_uint_32 proflen = 0; - auto ok = png_get_iCCP(png_ptr, info_ptr, &name, &compression_type, - &profile, &proflen); - if (ok && proflen) { - ppf->icc.assign(profile, profile + proflen); - ppf->primary_color_representation = PackedPixelFile::kIccIsPrimary; - have_color = true; - have_iccp = true; - } else { - // TODO(eustas): JXL_WARNING? - } - } else if (!have_cicp && !have_iccp && id == kId_sRGB) { - JXL_RETURN_IF_ERROR(DecodeSRGB(chunk.data() + 8, chunk.size() - 12, - &ppf->color_encoding)); - have_srgb = true; - have_color = true; - } else if (!have_cicp && !have_srgb && !have_iccp && id == kId_gAMA) { - JXL_RETURN_IF_ERROR(DecodeGAMA(chunk.data() + 8, chunk.size() - 12, - &ppf->color_encoding)); - have_color = true; - } else if (!have_cicp && !have_srgb && !have_iccp && id == kId_cHRM) { - JXL_RETURN_IF_ERROR(DecodeCHRM(chunk.data() + 8, chunk.size() - 12, - &ppf->color_encoding)); - have_color = true; - } else if (id == kId_eXIf) { - ppf->metadata.exif.resize(chunk.size() - 12); - memcpy(ppf->metadata.exif.data(), chunk.data() + 8, - chunk.size() - 12); - } else if (!isAbc(chunk[4]) || !isAbc(chunk[5]) || !isAbc(chunk[6]) || - !isAbc(chunk[7])) { - break; - } else { - if (processing_data(png_ptr, info_ptr, chunk.data(), chunk.size())) { - break; - } - if (!hasInfo) { - chunksInfo.push_back(chunk); - continue; - } + case MakeTag('f', 'd', 'A', 'T'): { + if (!seen_idat) { + return JXL_FAILURE("fdAT chunk before IDAT"); + } + if (!seen_actl) { + return JXL_FAILURE("fdAT chunk before acTL"); } + /* The 'fdAT' chunk has... the same structure as an 'IDAT' chunk, + * except preceded by a sequence number. */ + if (payload.size() < 4) { + return JXL_FAILURE("Corrupted fdAT chunk"); + } + // Turn 'fdAT' to 'IDAT' by cutting sequence number and replacing tag. + std::array preamble; + png_save_uint_32(preamble.data(), payload.size() - 4); + memcpy(preamble.data() + 4, "IDAT", 4); + // Cut-off 'size', 'type' and 'sequence_number' + Bytes chunk_tail(chunk.data() + 12, chunk.size() - 12); + if (!ctx.FeedChunks(Bytes(preamble), chunk_tail)) { + return JXL_FAILURE("Decoding fdAT failed"); + } + seen_pixel_data = true; + continue; } - } - JXL_RETURN_IF_ERROR(ApplyColorHints( - color_hints, have_color, ppf->info.num_color_channels == 1, ppf)); + case MakeTag('c', 'I', 'C', 'P'): + if (color_info_type == ColorInfoType::CICP) { + JXL_DEBUG_V(2, "Excessive colorspace definition; cICP chunk ignored"); + continue; + } + JXL_RETURN_IF_ERROR(DecodeCicpChunk(payload, &ppf->color_encoding)); + ppf->icc.clear(); + ppf->primary_color_representation = + PackedPixelFile::kColorEncodingIsPrimary; + color_info_type = ColorInfoType::CICP; + continue; + + case MakeTag('i', 'C', 'C', 'P'): { + if (color_info_type == ColorInfoType::ICCP_OR_SRGB) { + return JXL_FAILURE("Repeated iCCP / sRGB chunk"); + } + if (color_info_type > ColorInfoType::ICCP_OR_SRGB) { + JXL_DEBUG_V(2, "Excessive colorspace definition; iCCP chunk ignored"); + continue; + } + // Let PNG decoder deal with chunk processing. + if (!ctx.FeedChunks(chunk)) { + return JXL_FAILURE("Corrupt iCCP chunk"); + } + + // TODO(jon): catch special case of PQ and synthesize color encoding + // in that case + int compression_type = 0; + png_bytep profile = nullptr; + png_charp name = nullptr; + png_uint_32 profile_len = 0; + png_uint_32 ok = + png_get_iCCP(ctx.png_ptr, ctx.info_ptr, &name, &compression_type, + &profile, &profile_len); + if (!ok || !profile_len) { + return JXL_FAILURE("Malformed / incomplete iCCP chunk"); + } + ppf->icc.assign(profile, profile + profile_len); + ppf->primary_color_representation = PackedPixelFile::kIccIsPrimary; + color_info_type = ColorInfoType::ICCP_OR_SRGB; + continue; + } + + case MakeTag('s', 'R', 'G', 'B'): + if (color_info_type == ColorInfoType::ICCP_OR_SRGB) { + return JXL_FAILURE("Repeated iCCP / sRGB chunk"); + } + if (color_info_type > ColorInfoType::ICCP_OR_SRGB) { + JXL_DEBUG_V(2, "Excessive colorspace definition; sRGB chunk ignored"); + continue; + } + JXL_RETURN_IF_ERROR(DecodeSrgbChunk(payload, &ppf->color_encoding)); + color_info_type = ColorInfoType::ICCP_OR_SRGB; + continue; + + case MakeTag('g', 'A', 'M', 'A'): + if (color_info_type >= ColorInfoType::GAMA_OR_CHRM) { + JXL_DEBUG_V(2, "Excessive colorspace definition; gAMA chunk ignored"); + continue; + } + JXL_RETURN_IF_ERROR(DecodeGamaChunk(payload, &ppf->color_encoding)); + color_info_type = ColorInfoType::GAMA_OR_CHRM; + continue; + + case MakeTag('c', 'H', 'R', 'M'): + if (color_info_type >= ColorInfoType::GAMA_OR_CHRM) { + JXL_DEBUG_V(2, "Excessive colorspace definition; cHRM chunk ignored"); + continue; + } + JXL_RETURN_IF_ERROR(DecodeChrmChunk(payload, &ppf->color_encoding)); + color_info_type = ColorInfoType::GAMA_OR_CHRM; + continue; + + case MakeTag('c', 'L', 'L', 'i'): + JXL_RETURN_IF_ERROR( + DecodeClliChunk(payload, &ppf->info.intensity_target)); + continue; + + case MakeTag('e', 'X', 'I', 'f'): + // TODO(eustas): next eXIF chunk overwrites current; is it ok? + ppf->metadata.exif.resize(payload.size()); + memcpy(ppf->metadata.exif.data(), payload.data(), payload.size()); + continue; + + default: + // We don't know what is that, just pass through. + if (!ctx.FeedChunks(chunk)) { + return JXL_FAILURE("PNG decoder failed to process chunk"); + } + // If it happens before IDAT, we consider it metadata and pass to all + // sub-decoders. + if (!seen_idat) { + passthrough_chunks.push_back(chunk); + } + continue; + } } - if (errorstate) return false; + bool color_is_already_set = (color_info_type != ColorInfoType::NONE); + bool is_gray = (ppf->info.num_color_channels == 1); + JXL_RETURN_IF_ERROR( + ApplyColorHints(color_hints, color_is_already_set, is_gray, ppf)); + + if (ppf->color_encoding.transfer_function != JXL_TRANSFER_FUNCTION_PQ) { + // Reset intensity target, in case we set it from cLLi but TF is not PQ. + ppf->info.intensity_target = 0.f; + } bool has_nontrivial_background = false; bool previous_frame_should_be_cleared = false; - enum { - DISPOSE_OP_NONE = 0, - DISPOSE_OP_BACKGROUND = 1, - DISPOSE_OP_PREVIOUS = 2, - }; - enum { - BLEND_OP_SOURCE = 0, - BLEND_OP_OVER = 1, - }; for (size_t i = 0; i < frames.size(); i++) { - auto& frame = frames[i]; - JXL_ASSERT(frame.data.xsize == frame.xsize); - JXL_ASSERT(frame.data.ysize == frame.ysize); - - // Before encountering a DISPOSE_OP_NONE frame, the canvas is filled with 0, - // so DISPOSE_OP_BACKGROUND and DISPOSE_OP_PREVIOUS are equivalent. - if (frame.dispose_op == DISPOSE_OP_NONE) { + Frame& frame = frames[i]; + const FrameControl& fc = frame.metadata; + const RectT vp = fc.viewport; + const auto& pixels = frame.pixels; + size_t xsize = pixels.xsize; + size_t ysize = pixels.ysize; + JXL_ENSURE(xsize == vp.xsize()); + JXL_ENSURE(ysize == vp.ysize()); + + // Before encountering a DISPOSE_OP_NONE frame, the canvas is filled with + // 0, so DISPOSE_OP_BACKGROUND and DISPOSE_OP_PREVIOUS are equivalent. + if (fc.dispose_op == DisposeOp::NONE) { has_nontrivial_background = true; } - bool should_blend = frame.blend_op == BLEND_OP_OVER; + bool should_blend = fc.blend_op == BlendOp::OVER; bool use_for_next_frame = - has_nontrivial_background && frame.dispose_op != DISPOSE_OP_PREVIOUS; - size_t x0 = frame.x0; - size_t y0 = frame.y0; - size_t xsize = frame.data.xsize; - size_t ysize = frame.data.ysize; + has_nontrivial_background && fc.dispose_op != DisposeOp::PREVIOUS; + size_t x0 = vp.x0(); + size_t y0 = vp.y0(); if (previous_frame_should_be_cleared) { - size_t px0 = frames[i - 1].x0; - size_t py0 = frames[i - 1].y0; - size_t pxs = frames[i - 1].xsize; - size_t pys = frames[i - 1].ysize; + const auto& pvp = frames[i - 1].metadata.viewport; + size_t px0 = pvp.x0(); + size_t py0 = pvp.y0(); + size_t pxs = pvp.xsize(); + size_t pys = pvp.ysize(); if (px0 >= x0 && py0 >= y0 && px0 + pxs <= x0 + xsize && - py0 + pys <= y0 + ysize && frame.blend_op == BLEND_OP_SOURCE && + py0 + pys <= y0 + ysize && fc.blend_op == BlendOp::SOURCE && use_for_next_frame) { - // If the previous frame is entirely contained in the current frame and - // we are using BLEND_OP_SOURCE, nothing special needs to be done. - ppf->frames.emplace_back(std::move(frame.data)); + // If the previous frame is entirely contained in the current frame + // and we are using BLEND_OP_SOURCE, nothing special needs to be done. + ppf->frames.emplace_back(std::move(frame.pixels)); } else if (px0 == x0 && py0 == y0 && px0 + pxs == x0 + xsize && py0 + pys == y0 + ysize && use_for_next_frame) { // If the new frame has the same size as the old one, but we are // blending, we can instead just not blend. should_blend = false; - ppf->frames.emplace_back(std::move(frame.data)); + ppf->frames.emplace_back(std::move(frame.pixels)); } else if (px0 <= x0 && py0 <= y0 && px0 + pxs >= x0 + xsize && py0 + pys >= y0 + ysize && use_for_next_frame) { // If the new frame is contained within the old frame, we can pad the // new frame with zeros and not blend. - PackedImage new_data(pxs, pys, frame.data.format); + JXL_ASSIGN_OR_RETURN(PackedImage new_data, + PackedImage::Create(pxs, pys, pixels.format)); memset(new_data.pixels(), 0, new_data.pixels_size); for (size_t y = 0; y < ysize; y++) { + JXL_RETURN_IF_ERROR( + PackedImage::ValidateDataType(new_data.format.data_type)); size_t bytes_per_pixel = PackedImage::BitsPerChannel(new_data.format.data_type) * new_data.format.num_channels / 8; - memcpy(static_cast(new_data.pixels()) + - new_data.stride * (y + y0 - py0) + - bytes_per_pixel * (x0 - px0), - static_cast(frame.data.pixels()) + - frame.data.stride * y, - xsize * bytes_per_pixel); + memcpy( + static_cast(new_data.pixels()) + + new_data.stride * (y + y0 - py0) + + bytes_per_pixel * (x0 - px0), + static_cast(pixels.pixels()) + pixels.stride * y, + xsize * bytes_per_pixel); } x0 = px0; @@ -951,7 +1239,8 @@ Status DecodeImageAPNG(const Span bytes, ppf->frames.emplace_back(std::move(new_data)); } else { // If all else fails, insert a placeholder blank frame with kReplace. - PackedImage blank(pxs, pys, frame.data.format); + JXL_ASSIGN_OR_RETURN(PackedImage blank, + PackedImage::Create(pxs, pys, pixels.format)); memset(blank.pixels(), 0, blank.pixels_size); ppf->frames.emplace_back(std::move(blank)); auto& pframe = ppf->frames.back(); @@ -966,10 +1255,10 @@ Status DecodeImageAPNG(const Span bytes, pframe.frame_info.layer_info.blend_info.blendmode = JXL_BLEND_REPLACE; pframe.frame_info.layer_info.blend_info.source = 1; pframe.frame_info.layer_info.save_as_reference = 1; - ppf->frames.emplace_back(std::move(frame.data)); + ppf->frames.emplace_back(std::move(frame.pixels)); } } else { - ppf->frames.emplace_back(std::move(frame.data)); + ppf->frames.emplace_back(std::move(frame.pixels)); } auto& pframe = ppf->frames.back(); @@ -977,7 +1266,8 @@ Status DecodeImageAPNG(const Span bytes, pframe.frame_info.layer_info.crop_y0 = y0; pframe.frame_info.layer_info.xsize = xsize; pframe.frame_info.layer_info.ysize = ysize; - pframe.frame_info.duration = frame.duration; + pframe.frame_info.duration = + fc.delay_num * 1000 / (fc.delay_den ? fc.delay_den : 100); pframe.frame_info.layer_info.blend_info.blendmode = should_blend ? JXL_BLEND_BLEND : JXL_BLEND_REPLACE; bool is_full_size = x0 == 0 && y0 == 0 && xsize == ppf->info.xsize && @@ -988,16 +1278,16 @@ Status DecodeImageAPNG(const Span bytes, pframe.frame_info.layer_info.save_as_reference = use_for_next_frame ? 1 : 0; previous_frame_should_be_cleared = - has_nontrivial_background && frame.dispose_op == DISPOSE_OP_BACKGROUND; + has_nontrivial_background && (fc.dispose_op == DisposeOp::BACKGROUND); } + if (ppf->frames.empty()) return JXL_FAILURE("No frames decoded"); ppf->frames.back().frame_info.is_last = JXL_TRUE; return true; -#else - return false; -#endif } +#endif // JPEGXL_ENABLE_APNG + } // namespace extras } // namespace jxl diff --git a/third_party/jpeg-xl/lib/extras/dec/apng.h b/third_party/jpeg-xl/lib/extras/dec/apng.h index d91364b1e61e6..7ebc2ee7c8ae1 100644 --- a/third_party/jpeg-xl/lib/extras/dec/apng.h +++ b/third_party/jpeg-xl/lib/extras/dec/apng.h @@ -8,11 +8,10 @@ // Decodes APNG images in memory. -#include +#include #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" diff --git a/third_party/jpeg-xl/lib/extras/dec/color_description.cc b/third_party/jpeg-xl/lib/extras/dec/color_description.cc index bf229632d06d3..ce0c4adf3242a 100644 --- a/third_party/jpeg-xl/lib/extras/dec/color_description.cc +++ b/third_party/jpeg-xl/lib/extras/dec/color_description.cc @@ -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; } diff --git a/third_party/jpeg-xl/lib/extras/dec/decode.cc b/third_party/jpeg-xl/lib/extras/dec/decode.cc index 3546cb65c0380..2581d53f633c0 100644 --- a/third_party/jpeg-xl/lib/extras/dec/decode.cc +++ b/third_party/jpeg-xl/lib/extras/dec/decode.cc @@ -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 bytes, const ColorHints& color_hints, extras::PackedPixelFile* ppf, const SizeConstraints* constraints, Codec* orig_codec) { diff --git a/third_party/jpeg-xl/lib/extras/dec/decode.h b/third_party/jpeg-xl/lib/extras/dec/decode.h index 1a90f4c6a33ea..bbffc7e0f0a33 100644 --- a/third_party/jpeg-xl/lib/extras/dec/decode.h +++ b/third_party/jpeg-xl/lib/extras/dec/decode.h @@ -8,11 +8,9 @@ // Facade for image decoders (PNG, PNM, ...). -#include -#include - +#include +#include #include -#include #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, diff --git a/third_party/jpeg-xl/lib/extras/dec/exr.cc b/third_party/jpeg-xl/lib/extras/dec/exr.cc index 4a6fe5043a6d7..59edd63eb863f 100644 --- a/third_party/jpeg-xl/lib/extras/dec/exr.cc +++ b/third_party/jpeg-xl/lib/extras/dec/exr.cc @@ -5,19 +5,51 @@ #include "lib/extras/dec/exr.h" -#if JPEGXL_ENABLE_EXR +#include + +#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 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 #include #include #include -#endif #include +#ifdef __EXCEPTIONS +#include +#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(reinterpret_cast(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 bytes, const ColorHints& color_hints, PackedPixelFile* ppf, const SizeConstraints* constraints) { -#if JPEGXL_ENABLE_EXR InMemoryIStream is(bytes); #ifdef __EXCEPTIONS std::unique_ptr input_ptr; try { - input_ptr.reset(new OpenEXR::RgbaInputFile(is)); + input_ptr = jxl::make_unique(is); } catch (...) { // silently return false if it is not an EXR file return false; @@ -121,7 +149,12 @@ Status DecodeImageEXR(Span 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 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 diff --git a/third_party/jpeg-xl/lib/extras/dec/exr.h b/third_party/jpeg-xl/lib/extras/dec/exr.h index 0605cbba06ee2..65078d030ff97 100644 --- a/third_party/jpeg-xl/lib/extras/dec/exr.h +++ b/third_party/jpeg-xl/lib/extras/dec/exr.h @@ -8,6 +8,8 @@ // Decodes OpenEXR images in memory. +#include + #include "lib/extras/dec/color_hints.h" #include "lib/extras/packed_image.h" #include "lib/jxl/base/data_parallel.h" diff --git a/third_party/jpeg-xl/lib/extras/dec/gif.cc b/third_party/jpeg-xl/lib/extras/dec/gif.cc index d35202377391f..a87beb901acf7 100644 --- a/third_party/jpeg-xl/lib/extras/dec/gif.cc +++ b/third_party/jpeg-xl/lib/extras/dec/gif.cc @@ -5,19 +5,22 @@ #include "lib/extras/dec/gif.h" +#include "lib/jxl/base/status.h" + #if JPEGXL_ENABLE_GIF #include #endif #include -#include +#include #include #include #include #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(frame->extra_channels[0].pixels()), frame->color.xsize * frame->color.ysize, 255u); + return true; } } // namespace #endif @@ -81,7 +87,7 @@ Status DecodeImageGIF(Span 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 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 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(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 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( 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 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 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 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 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; diff --git a/third_party/jpeg-xl/lib/extras/dec/jpegli.cc b/third_party/jpeg-xl/lib/extras/dec/jpegli.cc index 957c405023e8a..c307105139173 100644 --- a/third_party/jpeg-xl/lib/extras/dec/jpegli.cc +++ b/third_party/jpeg-xl/lib/extras/dec/jpegli.cc @@ -6,16 +6,17 @@ #include "lib/extras/dec/jpegli.h" #include -#include #include -#include +#include +#include #include #include #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 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& 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& 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( @@ -258,8 +268,9 @@ Status DecodeJpeg(const std::vector& 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)); } } diff --git a/third_party/jpeg-xl/lib/extras/dec/jpg.cc b/third_party/jpeg-xl/lib/extras/dec/jpg.cc index f938006968432..35f7b51e0c68a 100644 --- a/third_party/jpeg-xl/lib/extras/dec/jpg.cc +++ b/third_party/jpeg-xl/lib/extras/dec/jpg.cc @@ -6,19 +6,19 @@ #include "lib/extras/dec/jpg.h" #if JPEGXL_ENABLE_JPEG -#include -#include +#include "lib/jxl/base/include_jpeglib.h" // NOLINT #endif -#include #include +#include #include #include #include #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 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 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 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 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 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( static_cast(frame.color.pixels()) + @@ -323,8 +332,9 @@ Status DecodeImageJPG(const Span 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)); } } diff --git a/third_party/jpeg-xl/lib/extras/dec/jxl.cc b/third_party/jpeg-xl/lib/extras/dec/jxl.cc index 576c8f900f48e..1120dedc30cdb 100644 --- a/third_party/jpeg-xl/lib/extras/dec/jxl.cc +++ b/third_party/jpeg-xl/lib/extras/dec/jxl.cc @@ -6,14 +6,21 @@ #include "lib/extras/dec/jxl.h" #include +#include #include #include #include -#include +#include // PRIu32 +#include +#include +#include +#include +#include #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* out) { - JXL_ASSERT(out != nullptr); + bool InitializeOutput(std::vector* 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( - 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(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( diff --git a/third_party/jpeg-xl/lib/extras/dec/jxl.h b/third_party/jpeg-xl/lib/extras/dec/jxl.h index 5f4ed7f683800..7c80280c033ad 100644 --- a/third_party/jpeg-xl/lib/extras/dec/jxl.h +++ b/third_party/jpeg-xl/lib/extras/dec/jxl.h @@ -8,10 +8,12 @@ // Decodes JPEG XL images in memory. +#include #include #include -#include +#include +#include #include #include #include @@ -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; diff --git a/third_party/jpeg-xl/lib/extras/dec/pgx.cc b/third_party/jpeg-xl/lib/extras/dec/pgx.cc index 76a6f06413aba..4499069d7708b 100644 --- a/third_party/jpeg-xl/lib/extras/dec/pgx.cc +++ b/third_party/jpeg-xl/lib/extras/dec/pgx.cc @@ -150,7 +150,7 @@ Status DecodeImagePGX(const Span 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 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) { diff --git a/third_party/jpeg-xl/lib/extras/dec/pgx_test.cc b/third_party/jpeg-xl/lib/extras/dec/pgx_test.cc index 5dbc3149a2cd7..9370e5d5ae2bf 100644 --- a/third_party/jpeg-xl/lib/extras/dec/pgx_test.cc +++ b/third_party/jpeg-xl/lib/extras/dec/pgx_test.cc @@ -5,10 +5,17 @@ #include "lib/extras/dec/pgx.h" +#include #include +#include +#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()); diff --git a/third_party/jpeg-xl/lib/extras/dec/pnm.cc b/third_party/jpeg-xl/lib/extras/dec/pnm.cc index a2a66d36d9c6e..587cd189a9d04 100644 --- a/third_party/jpeg-xl/lib/extras/dec/pnm.cc +++ b/third_party/jpeg-xl/lib/extras/dec/pnm.cc @@ -5,17 +5,18 @@ #include "lib/extras/dec/pnm.h" -#include -#include +#include #include +#include #include -#include +#include +#include -#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 MakeSpan(const char* str) { - return Bytes(reinterpret_cast(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::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 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 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 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 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)); - - 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); +// Exposed for testing. +Status PnmParseSigned(Bytes str, double* v) { + return Parser(str).ParseSigned(v); +} + +Status PnmParseUnsigned(Bytes str, size_t* v) { + return Parser(str).ParseUnsigned(v); } } // namespace extras diff --git a/third_party/jpeg-xl/lib/extras/dec/pnm.h b/third_party/jpeg-xl/lib/extras/dec/pnm.h index b740a79af511b..a6ad14fdc8f6b 100644 --- a/third_party/jpeg-xl/lib/extras/dec/pnm.h +++ b/third_party/jpeg-xl/lib/extras/dec/pnm.h @@ -13,12 +13,10 @@ // TODO(janwas): workaround for incorrect Win64 codegen (cause unknown) #include -#include #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 bytes, const ColorHints& color_hints, PackedPixelFile* ppf, const SizeConstraints* constraints = nullptr); -void TestCodecPNM(); - struct HeaderPNM { size_t xsize; size_t ysize; diff --git a/third_party/jpeg-xl/lib/extras/enc/apng.cc b/third_party/jpeg-xl/lib/extras/enc/apng.cc index 40aa876e84b32..72139032af020 100644 --- a/third_party/jpeg-xl/lib/extras/enc/apng.cc +++ b/third_party/jpeg-xl/lib/extras/enc/apng.cc @@ -36,8 +36,7 @@ * */ -#include - +#include #include #include @@ -62,7 +61,8 @@ class APNGEncoder : public Encoder { std::vector AcceptedFormats() const override { std::vector 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* bytes) const; + std::vector* 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(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* 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* 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 = frame.color; + const PackedImage& color = encode_extra_channels + ? frame.extra_channels[extra_channel_index] + : 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(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 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(in[i] * mul + 0.5); + out[i] = static_cast(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(val * mul + 0.5), p_out); + StoreBE16(static_cast(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(p_in), + 0.f, 1.f); + StoreBE16(static_cast(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; diff --git a/third_party/jpeg-xl/lib/extras/enc/encode.cc b/third_party/jpeg-xl/lib/extras/enc/encode.cc index c5e22d8c7e245..71be78e36cc22 100644 --- a/third_party/jpeg-xl/lib/extras/enc/encode.cc +++ b/third_party/jpeg-xl/lib/extras/enc/encode.cc @@ -134,5 +134,13 @@ std::unique_ptr 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 diff --git a/third_party/jpeg-xl/lib/extras/enc/encode.h b/third_party/jpeg-xl/lib/extras/enc/encode.h index 2502d9976b622..a71f3b220fc7b 100644 --- a/third_party/jpeg-xl/lib/extras/enc/encode.h +++ b/third_party/jpeg-xl/lib/extras/enc/encode.h @@ -82,6 +82,8 @@ class Encoder { std::unordered_map options_; }; +std::string ListOfEncodeCodecs(); + } // namespace extras } // namespace jxl diff --git a/third_party/jpeg-xl/lib/extras/enc/jpegli.cc b/third_party/jpeg-xl/lib/extras/enc/jpegli.cc index af9c149d7f113..52de317399a6e 100644 --- a/third_party/jpeg-xl/lib/extras/enc/jpegli.cc +++ b/third_party/jpeg-xl/lib/extras/enc/jpegli.cc @@ -9,11 +9,11 @@ #include #include #include -#include #include #include #include +#include #include #include #include @@ -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 pixels; unsigned char* output_buffer = nullptr; - unsigned long output_size = 0; + unsigned long output_size = 0; // NOLINT std::vector 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 xyb_tmp = hwy::AllocateAligned(6 * rowlen); hwy::AlignedFreeUniquePtr premul_absorb = - hwy::AllocateAligned(MaxVectorSize() * 12); + hwy::AllocateAligned(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; diff --git a/third_party/jpeg-xl/lib/extras/enc/jpg.cc b/third_party/jpeg-xl/lib/extras/enc/jpg.cc index de0228fc0de97..9b6a83ad05c9e 100644 --- a/third_party/jpeg-xl/lib/extras/enc/jpg.cc +++ b/third_party/jpeg-xl/lib/extras/enc/jpg.cc @@ -6,26 +6,23 @@ #include "lib/extras/enc/jpg.h" #if JPEGXL_ENABLE_JPEG -#include -#include +#include "lib/jxl/base/include_jpeglib.h" // NOLINT #endif -#include #include #include #include +#include #include -#include #include -#include #include #include #include #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(); hook->ReadBaseTables(params.custom_base_quant_fn); hook->q_start = params.search_q_start; hook->q_precision = params.search_q_precision; diff --git a/third_party/jpeg-xl/lib/extras/enc/jxl.cc b/third_party/jpeg-xl/lib/extras/enc/jxl.cc index 7787e25bd4179..15f62673161da 100644 --- a/third_party/jpeg-xl/lib/extras/enc/jxl.cc +++ b/third_party/jpeg-xl/lib/extras/enc/jxl.cc @@ -5,10 +5,18 @@ #include "lib/extras/enc/jxl.h" +#include #include #include #include +#include +#include +#include +#include +#include + +#include "lib/extras/packed_image.h" #include "lib/jxl/base/exif.h" namespace jxl { @@ -112,7 +120,7 @@ bool ReadCompressedOutput(JxlEncoder* enc, std::vector* compressed) { bool EncodeImageJXL(const JXLCompressParams& params, const PackedPixelFile& ppf, const std::vector* jpeg_bytes, std::vector* 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(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& 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()) { diff --git a/third_party/jpeg-xl/lib/extras/enc/jxl.h b/third_party/jpeg-xl/lib/extras/enc/jxl.h index 186f5f41aa65b..a6573eb129ffa 100644 --- a/third_party/jpeg-xl/lib/extras/enc/jxl.h +++ b/third_party/jpeg-xl/lib/extras/enc/jxl.h @@ -7,11 +7,13 @@ #define LIB_EXTRAS_ENC_JXL_H_ #include +#include #include #include #include -#include +#include +#include #include #include "lib/extras/packed_image.h" @@ -36,32 +38,41 @@ struct JXLOption { struct JXLCompressParams { std::vector 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; diff --git a/third_party/jpeg-xl/lib/extras/enc/npy.cc b/third_party/jpeg-xl/lib/extras/enc/npy.cc index 8d9954ef316ad..38777a3535412 100644 --- a/third_party/jpeg-xl/lib/extras/enc/npy.cc +++ b/third_party/jpeg-xl/lib/extras/enc/npy.cc @@ -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(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(ec.pixels()); - JXL_ASSERT(offset + sample_size <= ec.pixels_size); + JXL_ENSURE(offset + sample_size <= ec.pixels_size); Append(out, pixels + offset, sample_size); } } diff --git a/third_party/jpeg-xl/lib/extras/enc/pgx.cc b/third_party/jpeg-xl/lib/extras/enc/pgx.cc index eb8eab4271722..fb47b3e1a97d5 100644 --- a/third_party/jpeg-xl/lib/extras/enc/pgx.cc +++ b/third_party/jpeg-xl/lib/extras/enc/pgx.cc @@ -6,7 +6,8 @@ #include "lib/extras/enc/pgx.h" #include -#include + +#include #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(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; diff --git a/third_party/jpeg-xl/lib/extras/enc/pnm.cc b/third_party/jpeg-xl/lib/extras/enc/pnm.cc index 966611cfca1a2..c4aa8d12eb4d6 100644 --- a/third_party/jpeg-xl/lib/extras/enc/pnm.cc +++ b/third_party/jpeg-xl/lib/extras/enc/pnm.cc @@ -5,28 +5,23 @@ #include "lib/extras/enc/pnm.h" -#include - +#include +#include +#include +#include #include #include #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* bytes) const { + static Status EncodeImage(const PackedImage& image, size_t bits_per_sample, + std::vector* 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* bytes) const { + static Status EncodeImage(const PackedImage& image, + std::vector* 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(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"); } diff --git a/third_party/jpeg-xl/lib/extras/gain_map.cc b/third_party/jpeg-xl/lib/extras/gain_map.cc new file mode 100644 index 0000000000000..8cce67161bb84 --- /dev/null +++ b/third_party/jpeg-xl/lib/extras/gain_map.cc @@ -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 + +#include +#include +#include +#include + +#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 +class FixedSizeMemoryManager { + public: + FixedSizeMemoryManager() = default; + + JxlMemoryManager* memory_manager() { return &manager_; } + + private: + static void* FixedSizeMemoryManagerAlloc(void* opaque, size_t capacity) { + auto manager = static_cast*>(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 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(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 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; +} diff --git a/third_party/jpeg-xl/lib/extras/gain_map_test.cc b/third_party/jpeg-xl/lib/extras/gain_map_test.cc new file mode 100644 index 0000000000000..7b4864974c07a --- /dev/null +++ b/third_party/jpeg-xl/lib/extras/gain_map_test.cc @@ -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 +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "lib/jxl/test_utils.h" +#include "lib/jxl/testing.h" + +namespace { + +std::vector GoldenTestGainMap(bool has_icc, bool has_color_encoding) { + // Define the parts of the gain map + uint8_t jhgm_version = 0x00; + std::vector 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 color_encoding = {0x50, 0xb4, 0x00}; + + std::vector icc_size = {0x00, 0x00, 0x00, 0x00}; + if (has_icc) { + icc_size = {0x00, 0x00, 0x00, 0x88}; // 136 in decimal + } + std::vector icc_data = jxl::test::GetCompressedIccTestProfile(); + std::string second_placeholder = + "placeholder for an actual naked JPEG XL codestream"; + + // Assemble the gain map + std::vector 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 icc_data; +}; + +class GainMapTest : public ::testing::TestWithParam {}; + +TEST_P(GainMapTest, GainMapRoundtrip) { + size_t bundle_size; + const GainMapTestParams& params = GetParam(); + std::vector 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 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 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 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 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 output_gain_map_metadata( + output_bundle.gain_map_metadata, + output_bundle.gain_map_metadata + output_bundle.gain_map_metadata_size); + std::vector output_alt_icc( + output_bundle.alt_icc, + output_bundle.alt_icc + output_bundle.alt_icc_size); + std::vector 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()}, + GainMapTestParams{true, test::GetCompressedIccTestProfile()}, + GainMapTestParams{false, test::GetCompressedIccTestProfile()}, + GainMapTestParams{false, std::vector()}), + [](const testing::TestParamInfo& 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 diff --git a/third_party/jpeg-xl/lib/extras/hlg.cc b/third_party/jpeg-xl/lib/extras/hlg.cc index 125005542b001..d92272052b969 100644 --- a/third_party/jpeg-xl/lib/extras/hlg.cc +++ b/third_party/jpeg-xl/lib/extras/hlg.cc @@ -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; } diff --git a/third_party/jpeg-xl/lib/extras/jpegli_test.cc b/third_party/jpeg-xl/lib/extras/jpegli_test.cc index a29af1ced725b..d22afd0e851d3 100644 --- a/third_party/jpeg-xl/lib/extras/jpegli_test.cc +++ b/third_party/jpeg-xl/lib/extras/jpegli_test.cc @@ -9,7 +9,6 @@ #include #include -#include #include #include @@ -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 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 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) { diff --git a/third_party/jpeg-xl/lib/extras/metrics.cc b/third_party/jpeg-xl/lib/extras/metrics.cc index 4259d3c375754..55c1130944480 100644 --- a/third_party/jpeg-xl/lib/extras/metrics.cc +++ b/third_party/jpeg-xl/lib/extras/metrics.cc @@ -16,6 +16,7 @@ #include #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::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}, diff --git a/third_party/jpeg-xl/lib/extras/mmap.h b/third_party/jpeg-xl/lib/extras/mmap.h index 8bc023dec0f35..60cc215993eea 100644 --- a/third_party/jpeg-xl/lib/extras/mmap.h +++ b/third_party/jpeg-xl/lib/extras/mmap.h @@ -18,10 +18,10 @@ class MemoryMappedFile { static StatusOr 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 impl_; diff --git a/third_party/jpeg-xl/lib/extras/packed_image.h b/third_party/jpeg-xl/lib/extras/packed_image.h index b0570dbd31225..8a88af618811a 100644 --- a/third_party/jpeg-xl/lib/extras/packed_image.h +++ b/third_party/jpeg-xl/lib/extras/packed_image.h @@ -12,22 +12,19 @@ #include #include #include -#include -#include -#include -#include #include #include +#include +#include +#include +#include #include #include -#include -#include #include #include #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 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(copy.pixels()), reinterpret_cast(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(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 - explicit PackedFrame(Args&&... args) : color(std::forward(args)...) {} + explicit PackedFrame(PackedImage&& image) : color(std::move(image)) {} + + static StatusOr 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; + } - PackedFrame Copy() const { - PackedFrame copy(color.xsize, color.ysize, color.format); + StatusOr 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 exif; std::vector iptc; + std::vector jhgm; std::vector jumbf; std::vector xmp; }; @@ -261,6 +286,8 @@ class PackedPixelFile { // The icc profile of the original image. std::vector orig_icc; + JxlBitDepth input_bitdepth = {JXL_BIT_DEPTH_FROM_PIXEL_FORMAT, 0, 0}; + std::unique_ptr preview_frame; std::vector frames; mutable std::vector chunked_frames; diff --git a/third_party/jpeg-xl/lib/extras/packed_image_convert.cc b/third_party/jpeg-xl/lib/extras/packed_image_convert.cc index 6dba0d602c285..7bdb3cdf64a3d 100644 --- a/third_party/jpeg-xl/lib/extras/packed_image_convert.cc +++ b/third_party/jpeg-xl/lib/extras/packed_image_convert.cc @@ -7,10 +7,14 @@ #include #include +#include #include #include +#include +#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 span( static_cast(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 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(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)); } diff --git a/third_party/jpeg-xl/lib/extras/packed_image_convert.h b/third_party/jpeg-xl/lib/extras/packed_image_convert.h index b14eed174e617..20ed330b84719 100644 --- a/third_party/jpeg-xl/lib/extras/packed_image_convert.h +++ b/third_party/jpeg-xl/lib/extras/packed_image_convert.h @@ -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 ConvertImage3FToPackedPixelFile( + const Image3F& image, const ColorEncoding& c_enc, JxlPixelFormat format, + ThreadPool* pool); } // namespace extras } // namespace jxl diff --git a/third_party/jpeg-xl/lib/extras/time.cc b/third_party/jpeg-xl/lib/extras/time.cc index d4f41754dadd7..344994f78da7a 100644 --- a/third_party/jpeg-xl/lib/extras/time.cc +++ b/third_party/jpeg-xl/lib/extras/time.cc @@ -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 diff --git a/third_party/jpeg-xl/lib/extras/tone_mapping.cc b/third_party/jpeg-xl/lib/extras/tone_mapping.cc index 3d0269524bff9..9a700c48a32f0 100644 --- a/third_party/jpeg-xl/lib/extras/tone_mapping.cc +++ b/third_party/jpeg-xl/lib/extras/tone_mapping.cc @@ -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 display_nits, ImageBundle* const ib, ThreadPool* const pool) { @@ -44,23 +44,25 @@ Status ToneMapFrame(const std::pair 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; } diff --git a/third_party/jpeg-xl/lib/extras/tone_mapping_gbench.cc b/third_party/jpeg-xl/lib/extras/tone_mapping_gbench.cc index 8fc928a4fd0d7..30b4e6e7e0930 100644 --- a/third_party/jpeg-xl/lib/extras/tone_mapping_gbench.cc +++ b/third_party/jpeg-xl/lib/extras/tone_mapping_gbench.cc @@ -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 + #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()); diff --git a/third_party/jpeg-xl/lib/include/jxl/cms_interface.h b/third_party/jpeg-xl/lib/include/jxl/cms_interface.h index 25c700867ac5c..137fb42d8ca9e 100644 --- a/third_party/jpeg-xl/lib/include/jxl/cms_interface.h +++ b/third_party/jpeg-xl/lib/include/jxl/cms_interface.h @@ -23,7 +23,7 @@ #include #include -#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 diff --git a/third_party/jpeg-xl/lib/include/jxl/codestream_header.h b/third_party/jpeg-xl/lib/include/jxl/codestream_header.h index e60eb03355417..513c92f1dda2d 100644 --- a/third_party/jpeg-xl/lib/include/jxl/codestream_header.h +++ b/third_party/jpeg-xl/lib/include/jxl/codestream_header.h @@ -19,7 +19,7 @@ #include #include -#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 diff --git a/third_party/jpeg-xl/lib/include/jxl/color_encoding.h b/third_party/jpeg-xl/lib/include/jxl/color_encoding.h index e6325dcb30299..14dcdeb0a2123 100644 --- a/third_party/jpeg-xl/lib/include/jxl/color_encoding.h +++ b/third_party/jpeg-xl/lib/include/jxl/color_encoding.h @@ -14,9 +14,7 @@ #ifndef JXL_COLOR_ENCODING_H_ #define JXL_COLOR_ENCODING_H_ -#include - -#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 diff --git a/third_party/jpeg-xl/lib/include/jxl/compressed_icc.h b/third_party/jpeg-xl/lib/include/jxl/compressed_icc.h new file mode 100644 index 0000000000000..10232794b69d3 --- /dev/null +++ b/third_party/jpeg-xl/lib/include/jxl/compressed_icc.h @@ -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 +#include +#include + +#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_ */ + +/** @} */ diff --git a/third_party/jpeg-xl/lib/include/jxl/decode.h b/third_party/jpeg-xl/lib/include/jxl/decode.h index 599b8336f3fc2..69c00243d6633 100644 --- a/third_party/jpeg-xl/lib/include/jxl/decode.h +++ b/third_party/jpeg-xl/lib/include/jxl/decode.h @@ -24,7 +24,7 @@ #include #include -#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 diff --git a/third_party/jpeg-xl/lib/include/jxl/decode_cxx.h b/third_party/jpeg-xl/lib/include/jxl/decode_cxx.h index 94d2fad83d85a..6089538dbe76c 100644 --- a/third_party/jpeg-xl/lib/include/jxl/decode_cxx.h +++ b/third_party/jpeg-xl/lib/include/jxl/decode_cxx.h @@ -20,7 +20,7 @@ #include -#if !(defined(__cplusplus) || defined(c_plusplus)) +#ifndef __cplusplus #error "This a C++ only header. Use jxl/decode.h from C sources." #endif diff --git a/third_party/jpeg-xl/lib/include/jxl/encode.h b/third_party/jpeg-xl/lib/include/jxl/encode.h index bb11dd7572874..633a98e41754e 100644 --- a/third_party/jpeg-xl/lib/include/jxl/encode.h +++ b/third_party/jpeg-xl/lib/include/jxl/encode.h @@ -25,7 +25,7 @@ #include #include -#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 diff --git a/third_party/jpeg-xl/lib/include/jxl/encode_cxx.h b/third_party/jpeg-xl/lib/include/jxl/encode_cxx.h index 13adb8683ce7f..8e552357ac1c5 100644 --- a/third_party/jpeg-xl/lib/include/jxl/encode_cxx.h +++ b/third_party/jpeg-xl/lib/include/jxl/encode_cxx.h @@ -20,7 +20,7 @@ #include -#if !(defined(__cplusplus) || defined(c_plusplus)) +#ifndef __cplusplus #error "This a C++ only header. Use jxl/encode.h from C sources." #endif diff --git a/third_party/jpeg-xl/lib/include/jxl/gain_map.h b/third_party/jpeg-xl/lib/include/jxl/gain_map.h new file mode 100644 index 0000000000000..e1b314b56cbd9 --- /dev/null +++ b/third_party/jpeg-xl/lib/include/jxl/gain_map.h @@ -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 +#include +#include + +#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_ */ + +/** @} */ diff --git a/third_party/jpeg-xl/lib/include/jxl/memory_manager.h b/third_party/jpeg-xl/lib/include/jxl/memory_manager.h index 52640a8beba56..05b4abe90b520 100644 --- a/third_party/jpeg-xl/lib/include/jxl/memory_manager.h +++ b/third_party/jpeg-xl/lib/include/jxl/memory_manager.h @@ -15,7 +15,7 @@ #include -#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 diff --git a/third_party/jpeg-xl/lib/include/jxl/parallel_runner.h b/third_party/jpeg-xl/lib/include/jxl/parallel_runner.h index ea66685dbc0e7..742f9598e90a5 100644 --- a/third_party/jpeg-xl/lib/include/jxl/parallel_runner.h +++ b/third_party/jpeg-xl/lib/include/jxl/parallel_runner.h @@ -40,20 +40,25 @@ #include #include -#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 diff --git a/third_party/jpeg-xl/lib/include/jxl/resizable_parallel_runner.h b/third_party/jpeg-xl/lib/include/jxl/resizable_parallel_runner.h index c82b0bc23b81d..b0bf68091ea21 100644 --- a/third_party/jpeg-xl/lib/include/jxl/resizable_parallel_runner.h +++ b/third_party/jpeg-xl/lib/include/jxl/resizable_parallel_runner.h @@ -37,7 +37,7 @@ #include #include -#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 diff --git a/third_party/jpeg-xl/lib/include/jxl/resizable_parallel_runner_cxx.h b/third_party/jpeg-xl/lib/include/jxl/resizable_parallel_runner_cxx.h index 84ba82772a82e..344c96cc9ebf9 100644 --- a/third_party/jpeg-xl/lib/include/jxl/resizable_parallel_runner_cxx.h +++ b/third_party/jpeg-xl/lib/include/jxl/resizable_parallel_runner_cxx.h @@ -21,7 +21,7 @@ #include -#if !(defined(__cplusplus) || defined(c_plusplus)) +#ifndef __cplusplus #error \ "This a C++ only header. Use jxl/jxl_resizable_parallel_runner.h from C" \ "sources." diff --git a/third_party/jpeg-xl/lib/include/jxl/stats.h b/third_party/jpeg-xl/lib/include/jxl/stats.h index 5ed440636f355..35930b4da1547 100644 --- a/third_party/jpeg-xl/lib/include/jxl/stats.h +++ b/third_party/jpeg-xl/lib/include/jxl/stats.h @@ -16,7 +16,7 @@ #include #include -#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 diff --git a/third_party/jpeg-xl/lib/include/jxl/thread_parallel_runner.h b/third_party/jpeg-xl/lib/include/jxl/thread_parallel_runner.h index 933f373ce960c..fbfe9e20749aa 100644 --- a/third_party/jpeg-xl/lib/include/jxl/thread_parallel_runner.h +++ b/third_party/jpeg-xl/lib/include/jxl/thread_parallel_runner.h @@ -37,7 +37,7 @@ #include #include -#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 diff --git a/third_party/jpeg-xl/lib/include/jxl/thread_parallel_runner_cxx.h b/third_party/jpeg-xl/lib/include/jxl/thread_parallel_runner_cxx.h index 6c0bd4b302859..7f35ca00e2898 100644 --- a/third_party/jpeg-xl/lib/include/jxl/thread_parallel_runner_cxx.h +++ b/third_party/jpeg-xl/lib/include/jxl/thread_parallel_runner_cxx.h @@ -21,7 +21,7 @@ #include #include -#if !(defined(__cplusplus) || defined(c_plusplus)) +#ifndef __cplusplus #error \ "This a C++ only header. Use jxl/jxl_thread_parallel_runner.h from C" \ "sources." diff --git a/third_party/jpeg-xl/lib/include/jxl/types.h b/third_party/jpeg-xl/lib/include/jxl/types.h index 2538dbaa82e3b..1844375f68dac 100644 --- a/third_party/jpeg-xl/lib/include/jxl/types.h +++ b/third_party/jpeg-xl/lib/include/jxl/types.h @@ -16,7 +16,7 @@ #include #include -#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 diff --git a/third_party/jpeg-xl/lib/jpegli.cmake b/third_party/jpeg-xl/lib/jpegli.cmake index f06912f4387ad..a471c8b2abd8c 100644 --- a/third_party/jpeg-xl/lib/jpegli.cmake +++ b/third_party/jpeg-xl/lib/jpegli.cmake @@ -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} diff --git a/third_party/jpeg-xl/lib/jpegli/README.md b/third_party/jpeg-xl/lib/jpegli/README.md index 72f13afd2265b..7241d1eaabfd9 100644 --- a/third_party/jpeg-xl/lib/jpegli/README.md +++ b/third_party/jpeg-xl/lib/jpegli/README.md @@ -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 diff --git a/third_party/jpeg-xl/lib/jpegli/adaptive_quantization.cc b/third_party/jpeg-xl/lib/jpegli/adaptive_quantization.cc index 2039326cbd4a7..11367ee66083f 100644 --- a/third_party/jpeg-xl/lib/jpegli/adaptive_quantization.cc +++ b/third_party/jpeg-xl/lib/jpegli/adaptive_quantization.cc @@ -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& 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); } diff --git a/third_party/jpeg-xl/lib/jpegli/color_quantize.cc b/third_party/jpeg-xl/lib/jpegli/color_quantize.cc index c4f32bf439c43..d5b0097f3d066 100644 --- a/third_party/jpeg-xl/lib/jpegli/color_quantize.cc +++ b/third_party/jpeg-xl/lib/jpegli/color_quantize.cc @@ -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::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; } diff --git a/third_party/jpeg-xl/lib/jpegli/color_transform.cc b/third_party/jpeg-xl/lib/jpegli/color_transform.cc index 020a6fd80c8db..ec906bedce414 100644 --- a/third_party/jpeg-xl/lib/jpegli/color_transform.cc +++ b/third_party/jpeg-xl/lib/jpegli/color_transform.cc @@ -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 +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 +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) { diff --git a/third_party/jpeg-xl/lib/jpegli/common.h b/third_party/jpeg-xl/lib/jpegli/common.h index 42487f2b89469..731a2e9d3f361 100644 --- a/third_party/jpeg-xl/lib/jpegli/common.h +++ b/third_party/jpeg-xl/lib/jpegli/common.h @@ -20,14 +20,9 @@ #ifndef LIB_JPEGLI_COMMON_H_ #define LIB_JPEGLI_COMMON_H_ -/* clang-format off */ -#include -#include -/* 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 diff --git a/third_party/jpeg-xl/lib/jpegli/common_internal.h b/third_party/jpeg-xl/lib/jpegli/common_internal.h index 248d3154e10ee..bd0a86d3b0864 100644 --- a/third_party/jpeg-xl/lib/jpegli/common_internal.h +++ b/third_party/jpeg-xl/lib/jpegli/common_internal.h @@ -6,17 +6,33 @@ #ifndef LIB_JPEGLI_COMMON_INTERNAL_H_ #define LIB_JPEGLI_COMMON_INTERNAL_H_ -#include -#include -#include +#include +#include +#include + +// 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 + +#ifdef __clang__ +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#pragma GCC pop_options +#endif + #include #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 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(HWY_ALIGNMENT, vec_size); size_t min_memstride = alignment + rowsize * sizeof(T) + vec_size; size_t memstride = RoundUpTo(min_memstride, alignment); diff --git a/third_party/jpeg-xl/lib/jpegli/dct-inl.h b/third_party/jpeg-xl/lib/jpegli/dct-inl.h index 66cc3b6b53b76..fb54a152d59c3 100644 --- a/third_party/jpeg-xl/lib/jpegli/dct-inl.h +++ b/third_party/jpeg-xl/lib/jpegli/dct-inl.h @@ -35,24 +35,24 @@ using D = HWY_FULL(float); using DI = HWY_FULL(int32_t); template -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 -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 -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 diff --git a/third_party/jpeg-xl/lib/jpegli/decode.cc b/third_party/jpeg-xl/lib/jpegli/decode.cc index bf57115ad6a52..d967b787d34c1 100644 --- a/third_party/jpeg-xl/lib/jpegli/decode.cc +++ b/third_party/jpeg-xl/lib/jpegli/decode.cc @@ -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(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_); } diff --git a/third_party/jpeg-xl/lib/jpegli/decode.h b/third_party/jpeg-xl/lib/jpegli/decode.h index 9800ebf67a210..78c39b409cd16 100644 --- a/third_party/jpeg-xl/lib/jpegli/decode.h +++ b/third_party/jpeg-xl/lib/jpegli/decode.h @@ -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 diff --git a/third_party/jpeg-xl/lib/jpegli/decode_api_test.cc b/third_party/jpeg-xl/lib/jpegli/decode_api_test.cc index bc903c2bbfad0..a3caa5106d96b 100644 --- a/third_party/jpeg-xl/lib/jpegli/decode_api_test.cc +++ b/third_party/jpeg-xl/lib/jpegli/decode_api_test.cc @@ -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 +#include + +#include #include +#include +#include +#include +#include +#include +#include +#include #include #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(cinfo->src); if (num_bytes <= 0) { return; @@ -219,13 +230,14 @@ struct TestConfig { float max_diff = 35.0f; }; -std::vector GetTestJpegData(TestConfig& config) { +jxl::StatusOr> GetTestJpegData(TestConfig& config) { std::vector 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 GenerateBasicConfigs() { TEST(DecodeAPITest, ReuseCinfoSameMemSource) { std::vector 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 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 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 compressed = GetTestJpegData(config); + JXL_ASSIGN_OR_QUIT(std::vector 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 { TEST_P(DecodeAPITestParamBuffered, TestAPI) { TestConfig config = GetParam(); const DecompressParams& dparams = config.dparams; - const std::vector compressed = GetTestJpegData(config); + JXL_ASSIGN_OR_QUIT(std::vector compressed, GetTestJpegData(config), + "Failed to create test data."); SourceManager src(compressed.data(), compressed.size(), dparams.chunk_size); std::vector output_progression1; @@ -893,7 +908,9 @@ std::vector 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 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 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); } } diff --git a/third_party/jpeg-xl/lib/jpegli/decode_internal.h b/third_party/jpeg-xl/lib/jpegli/decode_internal.h index ed7baa39e9867..c36f6774b9ca6 100644 --- a/third_party/jpeg-xl/lib/jpegli/decode_internal.h +++ b/third_party/jpeg-xl/lib/jpegli/decode_internal.h @@ -6,14 +6,15 @@ #ifndef LIB_JPEGLI_DECODE_INTERNAL_H_ #define LIB_JPEGLI_DECODE_INTERNAL_H_ -#include #include +#include #include #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 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> 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_ diff --git a/third_party/jpeg-xl/lib/jpegli/decode_marker.cc b/third_party/jpeg-xl/lib/jpegli/decode_marker.cc index 6ef2dd4d7eec7..2621ed08670cc 100644 --- a/third_party/jpeg-xl/lib/jpegli/decode_marker.cc +++ b/third_party/jpeg-xl/lib/jpegli/decode_marker.cc @@ -23,23 +23,22 @@ constexpr uint8_t kIccProfileTag[12] = "ICC_PROFILE"; // Macros for commonly used error conditions. -#define JPEG_VERIFY_LEN(n) \ - if (pos + (n) > len) { \ - return JPEGLI_ERROR("Unexpected end of marker: pos=%" PRIuS \ - " need=%d len=%" PRIuS, \ - pos, static_cast(n), len); \ +#define JPEG_VERIFY_LEN(n) \ + if (pos + (n) > len) { \ + JPEGLI_ERROR("Unexpected end of marker: pos=%" PRIuS \ + " need=%d len=%" PRIuS, \ + pos, static_cast(n), len); \ } -#define JPEG_VERIFY_INPUT(var, low, high) \ - if ((var) < (low) || (var) > (high)) { \ - return JPEGLI_ERROR("Invalid " #var ": %d", static_cast(var)); \ +#define JPEG_VERIFY_INPUT(var, low, high) \ + if ((var) < (low) || (var) > (high)) { \ + JPEGLI_ERROR("Invalid " #var ": %d", static_cast(var)); \ } -#define JPEG_VERIFY_MARKER_END() \ - if (pos != len) { \ - return JPEGLI_ERROR("Invalid marker length: declared=%" PRIuS \ - " actual=%" PRIuS, \ - len, pos); \ +#define JPEG_VERIFY_MARKER_END() \ + if (pos != len) { \ + JPEGLI_ERROR("Invalid marker length: declared=%" PRIuS " actual=%" PRIuS, \ + len, pos); \ } inline int ReadUint8(const uint8_t* data, size_t* pos) { @@ -104,9 +103,6 @@ void ProcessSOF(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { int quant_tbl_idx = ReadUint8(data, &pos); JPEG_VERIFY_INPUT(quant_tbl_idx, 0, NUM_QUANT_TBLS - 1); comp->quant_tbl_no = quant_tbl_idx; - if (cinfo->quant_tbl_ptrs[quant_tbl_idx] == nullptr) { - JPEGLI_ERROR("Quantization table with index %u not found", quant_tbl_idx); - } comp->quant_table = nullptr; // will be allocated after SOS marker } JPEG_VERIFY_MARKER_END(); @@ -169,6 +165,7 @@ void ProcessSOS(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { if (!m->found_sof_) { JPEGLI_ERROR("Unexpected SOS marker."); } + m->found_sos_ = true; size_t pos = 2; JPEG_VERIFY_LEN(1); cinfo->comps_in_scan = ReadUint8(data, &pos); @@ -182,7 +179,7 @@ void ProcessSOS(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { for (int i = 0; i < cinfo->comps_in_scan; ++i) { int id = ReadUint8(data, &pos); if (ids_seen[id]) { // (cf. section B.2.3, regarding CSj) - return JPEGLI_ERROR("Duplicate ID %d in SOS.", id); + JPEGLI_ERROR("Duplicate ID %d in SOS.", id); } ids_seen[id] = 1; jpeg_component_info* comp = nullptr; @@ -193,8 +190,7 @@ void ProcessSOS(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { } } if (!comp) { - return JPEGLI_ERROR("SOS marker: Could not find component with id %d", - id); + JPEGLI_ERROR("SOS marker: Could not find component with id %d", id); } int c = ReadUint8(data, &pos); comp->dc_tbl_no = c >> 4; @@ -262,12 +258,12 @@ void ProcessSOS(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { int comp_idx = cinfo->cur_comp_info[i]->component_index; for (int k = cinfo->Ss; k <= cinfo->Se; ++k) { if (m->scan_progression_[comp_idx][k] & scan_bitmask) { - return JPEGLI_ERROR( + JPEGLI_ERROR( "Overlapping scans: component=%d k=%d prev_mask: %u cur_mask %u", comp_idx, k, m->scan_progression_[i][k], scan_bitmask); } if (m->scan_progression_[comp_idx][k] & refinement_bitmask) { - return JPEGLI_ERROR( + JPEGLI_ERROR( "Invalid scan order, a more refined scan was already done: " "component=%d k=%d prev_mask=%u cur_mask=%u", comp_idx, k, m->scan_progression_[i][k], scan_bitmask); @@ -276,7 +272,7 @@ void ProcessSOS(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { } } if (cinfo->Al > 10) { - return JPEGLI_ERROR("Scan parameter Al=%d is not supported.", cinfo->Al); + JPEGLI_ERROR("Scan parameter Al=%d is not supported.", cinfo->Al); } } @@ -286,7 +282,7 @@ void ProcessSOS(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { void ProcessDHT(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { size_t pos = 2; if (pos == len) { - return JPEGLI_ERROR("DHT marker: no Huffman table found"); + JPEGLI_ERROR("DHT marker: no Huffman table found"); } while (pos < len) { JPEG_VERIFY_LEN(1 + kJpegHuffmanMaxBitLength); @@ -339,12 +335,12 @@ void ProcessDHT(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { void ProcessDQT(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { jpeg_decomp_master* m = cinfo->master; - if (m->found_sof_) { + if (m->found_sos_) { JPEGLI_ERROR("Updating quant tables between scans is not supported."); } size_t pos = 2; if (pos == len) { - return JPEGLI_ERROR("DQT marker: no quantization table found"); + JPEGLI_ERROR("DQT marker: no quantization table found"); } while (pos < len) { JPEG_VERIFY_LEN(1); @@ -378,7 +374,7 @@ void ProcessDNL(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { void ProcessDRI(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { jpeg_decomp_master* m = cinfo->master; if (m->found_dri_) { - return JPEGLI_ERROR("Duplicate DRI marker."); + JPEGLI_ERROR("Duplicate DRI marker."); } m->found_dri_ = true; size_t pos = 2; @@ -412,24 +408,24 @@ void ProcessAPP(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { payload += sizeof(kIccProfileTag); payload_size -= sizeof(kIccProfileTag); if (payload_size < 2) { - return JPEGLI_ERROR("ICC chunk is too small."); + JPEGLI_ERROR("ICC chunk is too small."); } uint8_t index = payload[0]; uint8_t total = payload[1]; ++m->icc_index_; if (m->icc_index_ != index) { - return JPEGLI_ERROR("Invalid ICC chunk order."); + JPEGLI_ERROR("Invalid ICC chunk order."); } if (total == 0) { - return JPEGLI_ERROR("Invalid ICC chunk total."); + JPEGLI_ERROR("Invalid ICC chunk total."); } if (m->icc_total_ == 0) { m->icc_total_ = total; } else if (m->icc_total_ != total) { - return JPEGLI_ERROR("Invalid ICC chunk total."); + JPEGLI_ERROR("Invalid ICC chunk total."); } if (m->icc_index_ > m->icc_total_) { - return JPEGLI_ERROR("Invalid ICC chunk index."); + JPEGLI_ERROR("Invalid ICC chunk index."); } m->icc_profile_.insert(m->icc_profile_.end(), payload + 2, payload + payload_size); diff --git a/third_party/jpeg-xl/lib/jpegli/decode_scan.cc b/third_party/jpeg-xl/lib/jpegli/decode_scan.cc index 1b50792f0af4c..6c4e5ac5f77e5 100644 --- a/third_party/jpeg-xl/lib/jpegli/decode_scan.cc +++ b/third_party/jpeg-xl/lib/jpegli/decode_scan.cc @@ -7,7 +7,7 @@ #include -#include +#include // HWY_ALIGN_MAX #include "lib/jpegli/decode_internal.h" #include "lib/jpegli/error.h" @@ -159,7 +159,7 @@ int ReadSymbol(const HuffmanTableEntry* table, BitReaderState* br) { * The lower half represents the negative DIFFs with an offset. */ int HuffExtend(int x, int s) { - JXL_DASSERT(s >= 1); + JXL_DASSERT(s > 0); int half = 1 << (s - 1); if (x >= half) { JXL_DASSERT(x < (1 << s)); diff --git a/third_party/jpeg-xl/lib/jpegli/destination_manager.cc b/third_party/jpeg-xl/lib/jpegli/destination_manager.cc index 6548130866c30..05d35797b87cb 100644 --- a/third_party/jpeg-xl/lib/jpegli/destination_manager.cc +++ b/third_party/jpeg-xl/lib/jpegli/destination_manager.cc @@ -52,7 +52,7 @@ struct MemoryDestinationManager { jpeg_destination_mgr pub; // Output buffer supplied by the application uint8_t** output; - unsigned long* output_size; + unsigned long* output_size; // NOLINT // Output buffer allocated by us. uint8_t* temp_buffer; // Current output buffer (either application supplied or allocated by us). @@ -113,7 +113,7 @@ void jpegli_stdio_dest(j_compress_ptr cinfo, FILE* outfile) { } void jpegli_mem_dest(j_compress_ptr cinfo, unsigned char** outbuffer, - unsigned long* outsize) { + unsigned long* outsize /* NOLINT */) { if (outbuffer == nullptr || outsize == nullptr) { JPEGLI_ERROR("jpegli_mem_dest: Invalid destination."); } diff --git a/third_party/jpeg-xl/lib/jpegli/downsample.cc b/third_party/jpeg-xl/lib/jpegli/downsample.cc index f1e945d509392..1e5bb1563b190 100644 --- a/third_party/jpeg-xl/lib/jpegli/downsample.cc +++ b/third_party/jpeg-xl/lib/jpegli/downsample.cc @@ -295,13 +295,14 @@ void DownsampleInputBuffer(j_compress_ptr cinfo) { } auto& input = *m->smooth_input[c]; auto& output = *m->raw_data[c]; - const size_t yout0 = y0 / v_factor; + const size_t y_out0 = y0 / v_factor; float* rows_in[MAX_SAMP_FACTOR]; - for (size_t yin = y0, yout = yout0; yin < y1; yin += v_factor, ++yout) { + for (size_t y_in = y0, y_out = y_out0; y_in < y1; + y_in += v_factor, ++y_out) { for (int iy = 0; iy < v_factor; ++iy) { - rows_in[iy] = input.Row(yin + iy); + rows_in[iy] = input.Row(y_in + iy); } - float* row_out = output.Row(yout); + float* row_out = output.Row(y_out); (*m->downsample_method[c])(rows_in, xsize_padded, row_out); } } diff --git a/third_party/jpeg-xl/lib/jpegli/encode.cc b/third_party/jpeg-xl/lib/jpegli/encode.cc index 15a961283904c..410eeed8083ec 100644 --- a/third_party/jpeg-xl/lib/jpegli/encode.cc +++ b/third_party/jpeg-xl/lib/jpegli/encode.cc @@ -146,7 +146,7 @@ void SetDefaultScanScript(j_compress_ptr cinfo) { ++next_scan; } } - JXL_ASSERT(next_scan - cinfo->script_space == cinfo->script_space_size); + JPEGLI_CHECK(next_scan - cinfo->script_space == cinfo->script_space_size); cinfo->scan_info = cinfo->script_space; cinfo->num_scans = cinfo->script_space_size; } @@ -283,15 +283,15 @@ void ProcessCompressionParams(j_compress_ptr cinfo) { JPEGLI_ERROR("Invalid sampling factor %d x %d", comp->h_samp_factor, comp->v_samp_factor); } + if (cinfo->num_components == 1) { + // Force samp factors to 1x1 for single-component images. + comp->h_samp_factor = comp->v_samp_factor = 1; + } cinfo->max_h_samp_factor = std::max(comp->h_samp_factor, cinfo->max_h_samp_factor); cinfo->max_v_samp_factor = std::max(comp->v_samp_factor, cinfo->max_v_samp_factor); } - if (cinfo->num_components == 1 && - (cinfo->max_h_samp_factor != 1 || cinfo->max_v_samp_factor != 1)) { - JPEGLI_ERROR("Sampling is not supported for simgle component image."); - } size_t iMCU_width = DCTSIZE * cinfo->max_h_samp_factor; size_t iMCU_height = DCTSIZE * cinfo->max_v_samp_factor; size_t total_iMCU_cols = DivCeil(cinfo->image_width, iMCU_width); @@ -587,7 +587,7 @@ void PadInputBuffer(j_compress_ptr cinfo, float* row[kMaxComponents]) { } void ProcessiMCURow(j_compress_ptr cinfo) { - JXL_ASSERT(cinfo->master->next_iMCU_row < cinfo->total_iMCU_rows); + JPEGLI_CHECK(cinfo->master->next_iMCU_row < cinfo->total_iMCU_rows); if (!cinfo->raw_data_in) { ApplyInputSmoothing(cinfo); DownsampleInputBuffer(cinfo); @@ -628,9 +628,9 @@ void ZigZagShuffleBlocks(j_compress_ptr cinfo) { for (int c = 0; c < cinfo->num_components; ++c) { jpeg_component_info* comp = &cinfo->comp_info[c]; for (JDIMENSION by = 0; by < comp->height_in_blocks; ++by) { - JBLOCKARRAY ba = GetBlockRow(cinfo, c, by); + JBLOCKARRAY blocks = GetBlockRow(cinfo, c, by); for (JDIMENSION bx = 0; bx < comp->width_in_blocks; ++bx) { - JCOEF* block = &ba[0][bx][0]; + JCOEF* block = &blocks[0][bx][0]; for (int k = 0; k < DCTSIZE2; ++k) { tmp[k] = block[kJPEGNaturalOrder[k]]; } @@ -713,18 +713,31 @@ void jpegli_set_defaults(j_compress_ptr cinfo) { void jpegli_default_colorspace(j_compress_ptr cinfo) { CheckState(cinfo, jpegli::kEncStart); + if (cinfo->in_color_space == JCS_RGB && cinfo->master->xyb_mode) { + jpegli_set_colorspace(cinfo, JCS_RGB); + return; + } switch (cinfo->in_color_space) { case JCS_GRAYSCALE: jpegli_set_colorspace(cinfo, JCS_GRAYSCALE); break; - case JCS_RGB: { - if (cinfo->master->xyb_mode) { - jpegli_set_colorspace(cinfo, JCS_RGB); - } else { - jpegli_set_colorspace(cinfo, JCS_YCbCr); - } + case JCS_RGB: +#ifdef JCS_EXTENSIONS + case JCS_EXT_RGB: + case JCS_EXT_BGR: + case JCS_EXT_RGBX: + case JCS_EXT_BGRX: + case JCS_EXT_XRGB: + case JCS_EXT_XBGR: +#endif +#if JCS_ALPHA_EXTENSIONS + case JCS_EXT_RGBA: + case JCS_EXT_BGRA: + case JCS_EXT_ARGB: + case JCS_EXT_ABGR: +#endif + jpegli_set_colorspace(cinfo, JCS_YCbCr); break; - } case JCS_YCbCr: jpegli_set_colorspace(cinfo, JCS_YCbCr); break; @@ -806,6 +819,11 @@ void jpegli_set_colorspace(j_compress_ptr cinfo, J_COLOR_SPACE colorspace) { cinfo->comp_info[2].quant_tbl_no = 1; cinfo->comp_info[1].dc_tbl_no = cinfo->comp_info[1].ac_tbl_no = 1; cinfo->comp_info[2].dc_tbl_no = cinfo->comp_info[2].ac_tbl_no = 1; + // Use chroma subsampling by default + cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; + if (colorspace == JCS_YCCK) { + cinfo->comp_info[3].h_samp_factor = cinfo->comp_info[3].v_samp_factor = 2; + } } } @@ -957,7 +975,7 @@ void jpegli_copy_critical_parameters(j_decompress_ptr srcinfo, jpegli_set_colorspace(dstinfo, srcinfo->jpeg_color_space); if (dstinfo->num_components != srcinfo->num_components) { const auto& cinfo = dstinfo; - return JPEGLI_ERROR("Mismatch between src colorspace and components"); + JPEGLI_ERROR("Mismatch between src colorspace and components"); } dstinfo->data_precision = srcinfo->data_precision; dstinfo->CCIR601_sampling = srcinfo->CCIR601_sampling; @@ -1156,7 +1174,7 @@ JDIMENSION jpegli_write_raw_data(j_compress_ptr cinfo, JSAMPIMAGE data, JPEGLI_ERROR("Missing input lines, minimum is %u", iMCU_height); } if (cinfo->next_scanline < m->next_input_row) { - JXL_ASSERT(m->next_input_row - cinfo->next_scanline == iMCU_height); + JPEGLI_CHECK(m->next_input_row - cinfo->next_scanline == iMCU_height); if (!jpegli::EmptyBitWriterBuffer(&m->bw)) { return 0; } diff --git a/third_party/jpeg-xl/lib/jpegli/encode.h b/third_party/jpeg-xl/lib/jpegli/encode.h index 320dfaaf8d1b8..54ff9d1f9eec6 100644 --- a/third_party/jpeg-xl/lib/jpegli/encode.h +++ b/third_party/jpeg-xl/lib/jpegli/encode.h @@ -21,8 +21,9 @@ #define LIB_JPEGLI_ENCODE_H_ #include "lib/jpegli/common.h" +#include "lib/jpegli/types.h" -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus extern "C" { #endif @@ -35,7 +36,7 @@ void jpegli_CreateCompress(j_compress_ptr cinfo, int version, void jpegli_stdio_dest(j_compress_ptr cinfo, FILE* outfile); void jpegli_mem_dest(j_compress_ptr cinfo, unsigned char** outbuffer, - unsigned long* outsize); + unsigned long* outsize /* NOLINT */); void jpegli_set_defaults(j_compress_ptr cinfo); @@ -151,7 +152,7 @@ void jpegli_set_progressive_level(j_compress_ptr cinfo, int level); // AC coefficients. Must be called before jpegli_set_defaults(). void jpegli_use_standard_quant_tables(j_compress_ptr cinfo); -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus } // extern "C" #endif diff --git a/third_party/jpeg-xl/lib/jpegli/encode_api_test.cc b/third_party/jpeg-xl/lib/jpegli/encode_api_test.cc index 1afdcf610d22a..c8a8e21f677aa 100644 --- a/third_party/jpeg-xl/lib/jpegli/encode_api_test.cc +++ b/third_party/jpeg-xl/lib/jpegli/encode_api_test.cc @@ -4,14 +4,22 @@ // license that can be found in the LICENSE file. #include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include "lib/jpegli/encode.h" -#include "lib/jpegli/error.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/sanitizers.h" +#include "lib/jpegli/types.h" namespace jpegli { namespace { @@ -69,7 +77,7 @@ TEST(EncodeAPITest, ReuseCinfoSameImageTwice) { CompressParams jparams; GenerateInput(PIXELS, jparams, &input); uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT std::vector compressed0; std::vector compressed1; jpeg_compress_struct cinfo; @@ -117,7 +125,7 @@ std::vector GenerateBasicConfigs() { TEST(EncodeAPITest, ReuseCinfoSameMemOutput) { std::vector 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 { @@ -145,7 +153,7 @@ TEST(EncodeAPITest, ReuseCinfoSameMemOutput) { TEST(EncodeAPITest, ReuseCinfoSameStdOutput) { std::vector all_configs = GenerateBasicConfigs(); FILE* tmpf = tmpfile(); - JXL_CHECK(tmpf); + ASSERT_TRUE(tmpf); { jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { @@ -161,9 +169,9 @@ TEST(EncodeAPITest, ReuseCinfoSameStdOutput) { jpegli_destroy_compress(&cinfo); } size_t total_size = ftell(tmpf); - rewind(tmpf); + fseek(tmpf, 0, SEEK_SET); std::vector compressed(total_size); - JXL_CHECK(total_size == fread(compressed.data(), 1, total_size, tmpf)); + ASSERT_TRUE(total_size == fread(compressed.data(), 1, total_size, tmpf)); fclose(tmpf); size_t pos = 0; for (auto& config : all_configs) { @@ -181,7 +189,7 @@ TEST(EncodeAPITest, ReuseCinfoChangeParams) { CompressParams jparams; DecompressParams dparams; uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT std::vector compressed; jpeg_compress_struct cinfo; const auto max_rms = [](int q, int hs, int vs) { @@ -246,9 +254,9 @@ TEST(EncodeAPITest, ReuseCinfoChangeParams) { TEST(EncodeAPITest, 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 { @@ -372,6 +380,8 @@ std::vector GenerateTests() { { TestConfig config; config.jparams.quality = 100; + config.jparams.h_sampling = {1, 1, 1}; + config.jparams.v_sampling = {1, 1, 1}; config.max_bpp = 6.6; config.max_dist = 0.6; all_tests.push_back(config); @@ -510,17 +520,23 @@ std::vector GenerateTests() { config.jparams.libjpeg_mode = true; config.max_bpp = 2.1; config.max_dist = 1.7; + config.jparams.h_sampling = {1, 1, 1}; + config.jparams.v_sampling = {1, 1, 1}; all_tests.push_back(config); } - for (J_COLOR_SPACE in_color_space : {JCS_RGB, JCS_YCbCr, JCS_GRAYSCALE}) { + for (J_COLOR_SPACE in_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}) { for (J_COLOR_SPACE jpeg_color_space : {JCS_RGB, JCS_YCbCr, JCS_GRAYSCALE}) { - if (jpeg_color_space == JCS_RGB && in_color_space == JCS_YCbCr) continue; + if (jpeg_color_space == JCS_RGB && in_color_space >= JCS_YCbCr) continue; TestConfig config; config.input.xsize = config.input.ysize = 256; config.input.color_space = in_color_space; config.jparams.set_jpeg_colorspace = true; config.jparams.jpeg_color_space = jpeg_color_space; + config.jparams.h_sampling = {1, 1, 1}; + config.jparams.v_sampling = {1, 1, 1}; config.max_bpp = jpeg_color_space == JCS_RGB ? 4.5 : 1.85; config.max_dist = jpeg_color_space == JCS_RGB ? 1.4 : 2.05; all_tests.push_back(config); @@ -536,6 +552,8 @@ std::vector GenerateTests() { config.jparams.set_jpeg_colorspace = true; config.jparams.jpeg_color_space = jpeg_color_space; } + config.jparams.h_sampling = {1, 1, 1, 1}; + config.jparams.v_sampling = {1, 1, 1, 1}; config.max_bpp = jpeg_color_space == JCS_CMYK ? 4.0 : 3.6; config.max_dist = jpeg_color_space == JCS_CMYK ? 1.2 : 1.5; all_tests.push_back(config); @@ -546,6 +564,8 @@ std::vector GenerateTests() { config.input.color_space = JCS_YCbCr; config.max_bpp = 1.6; config.max_dist = 1.35; + config.jparams.h_sampling = {1, 1, 1}; + config.jparams.v_sampling = {1, 1, 1}; all_tests.push_back(config); } for (bool xyb : {false, true}) { @@ -596,6 +616,8 @@ std::vector GenerateTests() { table.add_raw = add_raw; table.Generate(); config.jparams.optimize_coding = 1; + config.jparams.h_sampling = {1, 1, 1}; + config.jparams.v_sampling = {1, 1, 1}; config.jparams.quant_tables.push_back(table); config.jparams.quant_indexes = {0, 0, 0}; float q = (type == 0 ? 16 : type) * scale * 0.01f; @@ -614,6 +636,8 @@ std::vector GenerateTests() { config.input.ysize = 256; config.jparams.quant_indexes = {(qidx >> 2) & 1, (qidx >> 1) & 1, (qidx >> 0) & 1}; + config.jparams.h_sampling = {1, 1, 1}; + config.jparams.v_sampling = {1, 1, 1}; config.max_bpp = 2.25; config.max_dist = 2.8; all_tests.push_back(config); @@ -626,6 +650,8 @@ std::vector GenerateTests() { config.input.ysize = 256; config.jparams.quant_indexes = {(qidx >> 2) & 1, (qidx >> 1) & 1, (qidx >> 0) & 1}; + config.jparams.h_sampling = {1, 1, 1}; + config.jparams.v_sampling = {1, 1, 1}; CustomQuantTable table; table.slot_idx = slot_idx; table.Generate(); @@ -643,6 +669,10 @@ std::vector GenerateTests() { config.jparams.xyb_mode = xyb; config.jparams.quant_indexes = {(qidx >> 2) & 1, (qidx >> 1) & 1, (qidx >> 0) & 1}; + if (!xyb) { + config.jparams.h_sampling = {1, 1, 1}; + config.jparams.v_sampling = {1, 1, 1}; + } { CustomQuantTable table; table.slot_idx = 0; @@ -667,6 +697,10 @@ std::vector GenerateTests() { config.input.ysize = 256; config.jparams.xyb_mode = xyb; config.jparams.quant_indexes = {0, 1, 2}; + if (!xyb) { + config.jparams.h_sampling = {1, 1, 1}; + config.jparams.v_sampling = {1, 1, 1}; + } { CustomQuantTable table; table.slot_idx = 0; @@ -738,6 +772,8 @@ std::vector GenerateTests() { } config.jparams.progressive_mode = 0; config.jparams.optimize_coding = 0; + config.jparams.h_sampling = {1, 1, 1}; + config.jparams.v_sampling = {1, 1, 1}; config.max_bpp = 1.85; config.max_dist = 2.05; if (input_mode == COEFFICIENTS) { diff --git a/third_party/jpeg-xl/lib/jpegli/encode_finish.cc b/third_party/jpeg-xl/lib/jpegli/encode_finish.cc index 767a6532c5891..8cc3b8d27503b 100644 --- a/third_party/jpeg-xl/lib/jpegli/encode_finish.cc +++ b/third_party/jpeg-xl/lib/jpegli/encode_finish.cc @@ -99,10 +99,10 @@ float ComputePSNR(j_compress_ptr cinfo, int sampling) { HWY_ALIGN float iqmc[64]; ComputeInverseWeights(qmc, iqmc); for (JDIMENSION by = 0; by < comp->height_in_blocks; by += sampling) { - JBLOCKARRAY ba = GetBlockRow(cinfo, c, by); + JBLOCKARRAY blocks = GetBlockRow(cinfo, c, by); const float* qf = m->quant_field.Row(by * v_factor); for (JDIMENSION bx = 0; bx < comp->width_in_blocks; bx += sampling) { - error += BlockError(&ba[0][bx][0], qmc, iqmc, qf[bx * h_factor], + error += BlockError(&blocks[0][bx][0], qmc, iqmc, qf[bx * h_factor], zero_bias_offset, zero_bias_mul); num += DCTSIZE2; } @@ -122,11 +122,11 @@ void ReQuantizeCoeffs(j_compress_ptr cinfo) { const float* zero_bias_offset = m->zero_bias_offset[c]; const float* zero_bias_mul = m->zero_bias_mul[c]; for (JDIMENSION by = 0; by < comp->height_in_blocks; ++by) { - JBLOCKARRAY ba = GetBlockRow(cinfo, c, by); + JBLOCKARRAY block = GetBlockRow(cinfo, c, by); const float* qf = m->quant_field.Row(by * v_factor); for (JDIMENSION bx = 0; bx < comp->width_in_blocks; ++bx) { - ReQuantizeBlock(&ba[0][bx][0], qmc, qf[bx * h_factor], zero_bias_offset, - zero_bias_mul); + ReQuantizeBlock(&block[0][bx][0], qmc, qf[bx * h_factor], + zero_bias_offset, zero_bias_mul); } } } diff --git a/third_party/jpeg-xl/lib/jpegli/encode_streaming.cc b/third_party/jpeg-xl/lib/jpegli/encode_streaming.cc index 89dbd813f8534..ff43864a47bae 100644 --- a/third_party/jpeg-xl/lib/jpegli/encode_streaming.cc +++ b/third_party/jpeg-xl/lib/jpegli/encode_streaming.cc @@ -114,14 +114,14 @@ void ProcessiMCURow(j_compress_ptr cinfo) { int32_t* nonzero_idx = m->block_tmp + 3 * DCTSIZE2; coeff_t* JXL_RESTRICT last_dc_coeff = m->last_dc_coeff; bool adaptive_quant = m->use_adaptive_quantization && m->psnr_target == 0; - JBLOCKARRAY ba[kMaxComponents]; + JBLOCKARRAY blocks[kMaxComponents]; if (kMode == kStreamingModeCoefficients) { for (int c = 0; c < cinfo->num_components; ++c) { jpeg_component_info* comp = &cinfo->comp_info[c]; int by0 = mcu_y * comp->v_samp_factor; int block_rows_left = comp->height_in_blocks - by0; int max_block_rows = std::min(comp->v_samp_factor, block_rows_left); - ba[c] = (*cinfo->mem->access_virt_barray)( + blocks[c] = (*cinfo->mem->access_virt_barray)( reinterpret_cast(cinfo), m->coeff_buffers[c], by0, max_block_rows, true); } @@ -189,7 +189,7 @@ void ProcessiMCURow(j_compress_ptr cinfo) { aq_strength, zero_bias_offset, zero_bias_mul, m->dct_buffer, block); if (kMode == kStreamingModeCoefficients) { - JCOEF* cblock = &ba[c][iy][bx][0]; + JCOEF* cblock = &blocks[c][iy][bx][0]; for (int k = 0; k < DCTSIZE2; ++k) { cblock[k] = block[kJPEGNaturalOrder[k]]; } diff --git a/third_party/jpeg-xl/lib/jpegli/entropy_coding.cc b/third_party/jpeg-xl/lib/jpegli/entropy_coding.cc index 515996a43d7f2..d7d928099b1c2 100644 --- a/third_party/jpeg-xl/lib/jpegli/entropy_coding.cc +++ b/third_party/jpeg-xl/lib/jpegli/entropy_coding.cc @@ -106,7 +106,7 @@ void TokenizeACProgressiveScan(j_compress_ptr cinfo, int scan_index, eob_run = 0; }; for (JDIMENSION by = 0; by < comp->height_in_blocks; ++by) { - JBLOCKARRAY ba = (*cinfo->mem->access_virt_barray)( + JBLOCKARRAY blocks = (*cinfo->mem->access_virt_barray)( reinterpret_cast(cinfo), m->coeff_buffers[comp_idx], by, 1, FALSE); // Each coefficient can appear in at most one token, but we have to reserve @@ -132,7 +132,7 @@ void TokenizeACProgressiveScan(j_compress_ptr cinfo, int scan_index, sti->restarts[restart_idx++] = m->total_num_tokens + ta->num_tokens; restarts_to_go = restart_interval; } - const coeff_t* block = &ba[0][bx][0]; + const coeff_t* block = &blocks[0][bx][0]; coeff_t temp2; coeff_t temp; int r = 0; @@ -213,7 +213,7 @@ void TokenizeACRefinementScan(j_compress_ptr cinfo, int scan_index, uint16_t* next_eobrun = sti->eobruns; size_t restart_idx = 0; for (JDIMENSION by = 0; by < comp->height_in_blocks; ++by) { - JBLOCKARRAY ba = (*cinfo->mem->access_virt_barray)( + JBLOCKARRAY blocks = (*cinfo->mem->access_virt_barray)( reinterpret_cast(cinfo), m->coeff_buffers[comp_idx], by, 1, FALSE); for (JDIMENSION bx = 0; bx < comp->width_in_blocks; ++bx) { @@ -223,7 +223,7 @@ void TokenizeACRefinementScan(j_compress_ptr cinfo, int scan_index, next_eob_token = next_token; eob_run = eob_refbits = 0; } - const coeff_t* block = &ba[0][bx][0]; + const coeff_t* block = &blocks[0][bx][0]; int num_eob_refinement_bits = 0; int num_refinement_bits = 0; int num_nzeros = 0; @@ -347,7 +347,7 @@ void TokenizeScan(j_compress_ptr cinfo, size_t scan_index, int ac_ctx_offset, } } - JBLOCKARRAY ba[MAX_COMPS_IN_SCAN]; + JBLOCKARRAY blocks[MAX_COMPS_IN_SCAN]; size_t block_idx = 0; for (size_t mcu_y = 0; mcu_y < sti->MCU_rows_in_scan; ++mcu_y) { for (int i = 0; i < scan_info->comps_in_scan; ++i) { @@ -357,7 +357,7 @@ void TokenizeScan(j_compress_ptr cinfo, size_t scan_index, int ac_ctx_offset, int by0 = mcu_y * n_blocks_y; int block_rows_left = comp->height_in_blocks - by0; int max_block_rows = std::min(n_blocks_y, block_rows_left); - ba[i] = (*cinfo->mem->access_virt_barray)( + blocks[i] = (*cinfo->mem->access_virt_barray)( reinterpret_cast(cinfo), m->coeff_buffers[comp_idx], by0, max_block_rows, FALSE); } @@ -400,7 +400,7 @@ void TokenizeScan(j_compress_ptr cinfo, size_t scan_index, int ac_ctx_offset, block_y >= comp->height_in_blocks) { block = kSinkBlock; } else { - block = &ba[i][iy][block_x][0]; + block = &blocks[i][iy][block_x][0]; } if (!is_progressive) { HWY_DYNAMIC_DISPATCH(ComputeTokensSequential) @@ -441,18 +441,19 @@ void TokenizeJpeg(j_compress_ptr cinfo) { std::vector processed(cinfo->num_scans); size_t max_refinement_tokens = 0; size_t num_refinement_bits = 0; - int num_refinement_scans[DCTSIZE2] = {}; + int num_refinement_scans[kMaxComponents][DCTSIZE2] = {}; int max_num_refinement_scans = 0; for (int i = 0; i < cinfo->num_scans; ++i) { const jpeg_scan_info* si = &cinfo->scan_info[i]; ScanTokenInfo* sti = &m->scan_token_info[i]; if (si->Ss > 0 && si->Ah == 0 && si->Al > 0) { int offset = m->ac_ctx_offset[i]; + int comp_idx = si->component_index[0]; TokenizeScan(cinfo, i, offset, sti); processed[i] = 1; max_refinement_tokens += sti->num_future_nonzeros; for (int k = si->Ss; k <= si->Se; ++k) { - num_refinement_scans[k] = si->Al; + num_refinement_scans[comp_idx][k] = si->Al; } max_num_refinement_scans = std::max(max_num_refinement_scans, si->Al); num_refinement_bits += sti->num_nonzeros; @@ -475,16 +476,17 @@ void TokenizeJpeg(j_compress_ptr cinfo) { size_t new_refinement_bits = 0; for (int i = 0; i < cinfo->num_scans; ++i) { const jpeg_scan_info* si = &cinfo->scan_info[i]; + int comp_idx = si->component_index[0]; ScanTokenInfo* sti = &m->scan_token_info[i]; if (si->Ss > 0 && si->Ah > 0 && - si->Ah == num_refinement_scans[si->Ss] - j) { + si->Ah == num_refinement_scans[comp_idx][si->Ss] - j) { int offset = m->ac_ctx_offset[i]; TokenizeScan(cinfo, i, offset, sti); processed[i] = 1; new_refinement_bits += sti->num_nonzeros; } } - JXL_DASSERT(m->next_refinement_bit == + JXL_DASSERT(m->next_refinement_bit <= refinement_bits + num_refinement_bits); num_refinement_bits += new_refinement_bits; } @@ -568,8 +570,8 @@ bool IsEmptyHistogram(const Histogram& histo) { return true; } -void ClusterJpegHistograms(const Histogram* histograms, size_t num, - JpegClusteredHistograms* clusters) { +void ClusterJpegHistograms(j_compress_ptr cinfo, const Histogram* histograms, + size_t num, JpegClusteredHistograms* clusters) { clusters->histogram_indexes.resize(num); std::vector slot_histograms; std::vector slot_costs; @@ -614,7 +616,7 @@ void ClusterJpegHistograms(const Histogram* histograms, size_t num, const Histogram& prev = clusters->histograms[histogram_index]; AddHistograms(prev, cur, &clusters->histograms[histogram_index]); clusters->histogram_indexes[i] = histogram_index; - JXL_ASSERT(clusters->slot_ids[histogram_index] == best_slot); + JPEGLI_CHECK(clusters->slot_ids[histogram_index] == best_slot); slot_costs[best_slot] += best_cost; } } @@ -716,11 +718,12 @@ void OptimizeHuffmanCodes(j_compress_ptr cinfo) { // Cluster DC histograms. JpegClusteredHistograms dc_clusters; - ClusterJpegHistograms(histograms.data(), cinfo->num_components, &dc_clusters); + ClusterJpegHistograms(cinfo, histograms.data(), cinfo->num_components, + &dc_clusters); // Cluster AC histograms. JpegClusteredHistograms ac_clusters; - ClusterJpegHistograms(histograms.data() + 4, m->num_contexts - 4, + ClusterJpegHistograms(cinfo, histograms.data() + 4, m->num_contexts - 4, &ac_clusters); // Create Huffman tables and slot ids clusters. diff --git a/third_party/jpeg-xl/lib/jpegli/error.cc b/third_party/jpeg-xl/lib/jpegli/error.cc index 289261672de19..b3ccab0452e74 100644 --- a/third_party/jpeg-xl/lib/jpegli/error.cc +++ b/third_party/jpeg-xl/lib/jpegli/error.cc @@ -22,7 +22,7 @@ const char* const kErrorMessageTable[] = { bool FormatString(char* buffer, const char* format, ...) { va_list args; va_start(args, format); - vsnprintf(buffer, JMSG_STR_PARM_MAX, format, args); + vsnprintf(buffer, JMSG_STR_PARM_MAX, format, args); // notypo va_end(args); return false; } diff --git a/third_party/jpeg-xl/lib/jpegli/error.h b/third_party/jpeg-xl/lib/jpegli/error.h index 4451abd416e8f..fb5dc411a8b6d 100644 --- a/third_party/jpeg-xl/lib/jpegli/error.h +++ b/third_party/jpeg-xl/lib/jpegli/error.h @@ -10,6 +10,7 @@ #include #include "lib/jpegli/common.h" +#include "lib/jxl/base/compiler_specific.h" namespace jpegli { @@ -17,10 +18,12 @@ bool FormatString(char* buffer, const char* format, ...); } // namespace jpegli +// `error_exit` should be no-return; but let's add some guarantees on our side. #define JPEGLI_ERROR(format, ...) \ jpegli::FormatString(cinfo->err->msg_parm.s, ("%s:%d: " format), __FILE__, \ __LINE__, ##__VA_ARGS__), \ - (*cinfo->err->error_exit)(reinterpret_cast(cinfo)) + (*cinfo->err->error_exit)(reinterpret_cast(cinfo)), \ + JXL_CRASH() #define JPEGLI_WARN(format, ...) \ jpegli::FormatString(cinfo->err->msg_parm.s, ("%s:%d: " format), __FILE__, \ @@ -34,4 +37,11 @@ bool FormatString(char* buffer, const char* format, ...); (*cinfo->err->emit_message)(reinterpret_cast(cinfo), \ (level)) +#define JPEGLI_CHECK(condition) \ + do { \ + if (!(condition)) { \ + JPEGLI_ERROR("JPEGLI_CHECK: %s", #condition); \ + } \ + } while (0) + #endif // LIB_JPEGLI_ERROR_H_ diff --git a/third_party/jpeg-xl/lib/jpegli/error_handling_test.cc b/third_party/jpeg-xl/lib/jpegli/error_handling_test.cc index 3eaf6a313b6fb..da85dbcb0b3db 100644 --- a/third_party/jpeg-xl/lib/jpegli/error_handling_test.cc +++ b/third_party/jpeg-xl/lib/jpegli/error_handling_test.cc @@ -3,19 +3,26 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include +#include +#include +#include +#include + +#include "lib/jpegli/common.h" #include "lib/jpegli/decode.h" #include "lib/jpegli/encode.h" -#include "lib/jpegli/error.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/sanitizers.h" namespace jpegli { namespace { TEST(EncoderErrorHandlingTest, MinimalSuccess) { 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 { @@ -64,7 +71,7 @@ TEST(EncoderErrorHandlingTest, NoDestination) { TEST(EncoderErrorHandlingTest, NoImageDimensions) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -82,7 +89,7 @@ TEST(EncoderErrorHandlingTest, NoImageDimensions) { TEST(EncoderErrorHandlingTest, ImageTooBig) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -102,7 +109,7 @@ TEST(EncoderErrorHandlingTest, ImageTooBig) { TEST(EncoderErrorHandlingTest, NoInputComponents) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -121,7 +128,7 @@ TEST(EncoderErrorHandlingTest, NoInputComponents) { TEST(EncoderErrorHandlingTest, TooManyInputComponents) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -141,7 +148,7 @@ TEST(EncoderErrorHandlingTest, TooManyInputComponents) { TEST(EncoderErrorHandlingTest, NoSetDefaults) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -164,7 +171,7 @@ TEST(EncoderErrorHandlingTest, NoSetDefaults) { TEST(EncoderErrorHandlingTest, NoStartCompress) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -186,7 +193,7 @@ TEST(EncoderErrorHandlingTest, NoStartCompress) { TEST(EncoderErrorHandlingTest, NoWriteScanlines) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -207,7 +214,7 @@ TEST(EncoderErrorHandlingTest, NoWriteScanlines) { TEST(EncoderErrorHandlingTest, NoWriteAllScanlines) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -231,7 +238,7 @@ TEST(EncoderErrorHandlingTest, NoWriteAllScanlines) { TEST(EncoderErrorHandlingTest, InvalidQuantValue) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -260,7 +267,7 @@ TEST(EncoderErrorHandlingTest, InvalidQuantValue) { TEST(EncoderErrorHandlingTest, InvalidQuantTableIndex) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -285,7 +292,7 @@ TEST(EncoderErrorHandlingTest, InvalidQuantTableIndex) { TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch1) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -306,7 +313,7 @@ TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch1) { TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch2) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -327,7 +334,7 @@ TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch2) { TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch3) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -353,7 +360,7 @@ TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch3) { TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch4) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -378,7 +385,7 @@ TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch4) { TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch5) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -403,7 +410,7 @@ TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch5) { TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch6) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -429,7 +436,7 @@ TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch6) { TEST(EncoderErrorHandlingTest, InvalidColorTransform) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -455,7 +462,7 @@ TEST(EncoderErrorHandlingTest, InvalidColorTransform) { TEST(EncoderErrorHandlingTest, DuplicateComponentIds) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -477,7 +484,7 @@ TEST(EncoderErrorHandlingTest, DuplicateComponentIds) { TEST(EncoderErrorHandlingTest, InvalidComponentIndex) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -498,7 +505,7 @@ TEST(EncoderErrorHandlingTest, InvalidComponentIndex) { TEST(EncoderErrorHandlingTest, ArithmeticCoding) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -519,7 +526,7 @@ TEST(EncoderErrorHandlingTest, ArithmeticCoding) { TEST(EncoderErrorHandlingTest, CCIR601Sampling) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -540,7 +547,7 @@ TEST(EncoderErrorHandlingTest, CCIR601Sampling) { TEST(EncoderErrorHandlingTest, InvalidScanScript1) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -563,7 +570,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript1) { TEST(EncoderErrorHandlingTest, InvalidScanScript2) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -586,7 +593,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript2) { TEST(EncoderErrorHandlingTest, InvalidScanScript3) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -609,7 +616,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript3) { TEST(EncoderErrorHandlingTest, InvalidScanScript4) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -632,7 +639,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript4) { TEST(EncoderErrorHandlingTest, InvalidScanScript5) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -655,7 +662,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript5) { TEST(EncoderErrorHandlingTest, InvalidScanScript6) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -678,7 +685,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript6) { TEST(EncoderErrorHandlingTest, InvalidScanScript7) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -701,7 +708,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript7) { TEST(EncoderErrorHandlingTest, InvalidScanScript8) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -726,7 +733,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript8) { TEST(EncoderErrorHandlingTest, InvalidScanScript9) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -751,7 +758,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript9) { TEST(EncoderErrorHandlingTest, InvalidScanScript10) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -776,7 +783,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript10) { TEST(EncoderErrorHandlingTest, InvalidScanScript11) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -801,7 +808,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript11) { TEST(EncoderErrorHandlingTest, InvalidScanScript12) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -826,7 +833,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript12) { TEST(EncoderErrorHandlingTest, InvalidScanScript13) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -854,7 +861,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript13) { TEST(EncoderErrorHandlingTest, MCUSizeTooBig) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -877,7 +884,7 @@ TEST(EncoderErrorHandlingTest, MCUSizeTooBig) { TEST(EncoderErrorHandlingTest, RestartIntervalTooBig) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -898,7 +905,7 @@ TEST(EncoderErrorHandlingTest, RestartIntervalTooBig) { TEST(EncoderErrorHandlingTest, SamplingFactorTooBig) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -919,7 +926,7 @@ TEST(EncoderErrorHandlingTest, SamplingFactorTooBig) { TEST(EncoderErrorHandlingTest, NonIntegralSamplingRatio) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -996,6 +1003,9 @@ TEST(EncoderErrorHandlingTest, AddOnTableNoStringParam) { const uint8_t kCompressed0[] = { // SOI 0xff, 0xd8, // + // SOF + 0xff, 0xc0, 0x00, 0x0b, 0x08, 0x00, 0x01, 0x00, 0x01, 0x01, // + 0x01, 0x11, 0x00, // // DQT 0xff, 0xdb, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x03, 0x02, // 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x05, // @@ -1004,9 +1014,6 @@ const uint8_t kCompressed0[] = { 0x0e, 0x12, 0x10, 0x0d, 0x0e, 0x11, 0x0e, 0x0b, 0x0b, 0x10, // 0x16, 0x10, 0x11, 0x13, 0x14, 0x15, 0x15, 0x15, 0x0c, 0x0f, // 0x17, 0x18, 0x16, 0x14, 0x18, 0x12, 0x14, 0x15, 0x14, // - // SOF - 0xff, 0xc0, 0x00, 0x0b, 0x08, 0x00, 0x01, 0x00, 0x01, 0x01, // - 0x01, 0x11, 0x00, // // DHT 0xff, 0xc4, 0x00, 0xd2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, // 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // @@ -1039,16 +1046,16 @@ const uint8_t kCompressed0[] = { }; const size_t kLen0 = sizeof(kCompressed0); -const size_t kDQTOffset = 2; -const size_t kSOFOffset = 71; +const size_t kSOFOffset = 2; +const size_t kDQTOffset = 15; const size_t kDHTOffset = 84; const size_t kSOSOffset = 296; TEST(DecoderErrorHandlingTest, MinimalSuccess) { - JXL_CHECK(kCompressed0[kDQTOffset] == 0xff); - JXL_CHECK(kCompressed0[kSOFOffset] == 0xff); - JXL_CHECK(kCompressed0[kDHTOffset] == 0xff); - JXL_CHECK(kCompressed0[kSOSOffset] == 0xff); + ASSERT_TRUE(kCompressed0[kDQTOffset] == 0xff); + ASSERT_TRUE(kCompressed0[kSOFOffset] == 0xff); + ASSERT_TRUE(kCompressed0[kDHTOffset] == 0xff); + ASSERT_TRUE(kCompressed0[kSOSOffset] == 0xff); jpeg_decompress_struct cinfo = {}; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -1169,7 +1176,7 @@ TEST(DecoderErrorHandlingTest, InvalidDQT) { compressed[kDQTOffset + 3] += diff; EXPECT_FALSE(ParseCompressed(compressed)); } - // inavlid table index / precision + // invalid table index / precision for (int val : {0x20, 0x05}) { std::vector compressed(kCompressed0, kCompressed0 + kLen0); compressed[kDQTOffset + 4] = val; @@ -1234,7 +1241,7 @@ TEST(DecoderErrorHandlingTest, InvalidDHT) { compressed[kDHTOffset + 2] += 17; EXPECT_FALSE(ParseCompressed(compressed)); } - // inavlid table slot_id + // invalid table slot_id for (int val : {0x05, 0x15, 0x20}) { std::vector compressed(kCompressed0, kCompressed0 + kLen0); compressed[kDHTOffset + 4] = val; diff --git a/third_party/jpeg-xl/lib/jpegli/fuzztest.h b/third_party/jpeg-xl/lib/jpegli/fuzztest.h new file mode 100644 index 0000000000000..d5cde97713e67 --- /dev/null +++ b/third_party/jpeg-xl/lib/jpegli/fuzztest.h @@ -0,0 +1,22 @@ +// Copyright (c) the JPEG XL Project Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#ifndef LIB_JPEGLI_FUZZTEST_H_ +#define LIB_JPEGLI_FUZZTEST_H_ + +#include "lib/jxl/base/compiler_specific.h" + +#if !defined(FUZZ_TEST) +struct FuzzTestSink { + template + FuzzTestSink WithSeeds(F /*f*/) { + return *this; + } +}; +#define FUZZ_TEST(A, B) \ + const JXL_MAYBE_UNUSED FuzzTestSink unused##A##B = FuzzTestSink() +#endif + +#endif // LIB_JPEGLI_FUZZTEST_H_ diff --git a/third_party/jpeg-xl/lib/jpegli/huffman.cc b/third_party/jpeg-xl/lib/jpegli/huffman.cc index 5391030213379..6b068ab64f6ad 100644 --- a/third_party/jpeg-xl/lib/jpegli/huffman.cc +++ b/third_party/jpeg-xl/lib/jpegli/huffman.cc @@ -10,6 +10,7 @@ #include "lib/jpegli/common.h" #include "lib/jpegli/error.h" +#include "lib/jxl/base/status.h" namespace jpegli { diff --git a/third_party/jpeg-xl/lib/jpegli/idct.cc b/third_party/jpeg-xl/lib/jpegli/idct.cc index 9859e8ef85bfc..665a00d826de0 100644 --- a/third_party/jpeg-xl/lib/jpegli/idct.cc +++ b/third_party/jpeg-xl/lib/jpegli/idct.cc @@ -8,6 +8,7 @@ #include #include "lib/jpegli/decode_internal.h" +#include "lib/jxl/base/compiler_specific.h" #include "lib/jxl/base/status.h" #undef HWY_TARGET_INCLUDE @@ -62,15 +63,15 @@ void DequantBlock(const int16_t* JXL_RESTRICT qblock, } template -void ForwardEvenOdd(const float* JXL_RESTRICT ain, size_t ain_stride, - float* JXL_RESTRICT aout) { +void ForwardEvenOdd(const float* JXL_RESTRICT a_in, size_t a_in_stride, + float* JXL_RESTRICT a_out) { for (size_t i = 0; i < N / 2; i++) { - auto in1 = LoadU(d8, ain + 2 * i * ain_stride); - Store(in1, d8, aout + i * 8); + auto in1 = LoadU(d8, a_in + 2 * i * a_in_stride); + Store(in1, d8, a_out + i * 8); } for (size_t i = N / 2; i < N; i++) { - auto in1 = LoadU(d8, ain + (2 * (i - N / 2) + 1) * ain_stride); - Store(in1, d8, aout + i * 8); + auto in1 = LoadU(d8, a_in + (2 * (i - N / 2) + 1) * a_in_stride); + Store(in1, d8, a_out + i * 8); } } @@ -111,8 +112,10 @@ struct WcMultipliers<8> { }; }; +#if JXL_CXX_LANG < JXL_CXX_17 constexpr float WcMultipliers<4>::kMultipliers[]; constexpr float WcMultipliers<8>::kMultipliers[]; +#endif template void MultiplyAndAdd(const float* JXL_RESTRICT coeff, float* JXL_RESTRICT out, @@ -609,7 +612,7 @@ void Compute1dIDCT(const float* in, float* out, size_t N) { break; } default: - JXL_ABORT("Compute1dIDCT does not support N=%d", static_cast(N)); + JXL_DEBUG_ABORT("Unreachable"); break; } } @@ -679,16 +682,21 @@ namespace jpegli { HWY_EXPORT(InverseTransformBlock8x8); HWY_EXPORT(InverseTransformBlockGeneric); -void ChooseInverseTransform(j_decompress_ptr cinfo) { +jxl::Status ChooseInverseTransform(j_decompress_ptr cinfo) { jpeg_decomp_master* m = cinfo->master; for (int c = 0; c < cinfo->num_components; ++c) { - if (m->scaled_dct_size[c] == DCTSIZE) { + int dct_size = m->scaled_dct_size[c]; + if (dct_size < 1 || dct_size > 16) { + return JXL_FAILURE("Compute1dIDCT does not support N=%d", dct_size); + } + if (dct_size == DCTSIZE) { m->inverse_transform[c] = HWY_DYNAMIC_DISPATCH(InverseTransformBlock8x8); } else { m->inverse_transform[c] = HWY_DYNAMIC_DISPATCH(InverseTransformBlockGeneric); } } + return true; } } // namespace jpegli diff --git a/third_party/jpeg-xl/lib/jpegli/idct.h b/third_party/jpeg-xl/lib/jpegli/idct.h index c2ec6d18dc859..746b1562c1524 100644 --- a/third_party/jpeg-xl/lib/jpegli/idct.h +++ b/third_party/jpeg-xl/lib/jpegli/idct.h @@ -7,11 +7,11 @@ #define LIB_JPEGLI_IDCT_H_ #include "lib/jpegli/common.h" -#include "lib/jxl/base/compiler_specific.h" +#include "lib/jxl/base/status.h" namespace jpegli { -void ChooseInverseTransform(j_decompress_ptr cinfo); +jxl::Status ChooseInverseTransform(j_decompress_ptr cinfo); } // namespace jpegli diff --git a/third_party/jpeg-xl/lib/jpegli/input_suspension_test.cc b/third_party/jpeg-xl/lib/jpegli/input_suspension_test.cc index eb8b7ebc26da7..6fa1416213ce6 100644 --- a/third_party/jpeg-xl/lib/jpegli/input_suspension_test.cc +++ b/third_party/jpeg-xl/lib/jpegli/input_suspension_test.cc @@ -3,16 +3,24 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include +#include + +#include +#include #include +#include +#include +#include +#include +#include #include #include "lib/jpegli/decode.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/jxl/base/status.h" -#include "lib/jxl/sanitizers.h" namespace jpegli { namespace { @@ -80,7 +88,8 @@ struct SourceManager { static boolean fill_input_buffer(j_decompress_ptr cinfo) { return FALSE; } - static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) { + static void skip_input_data(j_decompress_ptr cinfo, + long num_bytes /* NOLINT*/) { auto* src = reinterpret_cast(cinfo->src); if (num_bytes <= 0) { return; @@ -119,8 +128,9 @@ boolean test_marker_processor(j_decompress_ptr cinfo) { return TRUE; } -void ReadOutputImage(const DecompressParams& dparams, j_decompress_ptr cinfo, - SourceManager* src, TestImage* output) { +jxl::Status ReadOutputImage(const DecompressParams& dparams, + j_decompress_ptr cinfo, SourceManager* src, + TestImage* output) { output->ysize = cinfo->output_height; output->xsize = cinfo->output_width; output->components = cinfo->num_components; @@ -160,7 +170,7 @@ void ReadOutputImage(const DecompressParams& dparams, j_decompress_ptr cinfo, } while ((num_output_lines = jpegli_read_raw_data(cinfo, data.data(), max_lines)) == 0) { - JXL_CHECK(src && src->LoadNextChunk()); + JXL_ENSURE(src && src->LoadNextChunk()); } } else { size_t max_output_lines = dparams.max_output_lines; @@ -175,15 +185,16 @@ void ReadOutputImage(const DecompressParams& dparams, j_decompress_ptr cinfo, } while ((num_output_lines = jpegli_read_scanlines(cinfo, scanlines.data(), max_lines)) == 0) { - JXL_CHECK(src && src->LoadNextChunk()); + JXL_ENSURE(src && src->LoadNextChunk()); } } total_output_lines += num_output_lines; EXPECT_EQ(total_output_lines, cinfo->output_scanline); if (num_output_lines < max_lines) { - JXL_CHECK(src && src->LoadNextChunk()); + JXL_ENSURE(src && src->LoadNextChunk()); } } + return true; } struct TestConfig { @@ -195,13 +206,15 @@ struct TestConfig { float max_rms_dist = 1.0f; }; -std::vector GetTestJpegData(TestConfig& config) { +jxl::StatusOr> GetTestJpegData(TestConfig& config) { + std::vector compressed; if (!config.fn.empty()) { - return ReadTestData(config.fn); + JXL_ASSIGN_OR_RETURN(compressed, ReadTestData(config.fn)); + } else { + GeneratePixels(&config.input); + JXL_RETURN_IF_ERROR( + EncodeWithJpegli(config.input, config.jparams, &compressed)); } - GeneratePixels(&config.input); - std::vector compressed; - JXL_CHECK(EncodeWithJpegli(config.input, config.jparams, &compressed)); return compressed; } @@ -217,7 +230,8 @@ class InputSuspensionTestParam : public ::testing::TestWithParam {}; TEST_P(InputSuspensionTestParam, InputOutputLockStepNonBuffered) { TestConfig config = GetParam(); const DecompressParams& dparams = config.dparams; - std::vector compressed = GetTestJpegData(config); + JXL_ASSIGN_OR_QUIT(std::vector compressed, GetTestJpegData(config), + "Failed to create test data."); bool is_partial = config.dparams.size_factor < 1.0f; if (is_partial) { compressed.resize(compressed.size() * config.dparams.size_factor); @@ -240,7 +254,7 @@ TEST_P(InputSuspensionTestParam, InputOutputLockStepNonBuffered) { jpegli_set_marker_processor(&cinfo, 0xe8, test_marker_processor); } while (jpegli_read_header(&cinfo, TRUE) == JPEG_SUSPENDED) { - JXL_CHECK(src.LoadNextChunk()); + JPEGLI_TEST_ENSURE_TRUE(src.LoadNextChunk()); } SetDecompressParams(dparams, &cinfo); jpegli_set_output_format(&cinfo, dparams.data_type, dparams.endianness); @@ -254,18 +268,18 @@ TEST_P(InputSuspensionTestParam, InputOutputLockStepNonBuffered) { if (dparams.output_mode == COEFFICIENTS) { jvirt_barray_ptr* coef_arrays; while ((coef_arrays = jpegli_read_coefficients(&cinfo)) == nullptr) { - JXL_CHECK(src.LoadNextChunk()); + JPEGLI_TEST_ENSURE_TRUE(src.LoadNextChunk()); } CopyCoefficients(&cinfo, coef_arrays, &output0); } else { while (!jpegli_start_decompress(&cinfo)) { - JXL_CHECK(src.LoadNextChunk()); + JPEGLI_TEST_ENSURE_TRUE(src.LoadNextChunk()); } - ReadOutputImage(dparams, &cinfo, &src, &output0); + JPEGLI_TEST_ENSURE_TRUE(ReadOutputImage(dparams, &cinfo, &src, &output0)); } while (!jpegli_finish_decompress(&cinfo)) { - JXL_CHECK(src.LoadNextChunk()); + JPEGLI_TEST_ENSURE_TRUE(src.LoadNextChunk()); } return true; }; @@ -281,7 +295,8 @@ TEST_P(InputSuspensionTestParam, InputOutputLockStepBuffered) { TestConfig config = GetParam(); if (config.jparams.add_marker) return; const DecompressParams& dparams = config.dparams; - std::vector compressed = GetTestJpegData(config); + JXL_ASSIGN_OR_QUIT(std::vector compressed, GetTestJpegData(config), + "Failed to create test data."); bool is_partial = config.dparams.size_factor < 1.0f; if (is_partial) { compressed.resize(compressed.size() * config.dparams.size_factor); @@ -297,7 +312,7 @@ TEST_P(InputSuspensionTestParam, InputOutputLockStepBuffered) { cinfo.src = reinterpret_cast(&src); while (jpegli_read_header(&cinfo, TRUE) == JPEG_SUSPENDED) { - JXL_CHECK(src.LoadNextChunk()); + JPEGLI_TEST_ENSURE_TRUE(src.LoadNextChunk()); } SetDecompressParams(dparams, &cinfo); jpegli_set_output_format(&cinfo, dparams.data_type, dparams.endianness); @@ -318,18 +333,18 @@ TEST_P(InputSuspensionTestParam, InputOutputLockStepBuffered) { EXPECT_EQ(cinfo.output_scan_number, cinfo.input_scan_number); EXPECT_EQ(cinfo.input_scan_number, sos_marker_cnt); TestImage output; - ReadOutputImage(dparams, &cinfo, &src, &output); + JPEGLI_TEST_ENSURE_TRUE(ReadOutputImage(dparams, &cinfo, &src, &output)); output_progression0.emplace_back(std::move(output)); // read scanlines/read raw data does not change input/output scan number EXPECT_EQ(cinfo.input_scan_number, sos_marker_cnt); EXPECT_EQ(cinfo.output_scan_number, cinfo.input_scan_number); while (!jpegli_finish_output(&cinfo)) { - JXL_CHECK(src.LoadNextChunk()); + JPEGLI_TEST_ENSURE_TRUE(src.LoadNextChunk()); } ++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); + JPEGLI_TEST_ENSURE_TRUE(coef_arrays != nullptr); CopyCoefficients(&cinfo, coef_arrays, &output_progression0.back()); } } @@ -355,7 +370,8 @@ TEST_P(InputSuspensionTestParam, PreConsumeInputBuffered) { TestConfig config = GetParam(); if (config.jparams.add_marker) return; const DecompressParams& dparams = config.dparams; - std::vector compressed = GetTestJpegData(config); + JXL_ASSIGN_OR_QUIT(std::vector compressed, GetTestJpegData(config), + "Failed to create test data."); bool is_partial = config.dparams.size_factor < 1.0f; if (is_partial) { compressed.resize(compressed.size() * config.dparams.size_factor); @@ -375,7 +391,7 @@ TEST_P(InputSuspensionTestParam, PreConsumeInputBuffered) { int status; while ((status = jpegli_consume_input(&cinfo)) != JPEG_REACHED_SOS) { if (status == JPEG_SUSPENDED) { - JXL_CHECK(src.LoadNextChunk()); + JPEGLI_TEST_ENSURE_TRUE(src.LoadNextChunk()); } } EXPECT_EQ(JPEG_REACHED_SOS, jpegli_consume_input(&cinfo)); @@ -390,7 +406,7 @@ TEST_P(InputSuspensionTestParam, PreConsumeInputBuffered) { while ((status = jpegli_consume_input(&cinfo)) != JPEG_REACHED_EOI) { if (status == JPEG_SUSPENDED) { - JXL_CHECK(src.LoadNextChunk()); + JPEGLI_TEST_ENSURE_TRUE(src.LoadNextChunk()); } } @@ -402,14 +418,15 @@ TEST_P(InputSuspensionTestParam, PreConsumeInputBuffered) { EXPECT_EQ(output_progression1.size(), cinfo.input_scan_number); EXPECT_EQ(cinfo.output_scan_number, cinfo.input_scan_number); - ReadOutputImage(dparams, &cinfo, nullptr, &output0); + JPEGLI_TEST_ENSURE_TRUE( + ReadOutputImage(dparams, &cinfo, nullptr, &output0)); EXPECT_EQ(output_progression1.size(), cinfo.input_scan_number); EXPECT_EQ(cinfo.output_scan_number, cinfo.input_scan_number); EXPECT_TRUE(jpegli_finish_output(&cinfo)); if (dparams.output_mode == COEFFICIENTS) { jvirt_barray_ptr* coef_arrays = jpegli_read_coefficients(&cinfo); - JXL_CHECK(coef_arrays != nullptr); + JPEGLI_TEST_ENSURE_TRUE(coef_arrays != nullptr); CopyCoefficients(&cinfo, coef_arrays, &output0); } EXPECT_TRUE(jpegli_finish_decompress(&cinfo)); @@ -425,7 +442,8 @@ TEST_P(InputSuspensionTestParam, PreConsumeInputNonBuffered) { TestConfig config = GetParam(); if (config.jparams.add_marker || IsSequential(config)) return; const DecompressParams& dparams = config.dparams; - std::vector compressed = GetTestJpegData(config); + JXL_ASSIGN_OR_QUIT(std::vector compressed, GetTestJpegData(config), + "Failed to create test data."); bool is_partial = config.dparams.size_factor < 1.0f; if (is_partial) { compressed.resize(compressed.size() * config.dparams.size_factor); @@ -442,7 +460,7 @@ TEST_P(InputSuspensionTestParam, PreConsumeInputNonBuffered) { int status; while ((status = jpegli_consume_input(&cinfo)) != JPEG_REACHED_SOS) { if (status == JPEG_SUSPENDED) { - JXL_CHECK(src.LoadNextChunk()); + JPEGLI_TEST_ENSURE_TRUE(src.LoadNextChunk()); } } EXPECT_EQ(JPEG_REACHED_SOS, jpegli_consume_input(&cinfo)); @@ -453,22 +471,23 @@ TEST_P(InputSuspensionTestParam, PreConsumeInputNonBuffered) { jpegli_read_coefficients(&cinfo); } else { while (!jpegli_start_decompress(&cinfo)) { - JXL_CHECK(src.LoadNextChunk()); + JPEGLI_TEST_ENSURE_TRUE(src.LoadNextChunk()); } } while ((status = jpegli_consume_input(&cinfo)) != JPEG_REACHED_EOI) { if (status == JPEG_SUSPENDED) { - JXL_CHECK(src.LoadNextChunk()); + JPEGLI_TEST_ENSURE_TRUE(src.LoadNextChunk()); } } if (dparams.output_mode == COEFFICIENTS) { jvirt_barray_ptr* coef_arrays = jpegli_read_coefficients(&cinfo); - JXL_CHECK(coef_arrays != nullptr); + JPEGLI_TEST_ENSURE_TRUE(coef_arrays != nullptr); CopyCoefficients(&cinfo, coef_arrays, &output0); } else { - ReadOutputImage(dparams, &cinfo, nullptr, &output0); + JPEGLI_TEST_ENSURE_TRUE( + ReadOutputImage(dparams, &cinfo, nullptr, &output0)); } EXPECT_TRUE(jpegli_finish_decompress(&cinfo)); diff --git a/third_party/jpeg-xl/lib/jpegli/libjpeg_test_util.cc b/third_party/jpeg-xl/lib/jpegli/libjpeg_test_util.cc index 020adf5e9e9ee..22088b3d214b2 100644 --- a/third_party/jpeg-xl/lib/jpegli/libjpeg_test_util.cc +++ b/third_party/jpeg-xl/lib/jpegli/libjpeg_test_util.cc @@ -5,18 +5,22 @@ #include "lib/jpegli/libjpeg_test_util.h" -/* clang-format off */ -#include -#include -#include -/* clang-format on */ +#include -#include "lib/jxl/sanitizers.h" +#include "lib/jxl/base/compiler_specific.h" +#include "lib/jxl/base/include_jpeglib.h" // NOLINT +#include "lib/jxl/base/sanitizers.h" namespace jpegli { namespace { +void Check(bool ok) { + if (!ok) { + JXL_CRASH(); + } +} + #define JPEG_API_FN(name) jpeg_##name #include "lib/jpegli/test_utils-inl.h" #undef JPEG_API_FN @@ -31,7 +35,7 @@ void ReadOutputPass(j_decompress_ptr cinfo, const DecompressParams& dparams, xoffset = xsize_cropped = cinfo->output_width / 3; yoffset = ysize_cropped = cinfo->output_height / 3; jpeg_crop_scanline(cinfo, &xoffset, &xsize_cropped); - JXL_CHECK(xsize_cropped == cinfo->output_width); + Check(xsize_cropped == cinfo->output_width); } output->xsize = xsize_cropped; output->ysize = ysize_cropped; @@ -56,7 +60,7 @@ void ReadOutputPass(j_decompress_ptr cinfo, const DecompressParams& dparams, for (size_t y = 0; y < output->ysize; ++y) { JSAMPROW rows[] = { reinterpret_cast(&output->pixels[y * stride])}; - JXL_CHECK(1 == jpeg_read_scanlines(cinfo, rows, 1)); + Check(1 == jpeg_read_scanlines(cinfo, rows, 1)); jxl::msan::UnpoisonMemory( rows[0], sizeof(JSAMPLE) * cinfo->output_components * output->xsize); if (cinfo->quantize_colors) { @@ -77,7 +81,7 @@ void ReadOutputPass(j_decompress_ptr cinfo, const DecompressParams& dparams, } while (cinfo->output_scanline < cinfo->output_height) { size_t iMCU_height = cinfo->max_v_samp_factor * DCTSIZE; - JXL_CHECK(cinfo->output_scanline == cinfo->output_iMCU_row * iMCU_height); + Check(cinfo->output_scanline == cinfo->output_iMCU_row * iMCU_height); std::vector> rowdata(cinfo->num_components); std::vector data(cinfo->num_components); for (int c = 0; c < cinfo->num_components; ++c) { @@ -92,12 +96,11 @@ void ReadOutputPass(j_decompress_ptr cinfo, const DecompressParams& dparams, } data[c] = rowdata[c].data(); } - JXL_CHECK(iMCU_height == - jpeg_read_raw_data(cinfo, data.data(), iMCU_height)); + Check(iMCU_height == jpeg_read_raw_data(cinfo, data.data(), iMCU_height)); } } - JXL_CHECK(cinfo->total_iMCU_rows == - DivCeil(cinfo->image_height, cinfo->max_v_samp_factor * DCTSIZE)); + Check(cinfo->total_iMCU_rows == + DivCeil(cinfo->image_height, cinfo->max_v_samp_factor * DCTSIZE)); } void DecodeWithLibjpeg(const CompressParams& jparams, @@ -110,29 +113,30 @@ void DecodeWithLibjpeg(const CompressParams& jparams, if (!jparams.icc.empty()) { jpeg_save_markers(cinfo, JPEG_APP0 + 2, 0xffff); } - JXL_CHECK(JPEG_REACHED_SOS == - jpeg_read_header(cinfo, /*require_image=*/TRUE)); + Check(JPEG_REACHED_SOS == jpeg_read_header(cinfo, /*require_image=*/TRUE)); if (!jparams.icc.empty()) { uint8_t* icc_data = nullptr; unsigned int icc_len = 0; // "unpoison" via initialization - JXL_CHECK(jpeg_read_icc_profile(cinfo, &icc_data, &icc_len)); - JXL_CHECK(icc_data); + Check(jpeg_read_icc_profile(cinfo, &icc_data, &icc_len)); + Check(icc_data); jxl::msan::UnpoisonMemory(icc_data, icc_len); - JXL_CHECK(0 == memcmp(jparams.icc.data(), icc_data, icc_len)); + Check(0 == memcmp(jparams.icc.data(), icc_data, icc_len)); free(icc_data); } SetDecompressParams(dparams, cinfo); VerifyHeader(jparams, cinfo); if (dparams.output_mode == COEFFICIENTS) { jvirt_barray_ptr* coef_arrays = jpeg_read_coefficients(cinfo); - JXL_CHECK(coef_arrays != nullptr); + Check(coef_arrays != nullptr); + jxl::msan::UnpoisonMemory(coef_arrays, + cinfo->num_components * sizeof(jvirt_barray_ptr)); CopyCoefficients(cinfo, coef_arrays, output); } else { - JXL_CHECK(jpeg_start_decompress(cinfo)); + Check(jpeg_start_decompress(cinfo)); VerifyScanHeader(jparams, cinfo); ReadOutputPass(cinfo, dparams, output); } - JXL_CHECK(jpeg_finish_decompress(cinfo)); + Check(jpeg_finish_decompress(cinfo)); } } // namespace @@ -164,18 +168,17 @@ void DecodeAllScansWithLibjpeg(const CompressParams& jparams, jpeg_save_markers(&cinfo, kSpecialMarker0, 0xffff); jpeg_save_markers(&cinfo, kSpecialMarker1, 0xffff); } - JXL_CHECK(JPEG_REACHED_SOS == - jpeg_read_header(&cinfo, /*require_image=*/TRUE)); + Check(JPEG_REACHED_SOS == jpeg_read_header(&cinfo, /*require_image=*/TRUE)); cinfo.buffered_image = TRUE; SetDecompressParams(dparams, &cinfo); VerifyHeader(jparams, &cinfo); - JXL_CHECK(jpeg_start_decompress(&cinfo)); + Check(jpeg_start_decompress(&cinfo)); // start decompress should not read the whole input in buffered image mode - JXL_CHECK(!jpeg_input_complete(&cinfo)); - JXL_CHECK(cinfo.output_scan_number == 0); + Check(!jpeg_input_complete(&cinfo)); + Check(cinfo.output_scan_number == 0); int sos_marker_cnt = 1; // read header reads the first SOS marker while (!jpeg_input_complete(&cinfo)) { - JXL_CHECK(cinfo.input_scan_number == sos_marker_cnt); + Check(cinfo.input_scan_number == sos_marker_cnt); if (dparams.skip_scans && (cinfo.input_scan_number % 2) != 1) { int result = JPEG_SUSPENDED; while (result != JPEG_REACHED_SOS && result != JPEG_REACHED_EOI) { @@ -185,32 +188,34 @@ void DecodeAllScansWithLibjpeg(const CompressParams& jparams, continue; } SetScanDecompressParams(dparams, &cinfo, cinfo.input_scan_number); - JXL_CHECK(jpeg_start_output(&cinfo, cinfo.input_scan_number)); + Check(jpeg_start_output(&cinfo, cinfo.input_scan_number)); // start output sets output_scan_number, but does not change // input_scan_number - JXL_CHECK(cinfo.output_scan_number == cinfo.input_scan_number); - JXL_CHECK(cinfo.input_scan_number == sos_marker_cnt); + Check(cinfo.output_scan_number == cinfo.input_scan_number); + Check(cinfo.input_scan_number == sos_marker_cnt); VerifyScanHeader(jparams, &cinfo); TestImage output; ReadOutputPass(&cinfo, dparams, &output); output_progression->emplace_back(std::move(output)); // read scanlines/read raw data does not change input/output scan number if (!cinfo.progressive_mode) { - JXL_CHECK(cinfo.input_scan_number == sos_marker_cnt); - JXL_CHECK(cinfo.output_scan_number == cinfo.input_scan_number); + Check(cinfo.input_scan_number == sos_marker_cnt); + Check(cinfo.output_scan_number == cinfo.input_scan_number); } - JXL_CHECK(jpeg_finish_output(&cinfo)); + Check(jpeg_finish_output(&cinfo)); ++sos_marker_cnt; // finish output reads the next SOS marker or EOI if (dparams.output_mode == COEFFICIENTS) { jvirt_barray_ptr* coef_arrays = jpeg_read_coefficients(&cinfo); - JXL_CHECK(coef_arrays != nullptr); + Check(coef_arrays != nullptr); + jxl::msan::UnpoisonMemory( + coef_arrays, cinfo.num_components * sizeof(jvirt_barray_ptr)); CopyCoefficients(&cinfo, coef_arrays, &output_progression->back()); } } - JXL_CHECK(jpeg_finish_decompress(&cinfo)); + Check(jpeg_finish_decompress(&cinfo)); return true; }; - JXL_CHECK(try_catch_block()); + Check(try_catch_block()); jpeg_destroy_decompress(&cinfo); } @@ -243,10 +248,11 @@ size_t DecodeWithLibjpeg(const CompressParams& jparams, } jpeg_mem_src(&cinfo, compressed, len); DecodeWithLibjpeg(jparams, dparams, &cinfo, output); + jxl::msan::UnpoisonMemory(cinfo.src, sizeof(jpeg_source_mgr)); bytes_read = len - cinfo.src->bytes_in_buffer; return true; }; - JXL_CHECK(try_catch_block()); + Check(try_catch_block()); jpeg_destroy_decompress(&cinfo); return bytes_read; } diff --git a/third_party/jpeg-xl/lib/jpegli/libjpeg_wrapper.cc b/third_party/jpeg-xl/lib/jpegli/libjpeg_wrapper.cc index 471b7c7192362..a2b333afef2c7 100644 --- a/third_party/jpeg-xl/lib/jpegli/libjpeg_wrapper.cc +++ b/third_party/jpeg-xl/lib/jpegli/libjpeg_wrapper.cc @@ -38,7 +38,7 @@ void jpeg_stdio_src(j_decompress_ptr cinfo, FILE *infile) { } void jpeg_mem_src(j_decompress_ptr cinfo, const unsigned char *inbuffer, - unsigned long insize) { + unsigned long insize /* NOLINT */) { jpegli_mem_src(cinfo, inbuffer, insize); } @@ -138,7 +138,7 @@ void jpeg_stdio_dest(j_compress_ptr cinfo, FILE *outfile) { } void jpeg_mem_dest(j_compress_ptr cinfo, unsigned char **outbuffer, - unsigned long *outsize) { + unsigned long *outsize /* NOLINT */) { jpegli_mem_dest(cinfo, outbuffer, outsize); } diff --git a/third_party/jpeg-xl/lib/jpegli/output_suspension_test.cc b/third_party/jpeg-xl/lib/jpegli/output_suspension_test.cc index 3cb2fd3ee49a2..44d63fdcbb4d0 100644 --- a/third_party/jpeg-xl/lib/jpegli/output_suspension_test.cc +++ b/third_party/jpeg-xl/lib/jpegli/output_suspension_test.cc @@ -3,7 +3,18 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include +#include +#include +#include +#include +#include +#include +#include + #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" @@ -130,6 +141,7 @@ TEST_P(OutputSuspensionTestParam, RawData) { cinfo.input_components = input.components; cinfo.in_color_space = JCS_YCbCr; jpegli_set_defaults(&cinfo); + cinfo.comp_info[0].h_samp_factor = config.jparams.h_sampling[0]; cinfo.comp_info[0].v_samp_factor = config.jparams.v_sampling[0]; jpegli_set_progressive_level(&cinfo, 0); cinfo.optimize_coding = FALSE; diff --git a/third_party/jpeg-xl/lib/jpegli/render.cc b/third_party/jpeg-xl/lib/jpegli/render.cc index c550f9a575ddd..1510401fa70e6 100644 --- a/third_party/jpeg-xl/lib/jpegli/render.cc +++ b/third_party/jpeg-xl/lib/jpegli/render.cc @@ -5,13 +5,11 @@ #include "lib/jpegli/render.h" -#include - #include #include #include #include -#include +#include #include #include "lib/jpegli/color_quantize.h" @@ -22,7 +20,6 @@ #include "lib/jpegli/upsample.h" #include "lib/jxl/base/byte_order.h" #include "lib/jxl/base/compiler_specific.h" -#include "lib/jxl/base/status.h" #ifdef MEMORY_SANITIZER #define JXL_MEMORY_SANITIZER 1 @@ -431,7 +428,7 @@ void PredictSmooth(j_decompress_ptr cinfo, JBLOCKARRAY blocks, int component, } } // Get the correct coef_bits: In case of an incomplete scan, we use the - // prev coeficients. + // prev coefficients. if (cinfo->output_iMCU_row + 1 > cinfo->input_iMCU_row) { coef_bits = cinfo->master->prev_coef_bits_latch[component]; } else { @@ -466,8 +463,8 @@ void PredictSmooth(j_decompress_ptr cinfo, JBLOCKARRAY blocks, int component, auto dc = [&](int i, int j) { return swap_indices ? dc_values[j][i] : dc_values[i][j]; }; + JPEGLI_CHECK(coef_index >= 0 && coef_index < 10); Al = coef_bits[coef_index]; - JXL_ASSERT(coef_index >= 0 && coef_index < 10); switch (coef_index) { case 0: // set the DC @@ -569,21 +566,21 @@ void PrepareForOutput(j_decompress_ptr cinfo) { m->dequant_[c * DCTSIZE2 + k] = table->quantval[k] * kDequantScale; } } - ChooseInverseTransform(cinfo); + JPEGLI_CHECK(ChooseInverseTransform(cinfo)); ChooseColorTransform(cinfo); } void DecodeCurrentiMCURow(j_decompress_ptr cinfo) { jpeg_decomp_master* m = cinfo->master; const size_t imcu_row = cinfo->output_iMCU_row; - JBLOCKARRAY ba[kMaxComponents]; + JBLOCKARRAY blocks[kMaxComponents]; for (int c = 0; c < cinfo->num_components; ++c) { const jpeg_component_info* comp = &cinfo->comp_info[c]; int by0 = imcu_row * comp->v_samp_factor; int block_rows_left = comp->height_in_blocks - by0; int max_block_rows = std::min(comp->v_samp_factor, block_rows_left); int offset = m->streaming_mode_ ? 0 : by0; - ba[c] = (*cinfo->mem->access_virt_barray)( + blocks[c] = (*cinfo->mem->access_virt_barray)( reinterpret_cast(cinfo), m->coef_arrays[c], offset, max_block_rows, FALSE); } @@ -598,7 +595,7 @@ void DecodeCurrentiMCURow(j_decompress_ptr cinfo) { if (by >= compinfo.height_in_blocks) { continue; } - int16_t* JXL_RESTRICT coeffs = &ba[c][iy][0][0]; + int16_t* JXL_RESTRICT coeffs = &blocks[c][iy][0][0]; size_t num = compinfo.width_in_blocks * DCTSIZE2; GatherBlockStats(coeffs, num, &m->nonzeros_[k0], &m->sumabs_[k0]); m->num_processed_blocks_[c] += compinfo.width_in_blocks; @@ -617,11 +614,11 @@ void DecodeCurrentiMCURow(j_decompress_ptr cinfo) { continue; } size_t dctsize = m->scaled_dct_size[c]; - int16_t* JXL_RESTRICT row_in = &ba[c][iy][0][0]; + int16_t* JXL_RESTRICT row_in = &blocks[c][iy][0][0]; float* JXL_RESTRICT row_out = raw_out->Row(by * dctsize); for (size_t bx = 0; bx < compinfo.width_in_blocks; ++bx) { if (m->apply_smoothing) { - PredictSmooth(cinfo, ba[c], c, bx, iy); + PredictSmooth(cinfo, blocks[c], c, bx, iy); (*m->inverse_transform[c])(m->smoothing_scratch_, &m->dequant_[k0], &m->biases_[k0], m->idct_scratch_, &row_out[bx * dctsize], raw_out->stride(), @@ -746,7 +743,7 @@ void ProcessOutput(j_decompress_ptr cinfo, size_t* num_output_rows, WriteToOutput(cinfo, rows, m->xoffset_, cinfo->output_width, cinfo->out_color_components, output); } - JXL_ASSERT(cinfo->output_scanline == y + yix); + JPEGLI_CHECK(cinfo->output_scanline == y + yix); ++cinfo->output_scanline; ++(*num_output_rows); if (cinfo->output_scanline == cinfo->output_height) { diff --git a/third_party/jpeg-xl/lib/jpegli/source_manager.cc b/third_party/jpeg-xl/lib/jpegli/source_manager.cc index 58adf803b1f0f..e0f0b4c275a12 100644 --- a/third_party/jpeg-xl/lib/jpegli/source_manager.cc +++ b/third_party/jpeg-xl/lib/jpegli/source_manager.cc @@ -12,9 +12,10 @@ namespace jpegli { void init_mem_source(j_decompress_ptr cinfo) {} void init_stdio_source(j_decompress_ptr cinfo) {} -void skip_input_data(j_decompress_ptr cinfo, long num_bytes) { +void skip_input_data(j_decompress_ptr cinfo, long num_bytes /* NOLINT */) { if (num_bytes <= 0) return; - while (num_bytes > static_cast(cinfo->src->bytes_in_buffer)) { + while (num_bytes > + static_cast(cinfo->src->bytes_in_buffer)) { // NOLINT num_bytes -= cinfo->src->bytes_in_buffer; (*cinfo->src->fill_input_buffer)(cinfo); } @@ -53,7 +54,7 @@ struct StdioSourceManager { } // namespace jpegli void jpegli_mem_src(j_decompress_ptr cinfo, const unsigned char* inbuffer, - unsigned long insize) { + unsigned long insize /* NOLINT */) { if (cinfo->src && cinfo->src->init_source != jpegli::init_mem_source) { JPEGLI_ERROR("jpegli_mem_src: a different source manager was already set"); } diff --git a/third_party/jpeg-xl/lib/jpegli/source_manager_test.cc b/third_party/jpeg-xl/lib/jpegli/source_manager_test.cc index 59d12b001b0d9..b70b43d8dbef3 100644 --- a/third_party/jpeg-xl/lib/jpegli/source_manager_test.cc +++ b/third_party/jpeg-xl/lib/jpegli/source_manager_test.cc @@ -3,11 +3,18 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include +#include #include +#include +#include +#include +#include +#include #include #include "lib/jpegli/decode.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/status.h" @@ -43,14 +50,15 @@ FILE* MemOpen(const std::vector& data) { FILE* src = tmpfile(); if (!src) return nullptr; fwrite(data.data(), 1, data.size(), src); - rewind(src); + fseek(src, 0, SEEK_SET); return src; } } // namespace TEST_P(SourceManagerTestParam, TestStdioSourceManager) { TestConfig config = GetParam(); - std::vector compressed = ReadTestData(config.fn); + JXL_ASSIGN_OR_QUIT(std::vector compressed, ReadTestData(config.fn), + "Failed to read test data."); if (config.dparams.size_factor < 1.0) { compressed.resize(compressed.size() * config.dparams.size_factor); } @@ -77,7 +85,8 @@ TEST_P(SourceManagerTestParam, TestStdioSourceManager) { TEST_P(SourceManagerTestParam, TestMemSourceManager) { TestConfig config = GetParam(); - std::vector compressed = ReadTestData(config.fn); + JXL_ASSIGN_OR_QUIT(std::vector compressed, ReadTestData(config.fn), + "Failed to read test data."); if (config.dparams.size_factor < 1.0f) { compressed.resize(compressed.size() * config.dparams.size_factor); } diff --git a/third_party/jpeg-xl/lib/jpegli/streaming_test.cc b/third_party/jpeg-xl/lib/jpegli/streaming_test.cc index 2e6f7029b0d85..ae85fd2451a18 100644 --- a/third_party/jpeg-xl/lib/jpegli/streaming_test.cc +++ b/third_party/jpeg-xl/lib/jpegli/streaming_test.cc @@ -3,8 +3,18 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include +#include +#include +#include +#include +#include +#include +#include + #include "lib/jpegli/decode.h" #include "lib/jpegli/encode.h" +#include "lib/jpegli/test_params.h" #include "lib/jpegli/test_utils.h" #include "lib/jpegli/testing.h" @@ -28,7 +38,8 @@ struct SourceManager { static void init_source(j_decompress_ptr cinfo) {} static boolean fill_input_buffer(j_decompress_ptr cinfo) { return FALSE; } - 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 */) {} static void term_source(j_decompress_ptr cinfo) {} }; @@ -117,26 +128,26 @@ TEST_P(StreamingTestParam, TestStreaming) { size_t stride = cinfo.image_width * cinfo.input_components; size_t iMCU_height = 8 * cinfo.max_v_samp_factor; std::vector row_bytes(iMCU_height * stride); - size_t yin = 0; - size_t yout = 0; - while (yin < cinfo.image_height) { + size_t y_in = 0; + size_t y_out = 0; + while (y_in < cinfo.image_height) { // Feed one iMCU row at a time to the compressor. - size_t lines_in = std::min(iMCU_height, cinfo.image_height - yin); - memcpy(row_bytes.data(), &input.pixels[yin * stride], lines_in * stride); + size_t lines_in = std::min(iMCU_height, cinfo.image_height - y_in); + memcpy(row_bytes.data(), &input.pixels[y_in * stride], lines_in * stride); std::vector rows_in(lines_in); for (size_t i = 0; i < lines_in; ++i) { rows_in[i] = &row_bytes[i * stride]; } EXPECT_EQ(lines_in, jpegli_write_scanlines(&cinfo, rows_in.data(), lines_in)); - yin += lines_in; - if (yin == cinfo.image_height) { + y_in += lines_in; + if (y_in == cinfo.image_height) { jpegli_finish_compress(&cinfo); } // Atfer the first iMCU row, we don't yet expect any output because the // compressor delays processing to have context rows after the iMCU row. - if (yin < std::min(2 * iMCU_height, cinfo.image_height)) { + if (y_in < std::min(2 * iMCU_height, cinfo.image_height)) { continue; } @@ -144,7 +155,7 @@ TEST_P(StreamingTestParam, TestStreaming) { // data. We check here that at least the scan header was output, because // we expect that the compressor's output buffer was filled at least once // while emitting the first compressed iMCU row. - if (yin == std::min(2 * iMCU_height, cinfo.image_height)) { + if (y_in == std::min(2 * iMCU_height, cinfo.image_height)) { EXPECT_EQ(JPEG_REACHED_SOS, jpegli_read_header(&dinfo, /*require_image=*/TRUE)); output.xsize = dinfo.image_width; @@ -155,7 +166,7 @@ TEST_P(StreamingTestParam, TestStreaming) { EXPECT_EQ(output.components, input.components); EXPECT_TRUE(jpegli_start_decompress(&dinfo)); output.pixels.resize(output.ysize * stride); - if (yin < cinfo.image_height) { + if (y_in < cinfo.image_height) { continue; } } @@ -165,7 +176,7 @@ TEST_P(StreamingTestParam, TestStreaming) { // data to be in the decoder's input buffer, but since the decoder also // needs context rows for upsampling and smoothing, we don't expect any // output to be ready yet. - if (yin < 7 * iMCU_height && yin < cinfo.image_height) { + if (y_in < 7 * iMCU_height && y_in < cinfo.image_height) { continue; } @@ -173,18 +184,19 @@ TEST_P(StreamingTestParam, TestStreaming) { // with four iMCU rows of delay. // TODO(szabadka) Reduce the processing delay in the decoder if possible. size_t lines_out = - (yin == cinfo.image_height ? cinfo.image_height - yout : iMCU_height); + (y_in == cinfo.image_height ? cinfo.image_height - y_out + : iMCU_height); std::vector rows_out(lines_out); for (size_t i = 0; i < lines_out; ++i) { rows_out[i] = - reinterpret_cast(&output.pixels[(yout + i) * stride]); + reinterpret_cast(&output.pixels[(y_out + i) * stride]); } EXPECT_EQ(lines_out, jpegli_read_scanlines(&dinfo, rows_out.data(), lines_out)); - VerifyOutputImage(input, output, yout, lines_out, 3.8f); - yout += lines_out; + VerifyOutputImage(input, output, y_out, lines_out, 3.8f); + y_out += lines_out; - if (yout == cinfo.image_height) { + if (y_out == cinfo.image_height) { EXPECT_TRUE(jpegli_finish_decompress(&dinfo)); } } diff --git a/third_party/jpeg-xl/lib/jpegli/test_utils-inl.h b/third_party/jpeg-xl/lib/jpegli/test_utils-inl.h index 4fbcb721e4c61..da1a924e21f85 100644 --- a/third_party/jpeg-xl/lib/jpegli/test_utils-inl.h +++ b/third_party/jpeg-xl/lib/jpegli/test_utils-inl.h @@ -183,11 +183,11 @@ void SetScanDecompressParams(const DecompressParams& dparams, cinfo->two_pass_quantize = FALSE; cinfo->colormap = nullptr; } else if (sparams->color_quant_mode == CQUANT_2PASS) { - JXL_CHECK(cinfo->out_color_space == JCS_RGB); + Check(cinfo->out_color_space == JCS_RGB); cinfo->two_pass_quantize = TRUE; cinfo->colormap = nullptr; } else if (sparams->color_quant_mode == CQUANT_EXTERNAL) { - JXL_CHECK(cinfo->out_color_space == JCS_RGB); + Check(cinfo->out_color_space == JCS_RGB); cinfo->two_pass_quantize = FALSE; bool have_colormap = cinfo->colormap != nullptr; cinfo->actual_number_of_colors = kTestColorMapNumColors; @@ -205,8 +205,8 @@ void SetScanDecompressParams(const DecompressParams& dparams, JPEG_API_FN(new_colormap)(cinfo); } } else if (sparams->color_quant_mode == CQUANT_REUSE) { - JXL_CHECK(cinfo->out_color_space == JCS_RGB); - JXL_CHECK(cinfo->colormap); + Check(cinfo->out_color_space == JCS_RGB); + Check(cinfo->colormap); } } } @@ -259,18 +259,18 @@ void CheckMarkerPresent(j_decompress_ptr cinfo, uint8_t marker_type) { marker_found = true; } } - JXL_CHECK(marker_found); + Check(marker_found); } void VerifyHeader(const CompressParams& jparams, j_decompress_ptr cinfo) { if (jparams.set_jpeg_colorspace) { - JXL_CHECK(cinfo->jpeg_color_space == jparams.jpeg_color_space); + Check(cinfo->jpeg_color_space == jparams.jpeg_color_space); } if (jparams.override_JFIF >= 0) { - JXL_CHECK(cinfo->saw_JFIF_marker == jparams.override_JFIF); + Check(cinfo->saw_JFIF_marker == jparams.override_JFIF); } if (jparams.override_Adobe >= 0) { - JXL_CHECK(cinfo->saw_Adobe_marker == jparams.override_Adobe); + Check(cinfo->saw_Adobe_marker == jparams.override_Adobe); } if (jparams.add_marker) { CheckMarkerPresent(cinfo, kSpecialMarker0); @@ -283,114 +283,114 @@ void VerifyHeader(const CompressParams& jparams, j_decompress_ptr cinfo) { for (int i = 0; i < cinfo->num_components; ++i) { jpeg_component_info* comp = &cinfo->comp_info[i]; if (!jparams.comp_ids.empty()) { - JXL_CHECK(comp->component_id == jparams.comp_ids[i]); + Check(comp->component_id == jparams.comp_ids[i]); } if (!jparams.h_sampling.empty()) { - JXL_CHECK(comp->h_samp_factor == jparams.h_sampling[i]); + Check(comp->h_samp_factor == jparams.h_sampling[i]); } if (!jparams.v_sampling.empty()) { - JXL_CHECK(comp->v_samp_factor == jparams.v_sampling[i]); + Check(comp->v_samp_factor == jparams.v_sampling[i]); } if (!jparams.quant_indexes.empty()) { - JXL_CHECK(comp->quant_tbl_no == jparams.quant_indexes[i]); + Check(comp->quant_tbl_no == jparams.quant_indexes[i]); } max_h_samp_factor = std::max(max_h_samp_factor, comp->h_samp_factor); max_v_samp_factor = std::max(max_v_samp_factor, comp->v_samp_factor); } - JXL_CHECK(max_h_samp_factor == cinfo->max_h_samp_factor); - JXL_CHECK(max_v_samp_factor == cinfo->max_v_samp_factor); + Check(max_h_samp_factor == cinfo->max_h_samp_factor); + Check(max_v_samp_factor == cinfo->max_v_samp_factor); int referenced_tables[NUM_QUANT_TBLS] = {}; for (int i = 0; i < cinfo->num_components; ++i) { jpeg_component_info* comp = &cinfo->comp_info[i]; - JXL_CHECK(comp->width_in_blocks == - DivCeil(cinfo->image_width * comp->h_samp_factor, - max_h_samp_factor * DCTSIZE)); - JXL_CHECK(comp->height_in_blocks == - DivCeil(cinfo->image_height * comp->v_samp_factor, - max_v_samp_factor * DCTSIZE)); + Check(comp->width_in_blocks == + DivCeil(cinfo->image_width * comp->h_samp_factor, + max_h_samp_factor * DCTSIZE)); + Check(comp->height_in_blocks == + DivCeil(cinfo->image_height * comp->v_samp_factor, + max_v_samp_factor * DCTSIZE)); referenced_tables[comp->quant_tbl_no] = 1; } for (const auto& table : jparams.quant_tables) { JQUANT_TBL* quant_table = cinfo->quant_tbl_ptrs[table.slot_idx]; if (!referenced_tables[table.slot_idx]) { - JXL_CHECK(quant_table == nullptr); + Check(quant_table == nullptr); continue; } - JXL_CHECK(quant_table != nullptr); + Check(quant_table != nullptr); jxl::msan::UnpoisonMemory(quant_table, sizeof(*quant_table)); for (int k = 0; k < DCTSIZE2; ++k) { - JXL_CHECK(quant_table->quantval[k] == table.quantval[k]); + Check(quant_table->quantval[k] == table.quantval[k]); } } } void VerifyScanHeader(const CompressParams& jparams, j_decompress_ptr cinfo) { - JXL_CHECK(cinfo->input_scan_number > 0); + Check(cinfo->input_scan_number > 0); if (cinfo->progressive_mode) { - JXL_CHECK(cinfo->Ss != 0 || cinfo->Se != 63); + Check(cinfo->Ss != 0 || cinfo->Se != 63); } else { - JXL_CHECK(cinfo->Ss == 0 && cinfo->Se == 63); + Check(cinfo->Ss == 0 && cinfo->Se == 63); } if (jparams.progressive_mode > 2) { - JXL_CHECK(jparams.progressive_mode < 3 + kNumTestScripts); + Check(jparams.progressive_mode < 3 + kNumTestScripts); const ScanScript& script = kTestScript[jparams.progressive_mode - 3]; - JXL_CHECK(cinfo->input_scan_number <= script.num_scans); + Check(cinfo->input_scan_number <= script.num_scans); const jpeg_scan_info& scan = script.scans[cinfo->input_scan_number - 1]; - JXL_CHECK(cinfo->comps_in_scan == scan.comps_in_scan); + Check(cinfo->comps_in_scan == scan.comps_in_scan); for (int i = 0; i < cinfo->comps_in_scan; ++i) { - JXL_CHECK(cinfo->cur_comp_info[i]->component_index == - scan.component_index[i]); + Check(cinfo->cur_comp_info[i]->component_index == + scan.component_index[i]); } - JXL_CHECK(cinfo->Ss == scan.Ss); - JXL_CHECK(cinfo->Se == scan.Se); - JXL_CHECK(cinfo->Ah == scan.Ah); - JXL_CHECK(cinfo->Al == scan.Al); + Check(cinfo->Ss == scan.Ss); + Check(cinfo->Se == scan.Se); + Check(cinfo->Ah == scan.Ah); + Check(cinfo->Al == scan.Al); } if (jparams.restart_interval > 0) { - JXL_CHECK(cinfo->restart_interval == jparams.restart_interval); + Check(cinfo->restart_interval == jparams.restart_interval); } else if (jparams.restart_in_rows > 0) { - JXL_CHECK(cinfo->restart_interval == - jparams.restart_in_rows * cinfo->MCUs_per_row); + Check(cinfo->restart_interval == + jparams.restart_in_rows * cinfo->MCUs_per_row); } if (jparams.progressive_mode == 0 && jparams.optimize_coding == 0) { if (cinfo->jpeg_color_space == JCS_RGB) { - JXL_CHECK(cinfo->comp_info[0].dc_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[1].dc_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[2].dc_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[0].ac_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[1].ac_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[2].ac_tbl_no == 0); + Check(cinfo->comp_info[0].dc_tbl_no == 0); + Check(cinfo->comp_info[1].dc_tbl_no == 0); + Check(cinfo->comp_info[2].dc_tbl_no == 0); + Check(cinfo->comp_info[0].ac_tbl_no == 0); + Check(cinfo->comp_info[1].ac_tbl_no == 0); + Check(cinfo->comp_info[2].ac_tbl_no == 0); } else if (cinfo->jpeg_color_space == JCS_YCbCr) { - JXL_CHECK(cinfo->comp_info[0].dc_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[1].dc_tbl_no == 1); - JXL_CHECK(cinfo->comp_info[2].dc_tbl_no == 1); - JXL_CHECK(cinfo->comp_info[0].ac_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[1].ac_tbl_no == 1); - JXL_CHECK(cinfo->comp_info[2].ac_tbl_no == 1); + Check(cinfo->comp_info[0].dc_tbl_no == 0); + Check(cinfo->comp_info[1].dc_tbl_no == 1); + Check(cinfo->comp_info[2].dc_tbl_no == 1); + Check(cinfo->comp_info[0].ac_tbl_no == 0); + Check(cinfo->comp_info[1].ac_tbl_no == 1); + Check(cinfo->comp_info[2].ac_tbl_no == 1); } else if (cinfo->jpeg_color_space == JCS_CMYK) { - JXL_CHECK(cinfo->comp_info[0].dc_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[1].dc_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[2].dc_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[3].dc_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[0].ac_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[1].ac_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[2].ac_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[3].ac_tbl_no == 0); + Check(cinfo->comp_info[0].dc_tbl_no == 0); + Check(cinfo->comp_info[1].dc_tbl_no == 0); + Check(cinfo->comp_info[2].dc_tbl_no == 0); + Check(cinfo->comp_info[3].dc_tbl_no == 0); + Check(cinfo->comp_info[0].ac_tbl_no == 0); + Check(cinfo->comp_info[1].ac_tbl_no == 0); + Check(cinfo->comp_info[2].ac_tbl_no == 0); + Check(cinfo->comp_info[3].ac_tbl_no == 0); } else if (cinfo->jpeg_color_space == JCS_YCCK) { - JXL_CHECK(cinfo->comp_info[0].dc_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[1].dc_tbl_no == 1); - JXL_CHECK(cinfo->comp_info[2].dc_tbl_no == 1); - JXL_CHECK(cinfo->comp_info[3].dc_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[0].ac_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[1].ac_tbl_no == 1); - JXL_CHECK(cinfo->comp_info[2].ac_tbl_no == 1); - JXL_CHECK(cinfo->comp_info[3].ac_tbl_no == 0); + Check(cinfo->comp_info[0].dc_tbl_no == 0); + Check(cinfo->comp_info[1].dc_tbl_no == 1); + Check(cinfo->comp_info[2].dc_tbl_no == 1); + Check(cinfo->comp_info[3].dc_tbl_no == 0); + Check(cinfo->comp_info[0].ac_tbl_no == 0); + Check(cinfo->comp_info[1].ac_tbl_no == 1); + Check(cinfo->comp_info[2].ac_tbl_no == 1); + Check(cinfo->comp_info[3].ac_tbl_no == 0); } if (jparams.use_flat_dc_luma_code) { JHUFF_TBL* tbl = cinfo->dc_huff_tbl_ptrs[0]; jxl::msan::UnpoisonMemory(tbl, sizeof(*tbl)); for (int i = 0; i < 15; ++i) { - JXL_CHECK(tbl->huffval[i] == i); + Check(tbl->huffval[i] == i); } } } @@ -398,10 +398,10 @@ void VerifyScanHeader(const CompressParams& jparams, j_decompress_ptr cinfo) { void UnmapColors(uint8_t* row, size_t xsize, int components, JSAMPARRAY colormap, size_t num_colors) { - JXL_CHECK(colormap != nullptr); + Check(colormap != nullptr); std::vector tmp(xsize * components); for (size_t x = 0; x < xsize; ++x) { - JXL_CHECK(row[x] < num_colors); + Check(row[x] < num_colors); for (int c = 0; c < components; ++c) { tmp[x * components + c] = colormap[c][row[x]]; } @@ -421,11 +421,11 @@ void CopyCoefficients(j_decompress_ptr cinfo, jvirt_barray_ptr* coef_arrays, std::vector coeffs(comp->width_in_blocks * comp->height_in_blocks * DCTSIZE2); for (size_t by = 0; by < comp->height_in_blocks; ++by) { - JBLOCKARRAY ba = (*cinfo->mem->access_virt_barray)(comptr, coef_arrays[c], - by, 1, TRUE); + JBLOCKARRAY blocks = (*cinfo->mem->access_virt_barray)( + comptr, coef_arrays[c], by, 1, TRUE); size_t stride = comp->width_in_blocks * sizeof(JBLOCK); size_t offset = by * comp->width_in_blocks * DCTSIZE2; - memcpy(&coeffs[offset], ba[0], stride); + memcpy(&coeffs[offset], blocks[0], stride); } output->coeffs.emplace_back(std::move(coeffs)); } diff --git a/third_party/jpeg-xl/lib/jpegli/test_utils.cc b/third_party/jpeg-xl/lib/jpegli/test_utils.cc index 4e675070cf717..2b903fa0c022f 100644 --- a/third_party/jpeg-xl/lib/jpegli/test_utils.cc +++ b/third_party/jpeg-xl/lib/jpegli/test_utils.cc @@ -7,14 +7,17 @@ #include #include +#include #include +#include #include "lib/jpegli/decode.h" #include "lib/jpegli/encode.h" #include "lib/jxl/base/byte_order.h" +#include "lib/jxl/base/compiler_specific.h" #include "lib/jxl/base/printf_macros.h" +#include "lib/jxl/base/sanitizers.h" #include "lib/jxl/base/status.h" -#include "lib/jxl/sanitizers.h" #if !defined(TEST_DATA_PATH) #include "tools/cpp/runfiles/runfiles.h" @@ -22,6 +25,15 @@ namespace jpegli { +namespace { +void Check(bool ok) { + if (!ok) { + JXL_CRASH(); + } +} +#define QUIT(M) Check(false); +} // namespace + #define JPEG_API_FN(name) jpegli_##name #include "lib/jpegli/test_utils-inl.h" #undef JPEG_API_FN @@ -31,7 +43,7 @@ std::string GetTestDataPath(const std::string& filename) { return std::string(TEST_DATA_PATH "/") + filename; } #else -using bazel::tools::cpp::runfiles::Runfiles; +using ::bazel::tools::cpp::runfiles::Runfiles; const std::unique_ptr kRunfiles(Runfiles::Create("")); std::string GetTestDataPath(const std::string& filename) { std::string root(JPEGXL_ROOT_PACKAGE "/testdata/"); @@ -39,15 +51,16 @@ std::string GetTestDataPath(const std::string& filename) { } #endif -std::vector ReadTestData(const std::string& filename) { +jxl::StatusOr> ReadTestData(const std::string& filename) { + std::vector data; std::string full_path = GetTestDataPath(filename); fprintf(stderr, "ReadTestData %s\n", full_path.c_str()); std::ifstream file(full_path, std::ios::binary); std::vector str((std::istreambuf_iterator(file)), std::istreambuf_iterator()); - JXL_CHECK(file.good()); + JXL_ENSURE(file.good()); const uint8_t* raw = reinterpret_cast(str.data()); - std::vector data(raw, raw + str.size()); + data = std::vector(raw, raw + str.size()); printf("Test data %s is %d bytes long.\n", filename.c_str(), static_cast(data.size())); return data; @@ -171,6 +184,18 @@ std::string ColorSpaceName(J_COLOR_SPACE colorspace) { return "CMYK"; case JCS_YCCK: return "YCCK"; + case JCS_EXT_RGB: + return "EXT_RGB"; + case JCS_EXT_BGR: + return "EXT_BGR"; + case JCS_EXT_RGBA: + return "EXT_RGBA"; + case JCS_EXT_BGRA: + return "EXT_BGRA"; + case JCS_EXT_ARGB: + return "EXT_ARGB"; + case JCS_EXT_ABGR: + return "EXT_ABGR"; default: return ""; } @@ -196,7 +221,7 @@ std::string IOMethodName(JpegliDataType data_type, std::string SamplingId(const CompressParams& jparams) { std::stringstream os; - JXL_CHECK(jparams.h_sampling.size() == jparams.v_sampling.size()); + Check(jparams.h_sampling.size() == jparams.v_sampling.size()); if (!jparams.h_sampling.empty()) { size_t len = jparams.h_sampling.size(); while (len > 1 && jparams.h_sampling[len - 1] == 1 && @@ -298,18 +323,23 @@ std::ostream& operator<<(std::ostream& os, const CompressParams& jparams) { return os; } -void SetNumChannels(J_COLOR_SPACE colorspace, size_t* channels) { +jxl::Status SetNumChannels(J_COLOR_SPACE colorspace, size_t* channels) { if (colorspace == JCS_GRAYSCALE) { *channels = 1; - } else if (colorspace == JCS_RGB || colorspace == JCS_YCbCr) { + } else if (colorspace == JCS_RGB || colorspace == JCS_YCbCr || + colorspace == JCS_EXT_RGB || colorspace == JCS_EXT_BGR) { *channels = 3; - } else if (colorspace == JCS_CMYK || colorspace == JCS_YCCK) { + } else if (colorspace == JCS_CMYK || colorspace == JCS_YCCK || + colorspace == JCS_EXT_RGBA || colorspace == JCS_EXT_BGRA || + colorspace == JCS_EXT_ARGB || colorspace == JCS_EXT_ABGR) { *channels = 4; } else if (colorspace == JCS_UNKNOWN) { - JXL_CHECK(*channels <= 4); + JXL_ENSURE(*channels <= 4); } else { - JXL_ABORT(); + return JXL_FAILURE("Unsupported colorspace: %d", + static_cast(colorspace)); } + return true; } void RGBToYCbCr(float r, float g, float b, float* y, float* cb, float* cr) { @@ -330,7 +360,28 @@ void ConvertPixel(const uint8_t* input_rgb, uint8_t* out, if (colorspace == JCS_GRAYSCALE) { const float Y = 0.299f * r + 0.587f * g + 0.114f * b; out8[0] = static_cast(std::round(Y * kMul)); - } else if (colorspace == JCS_RGB || colorspace == JCS_UNKNOWN) { + } else if (colorspace == JCS_RGB || colorspace == JCS_EXT_RGB || + colorspace == JCS_EXT_RGBA) { + out8[0] = input_rgb[0]; + out8[1] = input_rgb[1]; + out8[2] = input_rgb[2]; + if (colorspace == JCS_EXT_RGBA) out8[3] = 255; + } else if (colorspace == JCS_EXT_BGR || colorspace == JCS_EXT_BGRA) { + out8[2] = input_rgb[0]; + out8[1] = input_rgb[1]; + out8[0] = input_rgb[2]; + if (colorspace == JCS_EXT_BGRA) out8[3] = 255; + } else if (colorspace == JCS_EXT_ABGR) { + out8[0] = 255; + out8[3] = input_rgb[0]; + out8[2] = input_rgb[1]; + out8[1] = input_rgb[2]; + } else if (colorspace == JCS_EXT_ARGB) { + out8[0] = 255; + out8[1] = input_rgb[0]; + out8[2] = input_rgb[1]; + out8[3] = input_rgb[2]; + } else if (colorspace == JCS_UNKNOWN) { for (size_t c = 0; c < num_channels; ++c) { out8[c] = input_rgb[std::min(2, c)]; } @@ -363,7 +414,7 @@ void ConvertPixel(const uint8_t* input_rgb, uint8_t* out, } out8[3] = static_cast(std::round(K * kMul)); } else { - JXL_ABORT("Colorspace %d not supported", colorspace); + Check(false); } if (data_type == JPEGLI_TYPE_UINT8) { memcpy(out, out8, num_channels); @@ -389,10 +440,24 @@ void ConvertPixel(const uint8_t* input_rgb, uint8_t* out, void ConvertToGrayscale(TestImage* img) { if (img->color_space == JCS_GRAYSCALE) return; - JXL_CHECK(img->data_type == JPEGLI_TYPE_UINT8); - for (size_t i = 0; i < img->pixels.size(); i += 3) { - if (img->color_space == JCS_RGB) { - ConvertPixel(&img->pixels[i], &img->pixels[i / 3], JCS_GRAYSCALE, 1); + Check(img->data_type == JPEGLI_TYPE_UINT8); + bool rgb_pre_alpha = + img->color_space == JCS_EXT_ARGB || img->color_space == JCS_EXT_ABGR; + bool rgb_post_alpha = + img->color_space == JCS_EXT_RGBA || img->color_space == JCS_EXT_BGRA; + bool rgb_alpha = rgb_pre_alpha || rgb_post_alpha; + bool is_rgb = img->color_space == JCS_RGB || + img->color_space == JCS_EXT_RGB || + img->color_space == JCS_EXT_BGR || rgb_alpha; + bool switch_br = img->color_space == JCS_EXT_BGR || + img->color_space == JCS_EXT_ABGR || + img->color_space == JCS_EXT_BGRA; + size_t stride = rgb_alpha ? 4 : 3; + size_t offset = rgb_pre_alpha ? 1 : 0; + for (size_t i = offset; i < img->pixels.size(); i += stride) { + if (is_rgb) { + if (switch_br) std::swap(img->pixels[i], img->pixels[i + 2]); + ConvertPixel(&img->pixels[i], &img->pixels[i / stride], JCS_GRAYSCALE, 1); } else if (img->color_space == JCS_YCbCr) { img->pixels[i / 3] = img->pixels[i]; } @@ -403,25 +468,27 @@ void ConvertToGrayscale(TestImage* img) { } void GeneratePixels(TestImage* img) { - const std::vector imgdata = ReadTestData("jxl/flower/flower.pnm"); + JXL_ASSIGN_OR_QUIT(std::vector imgdata, + ReadTestData("jxl/flower/flower.pnm"), + "Failed to read test data"); size_t xsize; size_t ysize; size_t channels; size_t bitdepth; std::vector pixels; - JXL_CHECK(ReadPNM(imgdata, &xsize, &ysize, &channels, &bitdepth, &pixels)); + Check(ReadPNM(imgdata, &xsize, &ysize, &channels, &bitdepth, &pixels)); if (img->xsize == 0) img->xsize = xsize; if (img->ysize == 0) img->ysize = ysize; - JXL_CHECK(img->xsize <= xsize); - JXL_CHECK(img->ysize <= ysize); - JXL_CHECK(3 == channels); - JXL_CHECK(8 == bitdepth); + Check(img->xsize <= xsize); + Check(img->ysize <= ysize); + Check(3 == channels); + Check(8 == bitdepth); size_t in_bytes_per_pixel = channels; size_t in_stride = xsize * in_bytes_per_pixel; size_t x0 = (xsize - img->xsize) / 2; size_t y0 = (ysize - img->ysize) / 2; - SetNumChannels(static_cast(img->color_space), - &img->components); + Check(SetNumChannels(static_cast(img->color_space), + &img->components)); size_t out_bytes_per_pixel = jpegli_bytes_per_sample(img->data_type) * img->components; size_t out_stride = img->xsize * out_bytes_per_pixel; @@ -548,7 +615,7 @@ void EncodeWithJpegli(const TestImage& input, const CompressParams& jparams, } if (jparams.simple_progression) { jpegli_simple_progression(cinfo); - JXL_CHECK(jparams.progressive_mode == -1); + Check(jparams.progressive_mode == -1); } if (jparams.progressive_mode > 2) { const ScanScript& script = kTestScript[jparams.progressive_mode - 3]; @@ -624,7 +691,7 @@ void EncodeWithJpegli(const TestImage& input, const CompressParams& jparams, } } size_t num_lines = jpegli_write_raw_data(cinfo, data.data(), max_lines); - JXL_CHECK(num_lines == max_lines); + Check(num_lines == max_lines); } } else if (!input.coeffs.empty()) { j_common_ptr comptr = reinterpret_cast(cinfo); @@ -650,11 +717,11 @@ void EncodeWithJpegli(const TestImage& input, const CompressParams& jparams, for (int c = 0; c < cinfo->num_components; ++c) { jpeg_component_info* comp = &cinfo->comp_info[c]; for (size_t by = 0; by < comp->height_in_blocks; ++by) { - JBLOCKARRAY ba = (*cinfo->mem->access_virt_barray)( + JBLOCKARRAY blocks = (*cinfo->mem->access_virt_barray)( comptr, coef_arrays[c], by, 1, TRUE); size_t stride = comp->width_in_blocks * sizeof(JBLOCK); size_t offset = by * comp->width_in_blocks * DCTSIZE2; - memcpy(ba[0], &input.coeffs[c][offset], stride); + memcpy(blocks[0], &input.coeffs[c][offset], stride); } } } else { @@ -673,7 +740,7 @@ void EncodeWithJpegli(const TestImage& input, const CompressParams& jparams, bool EncodeWithJpegli(const TestImage& input, const CompressParams& jparams, std::vector* compressed) { 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 { ERROR_HANDLER_SETUP(jpegli); @@ -695,7 +762,7 @@ bool EncodeWithJpegli(const TestImage& input, const CompressParams& jparams, int NumTestScanScripts() { return kNumTestScripts; } void DumpImage(const TestImage& image, const std::string& fn) { - JXL_CHECK(image.components == 1 || image.components == 3); + Check(image.components == 1 || image.components == 3); size_t bytes_per_sample = jpegli_bytes_per_sample(image.data_type); uint32_t maxval = (1u << (8 * bytes_per_sample)) - 1; char type = image.components == 1 ? '5' : '6'; @@ -719,7 +786,7 @@ double DistanceRms(const TestImage& input, const TestImage& output, (im.endianness == JPEGLI_LITTLE_ENDIAN || (im.endianness == JPEGLI_NATIVE_ENDIAN && IsLittleEndian())); size_t offset = start_offset + idx * bytes_per_sample; - JXL_CHECK(offset < data.size()); + Check(offset < data.size()); const uint8_t* p = &data[offset]; if (im.data_type == JPEGLI_TYPE_UINT8) { static const double mul8 = 1.0 / 255.0; @@ -745,10 +812,10 @@ double DistanceRms(const TestImage& input, const TestImage& output, diff2 += diff * diff; } } else { - JXL_CHECK(!input.raw_data.empty()); - JXL_CHECK(!output.raw_data.empty()); + Check(!input.raw_data.empty()); + Check(!output.raw_data.empty()); for (size_t c = 0; c < input.raw_data.size(); ++c) { - JXL_CHECK(c < output.raw_data.size()); + Check(c < output.raw_data.size()); num_samples += input.raw_data[c].size(); for (size_t i = 0; i < input.raw_data[c].size(); ++i) { double sample_orig = get_sample(input, input.raw_data[c], i); @@ -774,23 +841,23 @@ void VerifyOutputImage(const TestImage& input, const TestImage& output, double rms = DistanceRms(input, output, start_line, num_lines, &max_d); printf("rms: %f, max_rms: %f, max_d: %f, max_diff: %f\n", rms, max_rms, max_d, max_diff); - JXL_CHECK(rms <= max_rms); - JXL_CHECK(max_d <= max_diff); + Check(rms <= max_rms); + Check(max_d <= max_diff); } void VerifyOutputImage(const TestImage& input, const TestImage& output, double max_rms, double max_diff) { - JXL_CHECK(output.xsize == input.xsize); - JXL_CHECK(output.ysize == input.ysize); - JXL_CHECK(output.components == input.components); - JXL_CHECK(output.color_space == input.color_space); + Check(output.xsize == input.xsize); + Check(output.ysize == input.ysize); + Check(output.components == input.components); + Check(output.color_space == input.color_space); if (!input.coeffs.empty()) { - JXL_CHECK(input.coeffs.size() == input.components); - JXL_CHECK(output.coeffs.size() == input.components); + Check(input.coeffs.size() == input.components); + Check(output.coeffs.size() == input.components); for (size_t c = 0; c < input.components; ++c) { - JXL_CHECK(output.coeffs[c].size() == input.coeffs[c].size()); - JXL_CHECK(0 == memcmp(input.coeffs[c].data(), output.coeffs[c].data(), - input.coeffs[c].size())); + Check(output.coeffs[c].size() == input.coeffs[c].size()); + Check(0 == memcmp(input.coeffs[c].data(), output.coeffs[c].data(), + input.coeffs[c].size())); } } else { VerifyOutputImage(input, output, 0, output.ysize, max_rms, max_diff); diff --git a/third_party/jpeg-xl/lib/jpegli/test_utils.h b/third_party/jpeg-xl/lib/jpegli/test_utils.h index 132cfd042ad03..0ebd7ffbc8224 100644 --- a/third_party/jpeg-xl/lib/jpegli/test_utils.h +++ b/third_party/jpeg-xl/lib/jpegli/test_utils.h @@ -6,22 +6,15 @@ #ifndef LIB_JPEGLI_TEST_UTILS_H_ #define LIB_JPEGLI_TEST_UTILS_H_ -#include -#include - -#include +#include +#include #include #include -/* clang-format off */ -#include -#include -#include -/* clang-format on */ - -#include "lib/jpegli/common.h" -#include "lib/jpegli/libjpeg_test_util.h" #include "lib/jpegli/test_params.h" +#include "lib/jpegli/types.h" +#include "lib/jxl/base/include_jpeglib.h" // NOLINT +#include "lib/jxl/base/status.h" namespace jpegli { @@ -66,7 +59,7 @@ void UnmapColors(uint8_t* row, size_t xsize, int components, JSAMPARRAY colormap, size_t num_colors); std::string GetTestDataPath(const std::string& filename); -std::vector ReadTestData(const std::string& filename); +jxl::StatusOr> ReadTestData(const std::string& filename); class PNMParser { public: @@ -95,7 +88,7 @@ bool ReadPNM(const std::vector& data, size_t* xsize, size_t* ysize, size_t* num_channels, size_t* bitdepth, std::vector* pixels); -void SetNumChannels(J_COLOR_SPACE colorspace, size_t* channels); +jxl::Status SetNumChannels(J_COLOR_SPACE colorspace, size_t* channels); void ConvertToGrayscale(TestImage* img); diff --git a/third_party/jpeg-xl/lib/jpegli/testing.h b/third_party/jpeg-xl/lib/jpegli/testing.h index 873a0171e7ada..58df563f06644 100644 --- a/third_party/jpeg-xl/lib/jpegli/testing.h +++ b/third_party/jpeg-xl/lib/jpegli/testing.h @@ -6,15 +6,7 @@ #ifndef LIB_JPEGLI_TESTING_H_ #define LIB_JPEGLI_TESTING_H_ -// GTest/GMock specific macros / wrappers. - -// gmock unconditionally redefines those macros (to wrong values). -// Lets include it only here and mitigate the problem. -#pragma push_macro("PRIdS") -#pragma push_macro("PRIuS") -#include "gmock/gmock.h" -#pragma pop_macro("PRIuS") -#pragma pop_macro("PRIdS") +// GTest specific macros / wrappers. #include "gtest/gtest.h" @@ -26,10 +18,20 @@ #define JPEGLI_INSTANTIATE_TEST_SUITE_P INSTANTIATE_TEST_CASE_P #endif +// Replacement for ASSERT_TRUE inside try-catch blocks. +#define JPEGLI_TEST_ENSURE_TRUE(C) \ + if (!(C)) return false; + +#define QUIT(M) FAIL() << M + // Ensures that we don't make our test bounds too lax, effectively disabling the // tests. -MATCHER_P(IsSlightlyBelow, max, "") { - return max * 0.75 <= arg && arg <= max * 1.0; -} +#define EXPECT_SLIGHTLY_BELOW(A, E) \ + { \ + double _actual = (A); \ + double _expected = (E); \ + EXPECT_LE(_actual, _expected); \ + EXPECT_GE(_actual, 0.75 * _expected); \ + } #endif // LIB_JPEGLI_TESTING_H_ diff --git a/third_party/jpeg-xl/lib/jpegli/transcode_api_test.cc b/third_party/jpeg-xl/lib/jpegli/transcode_api_test.cc index 1d99ce37fa288..42d7e4f7fe324 100644 --- a/third_party/jpeg-xl/lib/jpegli/transcode_api_test.cc +++ b/third_party/jpeg-xl/lib/jpegli/transcode_api_test.cc @@ -3,13 +3,21 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include +#include +#include +#include +#include +#include +#include #include #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/status.h" namespace jpegli { namespace { @@ -20,7 +28,7 @@ void TranscodeWithJpegli(const std::vector& jpeg_input, jpeg_decompress_struct dinfo = {}; jpeg_compress_struct cinfo = {}; uint8_t* transcoded_data = nullptr; - unsigned long transcoded_size; + unsigned long transcoded_size; // NOLINT const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); dinfo.err = cinfo.err; @@ -30,7 +38,7 @@ void TranscodeWithJpegli(const std::vector& jpeg_input, EXPECT_EQ(JPEG_REACHED_SOS, jpegli_read_header(&dinfo, /*require_image=*/TRUE)); jvirt_barray_ptr* coef_arrays = jpegli_read_coefficients(&dinfo); - JXL_CHECK(coef_arrays != nullptr); + JPEGLI_TEST_ENSURE_TRUE(coef_arrays != nullptr); jpegli_create_compress(&cinfo); jpegli_mem_dest(&cinfo, &transcoded_data, &transcoded_size); jpegli_copy_critical_parameters(&dinfo, &cinfo); diff --git a/third_party/jpeg-xl/lib/jpegli/types.h b/third_party/jpeg-xl/lib/jpegli/types.h index 2f446b7fff2af..c0c0450c1865d 100644 --- a/third_party/jpeg-xl/lib/jpegli/types.h +++ b/third_party/jpeg-xl/lib/jpegli/types.h @@ -6,7 +6,7 @@ #ifndef LIB_JPEGLI_TYPES_H_ #define LIB_JPEGLI_TYPES_H_ -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus extern "C" { #endif @@ -31,7 +31,7 @@ typedef enum { int jpegli_bytes_per_sample(JpegliDataType data_type); -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus } // extern "C" #endif diff --git a/third_party/jpeg-xl/lib/jxl.cmake b/third_party/jpeg-xl/lib/jxl.cmake index 86fa37151d0b8..59b2cca4265ab 100644 --- a/third_party/jpeg-xl/lib/jxl.cmake +++ b/third_party/jpeg-xl/lib/jxl.cmake @@ -13,7 +13,9 @@ if (JPEGXL_ENABLE_TRANSCODE_JPEG OR JPEGXL_ENABLE_TOOLS OR JPEGXL_ENABLE_DEVTOOL list(APPEND JPEGXL_INTERNAL_DEC_SOURCES ${JPEGXL_INTERNAL_DEC_JPEG_SOURCES}) endif() -set_source_files_properties(jxl/enc_fast_lossless.cc PROPERTIES COMPILE_FLAGS -O3) +set(FJXL_COMPILE_FLAGS "-O3") + +set_source_files_properties(jxl/enc_fast_lossless.cc PROPERTIES COMPILE_FLAGS "${FJXL_COMPILE_FLAGS}") set(JPEGXL_DEC_INTERNAL_LIBS hwy @@ -80,10 +82,10 @@ foreach(path ${JPEGXL_INTERNAL_PUBLIC_HEADERS}) endforeach() add_library(jxl_base INTERFACE) -target_include_directories(jxl_base SYSTEM INTERFACE +target_include_directories(jxl_base SYSTEM BEFORE INTERFACE "$" ) -target_include_directories(jxl_base INTERFACE +target_include_directories(jxl_base BEFORE INTERFACE ${PROJECT_SOURCE_DIR} ${JXL_HWY_INCLUDE_DIRS} ) @@ -104,7 +106,7 @@ add_library(jxl_dec-obj OBJECT ${JPEGXL_INTERNAL_DEC_SOURCES}) target_compile_options(jxl_dec-obj PRIVATE ${JPEGXL_INTERNAL_FLAGS}) target_compile_options(jxl_dec-obj PUBLIC ${JPEGXL_COVERAGE_FLAGS}) set_property(TARGET jxl_dec-obj PROPERTY POSITION_INDEPENDENT_CODE ON) -target_include_directories(jxl_dec-obj PUBLIC +target_include_directories(jxl_dec-obj BEFORE PUBLIC "$" "${JXL_HWY_INCLUDE_DIRS}" "$>" @@ -119,7 +121,7 @@ add_library(jxl_enc-obj OBJECT ${JPEGXL_INTERNAL_ENC_SOURCES}) target_compile_options(jxl_enc-obj PRIVATE ${JPEGXL_INTERNAL_FLAGS}) target_compile_options(jxl_enc-obj PUBLIC ${JPEGXL_COVERAGE_FLAGS}) set_property(TARGET jxl_enc-obj PROPERTY POSITION_INDEPENDENT_CODE ON) -target_include_directories(jxl_enc-obj PUBLIC +target_include_directories(jxl_enc-obj BEFORE PUBLIC ${PROJECT_SOURCE_DIR} ${JXL_HWY_INCLUDE_DIRS} $ @@ -172,7 +174,7 @@ target_link_libraries(jxl-internal PUBLIC jxl_cms jxl_base ) -target_include_directories(jxl-internal PUBLIC +target_include_directories(jxl-internal BEFORE PUBLIC "$") target_compile_definitions(jxl-internal INTERFACE -DJXL_STATIC_DEFINE) diff --git a/third_party/jpeg-xl/lib/jxl/ac_context.h b/third_party/jpeg-xl/lib/jxl/ac_context.h index a2b9e046d1188..6529a9bb88bcb 100644 --- a/third_party/jpeg-xl/lib/jxl/ac_context.h +++ b/third_party/jpeg-xl/lib/jxl/ac_context.h @@ -62,7 +62,8 @@ static JXL_INLINE size_t ZeroDensityContext(size_t nonzeros_left, size_t k, size_t covered_blocks, size_t log2_covered_blocks, size_t prev) { - JXL_DASSERT((1u << log2_covered_blocks) == covered_blocks); + JXL_DASSERT((static_cast(1) << log2_covered_blocks) == + covered_blocks); nonzeros_left = (nonzeros_left + covered_blocks - 1) >> log2_covered_blocks; k >>= log2_covered_blocks; JXL_DASSERT(k > 0); @@ -109,7 +110,8 @@ struct BlockCtxMap { // Non-zero context is based on number of non-zeros and block context. // For better clustering, contexts with same number of non-zeros are grouped. constexpr uint32_t ZeroDensityContextsOffset(uint32_t block_ctx) const { - return num_ctxs * kNonZeroBuckets + kZeroDensityContextCount * block_ctx; + return static_cast(num_ctxs * kNonZeroBuckets + + kZeroDensityContextCount * block_ctx); } // Context map for AC coefficients consists of 2 blocks: @@ -121,7 +123,8 @@ struct BlockCtxMap { // number of non-zeros left and // index in scan order constexpr uint32_t NumACContexts() const { - return num_ctxs * (kNonZeroBuckets + kZeroDensityContextCount); + return static_cast(num_ctxs * + (kNonZeroBuckets + kZeroDensityContextCount)); } // Non-zero context is based on number of non-zeros and block context. @@ -134,7 +137,7 @@ struct BlockCtxMap { } else { ctx = 4 + non_zeros / 2; } - return ctx * num_ctxs + block_ctx; + return static_cast(ctx * num_ctxs + block_ctx); } BlockCtxMap() { diff --git a/third_party/jpeg-xl/lib/jxl/ac_strategy.cc b/third_party/jpeg-xl/lib/jxl/ac_strategy.cc index e7a72f5a33243..69e8ae6f470c1 100644 --- a/third_party/jpeg-xl/lib/jxl/ac_strategy.cc +++ b/third_party/jpeg-xl/lib/jxl/ac_strategy.cc @@ -5,12 +5,14 @@ #include "lib/jxl/ac_strategy.h" -#include +#include #include +#include #include #include "lib/jxl/base/bits.h" +#include "lib/jxl/base/compiler_specific.h" namespace jxl { @@ -78,20 +80,23 @@ void AcStrategy::ComputeNaturalCoeffOrderLut(coeff_order_t* lut) const { CoeffOrderAndLut(*this, lut); } -// These definitions are needed before C++17. +#if JXL_CXX_LANG < JXL_CXX_17 constexpr size_t AcStrategy::kMaxCoeffBlocks; constexpr size_t AcStrategy::kMaxBlockDim; constexpr size_t AcStrategy::kMaxCoeffArea; +#endif -StatusOr AcStrategyImage::Create(size_t xsize, size_t ysize) { +StatusOr AcStrategyImage::Create( + JxlMemoryManager* memory_manager, size_t xsize, size_t ysize) { AcStrategyImage img; - JXL_ASSIGN_OR_RETURN(img.layers_, ImageB::Create(xsize, ysize)); + JXL_ASSIGN_OR_RETURN(img.layers_, + ImageB::Create(memory_manager, xsize, ysize)); img.row_ = img.layers_.Row(0); img.stride_ = img.layers_.PixelsPerRow(); return img; } -size_t AcStrategyImage::CountBlocks(AcStrategy::Type type) const { +size_t AcStrategyImage::CountBlocks(AcStrategyType type) const { size_t ret = 0; for (size_t y = 0; y < layers_.ysize(); y++) { const uint8_t* JXL_RESTRICT row = layers_.ConstRow(y); diff --git a/third_party/jpeg-xl/lib/jxl/ac_strategy.h b/third_party/jpeg-xl/lib/jxl/ac_strategy.h index 9e5917ff1b84a..8c3191c791a90 100644 --- a/third_party/jpeg-xl/lib/jxl/ac_strategy.h +++ b/third_party/jpeg-xl/lib/jxl/ac_strategy.h @@ -6,14 +6,18 @@ #ifndef LIB_JXL_AC_STRATEGY_H_ #define LIB_JXL_AC_STRATEGY_H_ -#include -#include +#include +#include +#include #include // kMaxVectorSize +#include "lib/jxl/base/compiler_specific.h" +#include "lib/jxl/base/rect.h" #include "lib/jxl/base/status.h" #include "lib/jxl/coeff_order_fwd.h" #include "lib/jxl/frame_dimensions.h" +#include "lib/jxl/image.h" #include "lib/jxl/image_ops.h" // Defines the different kinds of transforms, and heuristics to choose between @@ -27,6 +31,53 @@ namespace jxl { +// Raw strategy types. +enum class AcStrategyType : uint32_t { + // Regular block size DCT + DCT = 0, + // Encode pixels without transforming + IDENTITY = 1, + // Use 2-by-2 DCT + DCT2X2 = 2, + // Use 4-by-4 DCT + DCT4X4 = 3, + // Use 16-by-16 DCT + DCT16X16 = 4, + // Use 32-by-32 DCT + DCT32X32 = 5, + // Use 16-by-8 DCT + DCT16X8 = 6, + // Use 8-by-16 DCT + DCT8X16 = 7, + // Use 32-by-8 DCT + DCT32X8 = 8, + // Use 8-by-32 DCT + DCT8X32 = 9, + // Use 32-by-16 DCT + DCT32X16 = 10, + // Use 16-by-32 DCT + DCT16X32 = 11, + // 4x8 and 8x4 DCT + DCT4X8 = 12, + DCT8X4 = 13, + // Corner-DCT. + AFV0 = 14, + AFV1 = 15, + AFV2 = 16, + AFV3 = 17, + // Larger DCTs + DCT64X64 = 18, + DCT64X32 = 19, + DCT32X64 = 20, + // No transforms smaller than 64x64 are allowed below. + DCT128X128 = 21, + DCT128X64 = 22, + DCT64X128 = 23, + DCT256X256 = 24, + DCT256X128 = 25, + DCT128X256 = 26 +}; + class AcStrategy { public: // Extremal values for the number of blocks/coefficients of a single strategy. @@ -38,55 +89,10 @@ class AcStrategy { static_assert((kMaxCoeffArea * sizeof(float)) % hwy::kMaxVectorSize == 0, "Coefficient area is not a multiple of vector size"); - // Raw strategy types. - enum Type : uint32_t { - // Regular block size DCT - DCT = 0, - // Encode pixels without transforming - IDENTITY = 1, - // Use 2-by-2 DCT - DCT2X2 = 2, - // Use 4-by-4 DCT - DCT4X4 = 3, - // Use 16-by-16 DCT - DCT16X16 = 4, - // Use 32-by-32 DCT - DCT32X32 = 5, - // Use 16-by-8 DCT - DCT16X8 = 6, - // Use 8-by-16 DCT - DCT8X16 = 7, - // Use 32-by-8 DCT - DCT32X8 = 8, - // Use 8-by-32 DCT - DCT8X32 = 9, - // Use 32-by-16 DCT - DCT32X16 = 10, - // Use 16-by-32 DCT - DCT16X32 = 11, - // 4x8 and 8x4 DCT - DCT4X8 = 12, - DCT8X4 = 13, - // Corner-DCT. - AFV0 = 14, - AFV1 = 15, - AFV2 = 16, - AFV3 = 17, - // Larger DCTs - DCT64X64 = 18, - DCT64X32 = 19, - DCT32X64 = 20, - DCT128X128 = 21, - DCT128X64 = 22, - DCT64X128 = 23, - DCT256X256 = 24, - DCT256X128 = 25, - DCT128X256 = 26, - // Marker for num of valid strategies. - kNumValidStrategies - }; - - static constexpr uint32_t TypeBit(const Type type) { + static constexpr uint8_t kNumValidStrategies = + static_cast(AcStrategyType::DCT128X256) + 1; + + static constexpr uint32_t TypeBit(const AcStrategyType type) { return 1u << static_cast(type); } @@ -96,15 +102,17 @@ class AcStrategy { JXL_INLINE bool IsMultiblock() const { constexpr uint32_t bits = - TypeBit(Type::DCT16X16) | TypeBit(Type::DCT32X32) | - TypeBit(Type::DCT16X8) | TypeBit(Type::DCT8X16) | - TypeBit(Type::DCT32X8) | TypeBit(Type::DCT8X32) | - TypeBit(Type::DCT16X32) | TypeBit(Type::DCT32X16) | - TypeBit(Type::DCT32X64) | TypeBit(Type::DCT64X32) | - TypeBit(Type::DCT64X64) | TypeBit(DCT64X128) | TypeBit(DCT128X64) | - TypeBit(DCT128X128) | TypeBit(DCT128X256) | TypeBit(DCT256X128) | - TypeBit(DCT256X256); - JXL_DASSERT(Strategy() < kNumValidStrategies); + TypeBit(AcStrategyType::DCT16X16) | TypeBit(AcStrategyType::DCT32X32) | + TypeBit(AcStrategyType::DCT16X8) | TypeBit(AcStrategyType::DCT8X16) | + TypeBit(AcStrategyType::DCT32X8) | TypeBit(AcStrategyType::DCT8X32) | + TypeBit(AcStrategyType::DCT16X32) | TypeBit(AcStrategyType::DCT32X16) | + TypeBit(AcStrategyType::DCT32X64) | TypeBit(AcStrategyType::DCT64X32) | + TypeBit(AcStrategyType::DCT64X64) | TypeBit(AcStrategyType::DCT64X128) | + TypeBit(AcStrategyType::DCT128X64) | + TypeBit(AcStrategyType::DCT128X128) | + TypeBit(AcStrategyType::DCT128X256) | + TypeBit(AcStrategyType::DCT256X128) | + TypeBit(AcStrategyType::DCT256X256); return ((1u << static_cast(Strategy())) & bits) != 0; } @@ -113,17 +121,16 @@ class AcStrategy { return static_cast(strategy_); } - JXL_INLINE Type Strategy() const { return strategy_; } + JXL_INLINE AcStrategyType Strategy() const { return strategy_; } // Inverse check static JXL_INLINE constexpr bool IsRawStrategyValid(int raw_strategy) { - return raw_strategy < static_cast(kNumValidStrategies) && - raw_strategy >= 0; + return raw_strategy < kNumValidStrategies && raw_strategy >= 0; } static JXL_INLINE AcStrategy FromRawStrategy(uint8_t raw_strategy) { - return FromRawStrategy(static_cast(raw_strategy)); + return FromRawStrategy(static_cast(raw_strategy)); } - static JXL_INLINE AcStrategy FromRawStrategy(Type raw_strategy) { + static JXL_INLINE AcStrategy FromRawStrategy(AcStrategyType raw_strategy) { JXL_DASSERT(IsRawStrategyValid(static_cast(raw_strategy))); return AcStrategy(raw_strategy, /*is_first=*/true); } @@ -167,12 +174,12 @@ class AcStrategy { private: friend class AcStrategyRow; - JXL_INLINE AcStrategy(Type strategy, bool is_first) + JXL_INLINE AcStrategy(AcStrategyType strategy, bool is_first) : strategy_(strategy), is_first_(is_first) { JXL_DASSERT(IsMultiblock() || is_first == true); } - Type strategy_; + AcStrategyType strategy_; bool is_first_; }; @@ -181,7 +188,7 @@ class AcStrategyRow { public: explicit AcStrategyRow(const uint8_t* row) : row_(row) {} AcStrategy operator[](size_t x) const { - AcStrategy::Type strategy = static_cast(row_[x] >> 1); + AcStrategyType strategy = static_cast(row_[x] >> 1); bool is_first = static_cast(row_[x] & 1); return AcStrategy(strategy, is_first); } @@ -193,29 +200,31 @@ class AcStrategyRow { class AcStrategyImage { public: AcStrategyImage() = default; - static StatusOr Create(size_t xsize, size_t ysize); + static StatusOr Create(JxlMemoryManager* memory_manager, + size_t xsize, size_t ysize); AcStrategyImage(AcStrategyImage&&) = default; AcStrategyImage& operator=(AcStrategyImage&&) = default; void FillDCT8(const Rect& rect) { - FillPlane((static_cast(AcStrategy::Type::DCT) << 1) | 1, + FillPlane((static_cast(AcStrategyType::DCT) << 1) | 1, &layers_, rect); } void FillDCT8() { FillDCT8(Rect(layers_)); } void FillInvalid() { FillImage(INVALID, &layers_); } - void Set(size_t x, size_t y, AcStrategy::Type type) { -#if JXL_ENABLE_ASSERT + Status Set(size_t x, size_t y, AcStrategyType type) { +#if (JXL_IS_DEBUG_BUILD) AcStrategy acs = AcStrategy::FromRawStrategy(type); -#endif // JXL_ENABLE_ASSERT - JXL_ASSERT(y + acs.covered_blocks_y() <= layers_.ysize()); - JXL_ASSERT(x + acs.covered_blocks_x() <= layers_.xsize()); - JXL_CHECK(SetNoBoundsCheck(x, y, type, /*check=*/false)); + JXL_DASSERT(y + acs.covered_blocks_y() <= layers_.ysize()); + JXL_DASSERT(x + acs.covered_blocks_x() <= layers_.xsize()); +#endif + JXL_RETURN_IF_ERROR(SetNoBoundsCheck(x, y, type, /*check=*/false)); + return true; } - Status SetNoBoundsCheck(size_t x, size_t y, AcStrategy::Type type, + Status SetNoBoundsCheck(size_t x, size_t y, AcStrategyType type, bool check = true) { AcStrategy acs = AcStrategy::FromRawStrategy(type); for (size_t iy = 0; iy < acs.covered_blocks_y(); iy++) { @@ -247,7 +256,9 @@ class AcStrategyImage { size_t ysize() const { return layers_.ysize(); } // Count the number of blocks of a given type. - size_t CountBlocks(AcStrategy::Type type) const; + size_t CountBlocks(AcStrategyType type) const; + + JxlMemoryManager* memory_manager() const { return layers_.memory_manager(); } private: ImageB layers_; diff --git a/third_party/jpeg-xl/lib/jxl/ac_strategy_test.cc b/third_party/jpeg-xl/lib/jxl/ac_strategy_test.cc index b1d9103466ad8..e6405fc86b25a 100644 --- a/third_party/jpeg-xl/lib/jxl/ac_strategy_test.cc +++ b/third_party/jpeg-xl/lib/jxl/ac_strategy_test.cc @@ -5,19 +5,21 @@ #include "lib/jxl/ac_strategy.h" -#include +#include -#include -#include +#include +#include #include // HWY_ALIGN_MAX #include -#include #include "lib/jxl/base/random.h" -#include "lib/jxl/dct_scales.h" +#include "lib/jxl/coeff_order_fwd.h" #include "lib/jxl/dec_transforms_testonly.h" #include "lib/jxl/enc_transforms.h" +#include "lib/jxl/memory_manager_internal.h" #include "lib/jxl/simd_util.h" +#include "lib/jxl/test_memory_manager.h" +#include "lib/jxl/test_utils.h" #include "lib/jxl/testing.h" namespace jxl { @@ -27,19 +29,22 @@ namespace { class AcStrategyRoundtrip : public ::hwy::TestWithParamTargetAndT { protected: void Run() { - const AcStrategy::Type type = static_cast(GetParam()); + JxlMemoryManager* memory_manager = test::MemoryManager(); + const AcStrategyType type = static_cast(GetParam()); const AcStrategy acs = AcStrategy::FromRawStrategy(type); const size_t dct_scratch_size = 3 * (MaxVectorSize() / sizeof(float)) * AcStrategy::kMaxBlockDim; - auto mem = hwy::AllocateAligned(4 * AcStrategy::kMaxCoeffArea + - dct_scratch_size); - float* coeffs = mem.get(); + size_t mem_bytes = + (4 * AcStrategy::kMaxCoeffArea + dct_scratch_size) * sizeof(float); + JXL_TEST_ASSIGN_OR_DIE(AlignedMemory mem, + AlignedMemory::Create(memory_manager, mem_bytes)); + float* coeffs = mem.address(); float* idct = coeffs + AcStrategy::kMaxCoeffArea; float* input = idct + AcStrategy::kMaxCoeffArea; float* scratch_space = input + AcStrategy::kMaxCoeffArea; - Rng rng(type * 65537 + 13); + Rng rng(static_cast(type) * 65537 + 13); for (size_t j = 0; j < 64; j++) { size_t i = (acs.log2_covered_blocks() @@ -55,7 +60,7 @@ class AcStrategyRoundtrip : public ::hwy::TestWithParamTargetAndT { scratch_space); for (size_t j = 0; j < 64u << acs.log2_covered_blocks(); j++) { ASSERT_NEAR(idct[j], j == i ? 0.2f : 0, 2e-6) - << "j = " << j << " i = " << i << " acs " << type; + << "j = " << j << " i = " << i << " acs " << static_cast(type); } } // Test DC. @@ -72,7 +77,8 @@ class AcStrategyRoundtrip : public ::hwy::TestWithParamTargetAndT { dc[y * acs.covered_blocks_x() * 8 + x] = 0.2; for (size_t j = 0; j < 64u << acs.log2_covered_blocks(); j++) { ASSERT_NEAR(idct[j], dc[j], 1e-6) - << "j = " << j << " x = " << x << " y = " << y << " acs " << type; + << "j = " << j << " x = " << x << " y = " << y << " acs " + << static_cast(type); } } } @@ -81,8 +87,7 @@ class AcStrategyRoundtrip : public ::hwy::TestWithParamTargetAndT { HWY_TARGET_INSTANTIATE_TEST_SUITE_P_T( AcStrategyRoundtrip, - ::testing::Range(0, - static_cast(AcStrategy::Type::kNumValidStrategies))); + ::testing::Range(0, static_cast(AcStrategy::kNumValidStrategies))); TEST_P(AcStrategyRoundtrip, Test) { Run(); } @@ -91,20 +96,23 @@ class AcStrategyRoundtripDownsample : public ::hwy::TestWithParamTargetAndT { protected: void Run() { - const AcStrategy::Type type = static_cast(GetParam()); + JxlMemoryManager* memory_manager = test::MemoryManager(); + const AcStrategyType type = static_cast(GetParam()); const AcStrategy acs = AcStrategy::FromRawStrategy(type); const size_t dct_scratch_size = 3 * (MaxVectorSize() / sizeof(float)) * AcStrategy::kMaxBlockDim; - auto mem = hwy::AllocateAligned(4 * AcStrategy::kMaxCoeffArea + - dct_scratch_size); - float* coeffs = mem.get(); + size_t mem_bytes = + (4 * AcStrategy::kMaxCoeffArea + dct_scratch_size) * sizeof(float); + JXL_TEST_ASSIGN_OR_DIE(AlignedMemory mem, + AlignedMemory::Create(memory_manager, mem_bytes)); + float* coeffs = mem.address(); float* idct = coeffs + AcStrategy::kMaxCoeffArea; float* dc = idct + AcStrategy::kMaxCoeffArea; float* scratch_space = dc + AcStrategy::kMaxCoeffArea; std::fill_n(coeffs, AcStrategy::kMaxCoeffArea, 0.0f); - Rng rng(type * 65537 + 13); + Rng rng(static_cast(type) * 65537 + 13); for (size_t y = 0; y < acs.covered_blocks_y(); y++) { for (size_t x = 0; x < acs.covered_blocks_x(); x++) { @@ -132,7 +140,7 @@ class AcStrategyRoundtripDownsample } sum /= 64.0f; ASSERT_NEAR(sum, dc[dy * 8 * acs.covered_blocks_x() + dx], 1e-6) - << "acs " << type; + << "acs " << static_cast(type); } } } @@ -142,8 +150,7 @@ class AcStrategyRoundtripDownsample HWY_TARGET_INSTANTIATE_TEST_SUITE_P_T( AcStrategyRoundtripDownsample, - ::testing::Range(0, - static_cast(AcStrategy::Type::kNumValidStrategies))); + ::testing::Range(0, static_cast(AcStrategy::kNumValidStrategies))); TEST_P(AcStrategyRoundtripDownsample, Test) { Run(); } @@ -152,7 +159,8 @@ TEST_P(AcStrategyRoundtripDownsample, Test) { Run(); } class AcStrategyDownsample : public ::hwy::TestWithParamTargetAndT { protected: void Run() { - const AcStrategy::Type type = static_cast(GetParam()); + JxlMemoryManager* memory_manager = test::MemoryManager(); + const AcStrategyType type = static_cast(GetParam()); const AcStrategy acs = AcStrategy::FromRawStrategy(type); const size_t dct_scratch_size = 3 * (MaxVectorSize() / sizeof(float)) * AcStrategy::kMaxBlockDim; @@ -160,14 +168,16 @@ class AcStrategyDownsample : public ::hwy::TestWithParamTargetAndT { size_t cy = acs.covered_blocks_x(); CoefficientLayout(&cy, &cx); - auto mem = hwy::AllocateAligned(4 * AcStrategy::kMaxCoeffArea + - dct_scratch_size); - float* idct = mem.get(); + size_t mem_bytes = + (4 * AcStrategy::kMaxCoeffArea + dct_scratch_size) * sizeof(float); + JXL_TEST_ASSIGN_OR_DIE(AlignedMemory mem, + AlignedMemory::Create(memory_manager, mem_bytes)); + float* idct = mem.address(); float* idct_acs_downsampled = idct + AcStrategy::kMaxCoeffArea; float* coeffs = idct + AcStrategy::kMaxCoeffArea; float* scratch_space = coeffs + AcStrategy::kMaxCoeffArea; - Rng rng(type * 65537 + 13); + Rng rng(static_cast(type) * 65537 + 13); for (size_t y = 0; y < cy; y++) { for (size_t x = 0; x < cx; x++) { @@ -197,7 +207,7 @@ class AcStrategyDownsample : public ::hwy::TestWithParamTargetAndT { ASSERT_NEAR( sum, idct_acs_downsampled[dy * 8 * acs.covered_blocks_x() + dx], 1e-6) - << " acs " << type; + << " acs " << static_cast(type); } } } @@ -207,8 +217,7 @@ class AcStrategyDownsample : public ::hwy::TestWithParamTargetAndT { HWY_TARGET_INSTANTIATE_TEST_SUITE_P_T( AcStrategyDownsample, - ::testing::Range(0, - static_cast(AcStrategy::Type::kNumValidStrategies))); + ::testing::Range(0, static_cast(AcStrategy::kNumValidStrategies))); TEST_P(AcStrategyDownsample, Test) { Run(); } @@ -231,13 +240,16 @@ TEST_P(AcStrategyTargetTest, RoundtripAFVDCT) { } TEST_P(AcStrategyTargetTest, BenchmarkAFV) { - const AcStrategy::Type type = AcStrategy::Type::AFV0; + JxlMemoryManager* memory_manager = test::MemoryManager(); + const AcStrategyType type = AcStrategyType::AFV0; HWY_ALIGN_MAX float pixels[64] = {1}; HWY_ALIGN_MAX float coeffs[64] = {}; const size_t dct_scratch_size = 3 * (MaxVectorSize() / sizeof(float)) * AcStrategy::kMaxBlockDim; - auto mem = hwy::AllocateAligned(64 + dct_scratch_size); - float* scratch_space = mem.get(); + size_t mem_bytes = (64 + dct_scratch_size) * sizeof(float); + JXL_TEST_ASSIGN_OR_DIE(AlignedMemory mem, + AlignedMemory::Create(memory_manager, mem_bytes)); + float* scratch_space = mem.address(); for (size_t i = 0; i < 1 << 14; i++) { TransformToPixels(type, coeffs, pixels, 8, scratch_space); TransformFromPixels(type, pixels, 8, coeffs, scratch_space); diff --git a/third_party/jpeg-xl/lib/jxl/alpha_test.cc b/third_party/jpeg-xl/lib/jxl/alpha_test.cc index ddafd829ecf11..6e26e77be6a7c 100644 --- a/third_party/jpeg-xl/lib/jxl/alpha_test.cc +++ b/third_party/jpeg-xl/lib/jxl/alpha_test.cc @@ -5,69 +5,69 @@ #include "lib/jxl/alpha.h" -#include "lib/jxl/test_utils.h" +#include + +#include "lib/jxl/base/common.h" #include "lib/jxl/testing.h" namespace jxl { namespace { -using ::testing::_; -using ::testing::ElementsAre; -using ::testing::FloatNear; +AlphaBlendingInputLayer makeAbil(const Color& rgb, const float& a) { + const float* data = rgb.data(); + return {data, data + 1, data + 2, &a}; +} + +AlphaBlendingOutput makeAbo(Color& rgb, float& a) { + float* data = rgb.data(); + return {data, data + 1, data + 2, &a}; +} TEST(AlphaTest, BlendingWithNonPremultiplied) { - const float bg_rgb[3] = {100, 110, 120}; + const Color bg_rgb{100, 110, 120}; const float bg_a = 180.f / 255; - const float fg_rgb[3] = {25, 21, 23}; + const Color fg_rgb{25, 21, 23}; const float fg_a = 15420.f / 65535; const float fg_a2 = 2.0f; - float out_rgb[3]; + Color out_rgb; float out_a; PerformAlphaBlending( - /*bg=*/{&bg_rgb[0], &bg_rgb[1], &bg_rgb[2], &bg_a}, - /*fg=*/{&fg_rgb[0], &fg_rgb[1], &fg_rgb[2], &fg_a}, - /*out=*/{&out_rgb[0], &out_rgb[1], &out_rgb[2], &out_a}, 1, + /*bg=*/makeAbil(bg_rgb, bg_a), + /*fg=*/makeAbil(fg_rgb, fg_a), + /*out=*/makeAbo(out_rgb, out_a), 1, /*alpha_is_premultiplied=*/false, /*clamp=*/false); - EXPECT_THAT(out_rgb, - ElementsAre(FloatNear(77.2f, .05f), FloatNear(83.0f, .05f), - FloatNear(90.6f, .05f))); + EXPECT_ARRAY_NEAR(out_rgb, (Color{77.2f, 83.0f, 90.6f}), 0.05f); EXPECT_NEAR(out_a, 3174.f / 4095, 1e-5); PerformAlphaBlending( - /*bg=*/{&bg_rgb[0], &bg_rgb[1], &bg_rgb[2], &bg_a}, - /*fg=*/{&fg_rgb[0], &fg_rgb[1], &fg_rgb[2], &fg_a2}, - /*out=*/{&out_rgb[0], &out_rgb[1], &out_rgb[2], &out_a}, 1, + /*bg=*/makeAbil(bg_rgb, bg_a), + /*fg=*/makeAbil(fg_rgb, fg_a2), + /*out=*/makeAbo(out_rgb, out_a), 1, /*alpha_is_premultiplied=*/false, /*clamp=*/true); - EXPECT_THAT(out_rgb, ElementsAre(FloatNear(fg_rgb[0], .05f), - FloatNear(fg_rgb[1], .05f), - FloatNear(fg_rgb[2], .05f))); + EXPECT_ARRAY_NEAR(out_rgb, fg_rgb, 0.05f); EXPECT_NEAR(out_a, 1.0f, 1e-5); } TEST(AlphaTest, BlendingWithPremultiplied) { - const float bg_rgb[3] = {100, 110, 120}; + const Color bg_rgb{100, 110, 120}; const float bg_a = 180.f / 255; - const float fg_rgb[3] = {25, 21, 23}; + const Color fg_rgb{25, 21, 23}; const float fg_a = 15420.f / 65535; const float fg_a2 = 2.0f; - float out_rgb[3]; + Color out_rgb; float out_a; PerformAlphaBlending( - /*bg=*/{&bg_rgb[0], &bg_rgb[1], &bg_rgb[2], &bg_a}, - /*fg=*/{&fg_rgb[0], &fg_rgb[1], &fg_rgb[2], &fg_a}, - /*out=*/{&out_rgb[0], &out_rgb[1], &out_rgb[2], &out_a}, 1, + /*bg=*/makeAbil(bg_rgb, bg_a), + /*fg=*/makeAbil(fg_rgb, fg_a), + /*out=*/makeAbo(out_rgb, out_a), 1, /*alpha_is_premultiplied=*/true, /*clamp=*/false); - EXPECT_THAT(out_rgb, - ElementsAre(FloatNear(101.5f, .05f), FloatNear(105.1f, .05f), - FloatNear(114.8f, .05f))); + EXPECT_ARRAY_NEAR(out_rgb, (Color{101.5f, 105.1f, 114.8f}), 0.05f); EXPECT_NEAR(out_a, 3174.f / 4095, 1e-5); PerformAlphaBlending( - /*bg=*/{&bg_rgb[0], &bg_rgb[1], &bg_rgb[2], &bg_a}, - /*fg=*/{&fg_rgb[0], &fg_rgb[1], &fg_rgb[2], &fg_a2}, - /*out=*/{&out_rgb[0], &out_rgb[1], &out_rgb[2], &out_a}, 1, + /*bg=*/makeAbil(bg_rgb, bg_a), + /*fg=*/makeAbil(fg_rgb, fg_a2), + /*out=*/makeAbo(out_rgb, out_a), 1, /*alpha_is_premultiplied=*/true, /*clamp=*/true); - EXPECT_THAT(out_rgb, ElementsAre(FloatNear(fg_rgb[0], .05f), - FloatNear(fg_rgb[1], .05f), - FloatNear(fg_rgb[2], .05f))); + EXPECT_ARRAY_NEAR(out_rgb, fg_rgb, 0.05f); EXPECT_NEAR(out_a, 1.0f, 1e-5); } @@ -76,58 +76,51 @@ TEST(AlphaTest, Mul) { const float fg = 25; float out; PerformMulBlending(&bg, &fg, &out, 1, /*clamp=*/false); - EXPECT_THAT(out, FloatNear(fg * bg, .05f)); + EXPECT_NEAR(out, fg * bg, .05f); PerformMulBlending(&bg, &fg, &out, 1, /*clamp=*/true); - EXPECT_THAT(out, FloatNear(bg, .05f)); + EXPECT_NEAR(out, bg, .05f); } TEST(AlphaTest, PremultiplyAndUnpremultiply) { - const float alpha[] = {0.f, 63.f / 255, 127.f / 255, 1.f}; - float r[] = {120, 130, 140, 150}; - float g[] = {124, 134, 144, 154}; - float b[] = {127, 137, 147, 157}; - - PremultiplyAlpha(r, g, b, alpha, 4); - EXPECT_THAT( - r, ElementsAre(FloatNear(0.f, 1e-5f), FloatNear(130 * 63.f / 255, 1e-5f), - FloatNear(140 * 127.f / 255, 1e-5f), 150)); - EXPECT_THAT( - g, ElementsAre(FloatNear(0.f, 1e-5f), FloatNear(134 * 63.f / 255, 1e-5f), - FloatNear(144 * 127.f / 255, 1e-5f), 154)); - EXPECT_THAT( - b, ElementsAre(FloatNear(0.f, 1e-5f), FloatNear(137 * 63.f / 255, 1e-5f), - FloatNear(147 * 127.f / 255, 1e-5f), 157)); - - UnpremultiplyAlpha(r, g, b, alpha, 4); - EXPECT_THAT(r, ElementsAre(FloatNear(120, 1e-4f), FloatNear(130, 1e-4f), - FloatNear(140, 1e-4f), FloatNear(150, 1e-4f))); - EXPECT_THAT(g, ElementsAre(FloatNear(124, 1e-4f), FloatNear(134, 1e-4f), - FloatNear(144, 1e-4f), FloatNear(154, 1e-4f))); - EXPECT_THAT(b, ElementsAre(FloatNear(127, 1e-4f), FloatNear(137, 1e-4f), - FloatNear(147, 1e-4f), FloatNear(157, 1e-4f))); + using F4 = std::array; + const F4 alpha{0.f, 63.f / 255, 127.f / 255, 1.f}; + F4 r{120, 130, 140, 150}; + F4 g{124, 134, 144, 154}; + F4 b{127, 137, 147, 157}; + + PremultiplyAlpha(r.data(), g.data(), b.data(), alpha.data(), alpha.size()); + EXPECT_ARRAY_NEAR(r, (F4{0.0f, 130 * 63.f / 255, 140 * 127.f / 255, 150}), + 1e-5f); + EXPECT_ARRAY_NEAR(g, (F4{0.0f, 134 * 63.f / 255, 144 * 127.f / 255, 154}), + 1e-5f); + EXPECT_ARRAY_NEAR(b, (F4{0.0f, 137 * 63.f / 255, 147 * 127.f / 255, 157}), + 1e-5f); + + UnpremultiplyAlpha(r.data(), g.data(), b.data(), alpha.data(), alpha.size()); + EXPECT_ARRAY_NEAR(r, (F4{120, 130, 140, 150}), 1e-4f); + EXPECT_ARRAY_NEAR(g, (F4{124, 134, 144, 154}), 1e-4f); + EXPECT_ARRAY_NEAR(b, (F4{127, 137, 147, 157}), 1e-4f); } TEST(AlphaTest, UnpremultiplyAndPremultiply) { - const float alpha[] = {0.f, 63.f / 255, 127.f / 255, 1.f}; - float r[] = {50, 60, 70, 80}; - float g[] = {54, 64, 74, 84}; - float b[] = {57, 67, 77, 87}; - - UnpremultiplyAlpha(r, g, b, alpha, 4); - EXPECT_THAT(r, ElementsAre(_, FloatNear(60 * 255.f / 63, 1e-4f), - FloatNear(70 * 255.f / 127, 1e-4f), 80)); - EXPECT_THAT(g, ElementsAre(_, FloatNear(64 * 255.f / 63, 1e-4f), - FloatNear(74 * 255.f / 127, 1e-4f), 84)); - EXPECT_THAT(b, ElementsAre(_, FloatNear(67 * 255.f / 63, 1e-4f), - FloatNear(77 * 255.f / 127, 1e-4f), 87)); - - PremultiplyAlpha(r, g, b, alpha, 4); - EXPECT_THAT(r, ElementsAre(FloatNear(50, 1e-4f), FloatNear(60, 1e-4f), - FloatNear(70, 1e-4f), FloatNear(80, 1e-4f))); - EXPECT_THAT(g, ElementsAre(FloatNear(54, 1e-4f), FloatNear(64, 1e-4f), - FloatNear(74, 1e-4f), FloatNear(84, 1e-4f))); - EXPECT_THAT(b, ElementsAre(FloatNear(57, 1e-4f), FloatNear(67, 1e-4f), - FloatNear(77, 1e-4f), FloatNear(87, 1e-4f))); + using F4 = std::array; + const F4 alpha{0.f, 63.f / 255, 127.f / 255, 1.f}; + F4 r{50, 60, 70, 80}; + F4 g{54, 64, 74, 84}; + F4 b{57, 67, 77, 87}; + + UnpremultiplyAlpha(r.data(), g.data(), b.data(), alpha.data(), alpha.size()); + EXPECT_ARRAY_NEAR( + r, (F4{50.0f * (1 << 26), 60 * 255.f / 63, 70 * 255.f / 127, 80}), 1e-4f); + EXPECT_ARRAY_NEAR( + g, (F4{54.0f * (1 << 26), 64 * 255.f / 63, 74 * 255.f / 127, 84}), 1e-4f); + EXPECT_ARRAY_NEAR( + b, (F4{57.0f * (1 << 26), 67 * 255.f / 63, 77 * 255.f / 127, 87}), 1e-4f); + + PremultiplyAlpha(r.data(), g.data(), b.data(), alpha.data(), alpha.size()); + EXPECT_ARRAY_NEAR(r, (F4{50, 60, 70, 80}), 1e-4); + EXPECT_ARRAY_NEAR(g, (F4{54, 64, 74, 84}), 1e-4); + EXPECT_ARRAY_NEAR(b, (F4{57, 67, 77, 87}), 1e-4); } } // namespace diff --git a/third_party/jpeg-xl/lib/jxl/ans_common.cc b/third_party/jpeg-xl/lib/jxl/ans_common.cc index 8e52cad0e8bf9..306ecb7276782 100644 --- a/third_party/jpeg-xl/lib/jxl/ans_common.cc +++ b/third_party/jpeg-xl/lib/jxl/ans_common.cc @@ -5,7 +5,10 @@ #include "lib/jxl/ans_common.h" +#include +#include #include +#include #include "lib/jxl/ans_params.h" #include "lib/jxl/base/status.h" @@ -13,8 +16,8 @@ namespace jxl { std::vector CreateFlatHistogram(int length, int total_count) { - JXL_ASSERT(length > 0); - JXL_ASSERT(length <= total_count); + JXL_DASSERT(length > 0); + JXL_DASSERT(length <= total_count); const int count = total_count / length; std::vector result(length, count); const int rem_counts = total_count % length; @@ -48,8 +51,12 @@ std::vector CreateFlatHistogram(int length, int total_count) { // underfull nor overfull, and represents exactly two symbols. The overfull // entry might be either overfull or underfull, and is pushed into the // corresponding stack. -void InitAliasTable(std::vector distribution, uint32_t range, - size_t log_alpha_size, AliasTable::Entry* JXL_RESTRICT a) { +Status InitAliasTable(std::vector distribution, uint32_t log_range, + size_t log_alpha_size, + AliasTable::Entry* JXL_RESTRICT a) { + const uint32_t range = 1 << log_range; + const size_t table_size = 1 << log_alpha_size; + JXL_ENSURE(table_size <= range); while (!distribution.empty() && distribution.back() == 0) { distribution.pop_back(); } @@ -59,32 +66,36 @@ void InitAliasTable(std::vector distribution, uint32_t range, if (distribution.empty()) { distribution.emplace_back(range); } - const size_t table_size = 1 << log_alpha_size; -#if JXL_ENABLE_ASSERT - int sum = std::accumulate(distribution.begin(), distribution.end(), 0); -#endif // JXL_ENABLE_ASSERT - JXL_ASSERT(static_cast(sum) == range); - // range must be a power of two - JXL_ASSERT((range & (range - 1)) == 0); - JXL_ASSERT(distribution.size() <= table_size); - JXL_ASSERT(table_size <= range); + JXL_ENSURE(distribution.size() <= table_size); const uint32_t entry_size = range >> log_alpha_size; // this is exact + int single_symbol = -1; + int sum = 0; // Special case for single-symbol distributions, that ensures that the state // does not change when decoding from such a distribution. Note that, since we // hardcode offset0 == 0, it is not straightforward (if at all possible) to // fix the general case to produce this result. for (size_t sym = 0; sym < distribution.size(); sym++) { - if (distribution[sym] == ANS_TAB_SIZE) { - for (size_t i = 0; i < table_size; i++) { - a[i].right_value = sym; - a[i].cutoff = 0; - a[i].offsets1 = entry_size * i; - a[i].freq0 = 0; - a[i].freq1_xor_freq0 = ANS_TAB_SIZE; - } - return; + int32_t v = distribution[sym]; + sum += v; + if (v == ANS_TAB_SIZE) { + JXL_ENSURE(single_symbol == -1); + single_symbol = sym; + } + } + JXL_ENSURE(static_cast(sum) == range); + if (single_symbol != -1) { + uint8_t sym = single_symbol; + JXL_ENSURE(single_symbol == sym); + for (size_t i = 0; i < table_size; i++) { + a[i].right_value = sym; + a[i].cutoff = 0; + a[i].offsets1 = entry_size * i; + a[i].freq0 = 0; + a[i].freq1_xor_freq0 = ANS_TAB_SIZE; } + return true; } + std::vector underfull_posn; std::vector overfull_posn; std::vector cutoffs(1 << log_alpha_size); @@ -105,7 +116,7 @@ void InitAliasTable(std::vector distribution, uint32_t range, while (!overfull_posn.empty()) { uint32_t overfull_i = overfull_posn.back(); overfull_posn.pop_back(); - JXL_ASSERT(!underfull_posn.empty()); + JXL_ENSURE(!underfull_posn.empty()); uint32_t underfull_i = underfull_posn.back(); underfull_posn.pop_back(); uint32_t underfull_by = entry_size - cutoffs[underfull_i]; @@ -143,6 +154,7 @@ void InitAliasTable(std::vector distribution, uint32_t range, a[i].freq0 = static_cast(freq0); a[i].freq1_xor_freq0 = static_cast(freq1 ^ freq0); } + return true; } } // namespace jxl diff --git a/third_party/jpeg-xl/lib/jxl/ans_common.h b/third_party/jpeg-xl/lib/jxl/ans_common.h index 44b8e3fba13eb..20897028f026a 100644 --- a/third_party/jpeg-xl/lib/jxl/ans_common.h +++ b/third_party/jpeg-xl/lib/jxl/ans_common.h @@ -6,9 +6,11 @@ #ifndef LIB_JXL_ANS_COMMON_H_ #define LIB_JXL_ANS_COMMON_H_ -#include - #include +#include +#include +#include +#include #include // Prefetch #include @@ -21,8 +23,8 @@ namespace jxl { // Returns the precision (number of bits) that should be used to store // a histogram count such that Log2Floor(count) == logcount. -static JXL_INLINE uint32_t GetPopulationCountPrecision(uint32_t logcount, - uint32_t shift) { +static JXL_MAYBE_UNUSED JXL_INLINE uint32_t +GetPopulationCountPrecision(uint32_t logcount, uint32_t shift) { int32_t r = std::min( logcount, static_cast(shift) - static_cast((ANS_LOG_TAB_SIZE - logcount) >> 1)); @@ -136,8 +138,8 @@ struct AliasTable { }; // Computes an alias table for a given distribution. -void InitAliasTable(std::vector distribution, uint32_t range, - size_t log_alpha_size, AliasTable::Entry* JXL_RESTRICT a); +Status InitAliasTable(std::vector distribution, uint32_t log_range, + size_t log_alpha_size, AliasTable::Entry* JXL_RESTRICT a); } // namespace jxl diff --git a/third_party/jpeg-xl/lib/jxl/ans_common_test.cc b/third_party/jpeg-xl/lib/jxl/ans_common_test.cc index 487b6cf5bdb44..b97f5186f9fae 100644 --- a/third_party/jpeg-xl/lib/jxl/ans_common_test.cc +++ b/third_party/jpeg-xl/lib/jxl/ans_common_test.cc @@ -14,10 +14,11 @@ namespace jxl { namespace { void VerifyAliasDistribution(const std::vector& distribution, - uint32_t range) { + uint32_t log_range) { constexpr size_t log_alpha_size = 8; AliasTable::Entry table[1 << log_alpha_size]; - InitAliasTable(distribution, range, log_alpha_size, table); + ASSERT_TRUE(InitAliasTable(distribution, log_range, log_alpha_size, table)); + uint32_t range = 1 << log_range; std::vector> offsets(distribution.size()); for (uint32_t i = 0; i < range; i++) { AliasTable::Symbol s = AliasTable::Lookup( @@ -34,9 +35,10 @@ void VerifyAliasDistribution(const std::vector& distribution, } TEST(ANSCommonTest, AliasDistributionSmoke) { - VerifyAliasDistribution({ANS_TAB_SIZE / 2, ANS_TAB_SIZE / 2}, ANS_TAB_SIZE); - VerifyAliasDistribution({ANS_TAB_SIZE}, ANS_TAB_SIZE); - VerifyAliasDistribution({0, 0, 0, ANS_TAB_SIZE, 0}, ANS_TAB_SIZE); + VerifyAliasDistribution({ANS_TAB_SIZE / 2, ANS_TAB_SIZE / 2}, + ANS_LOG_TAB_SIZE); + VerifyAliasDistribution({ANS_TAB_SIZE}, ANS_LOG_TAB_SIZE); + VerifyAliasDistribution({0, 0, 0, ANS_TAB_SIZE, 0}, ANS_LOG_TAB_SIZE); } } // namespace diff --git a/third_party/jpeg-xl/lib/jxl/ans_test.cc b/third_party/jpeg-xl/lib/jxl/ans_test.cc index 5d6a5ef0906a8..8bed98895f4c1 100644 --- a/third_party/jpeg-xl/lib/jxl/ans_test.cc +++ b/third_party/jpeg-xl/lib/jxl/ans_test.cc @@ -3,19 +3,22 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include -#include +#include +#include +#include #include #include "lib/jxl/ans_params.h" #include "lib/jxl/base/random.h" -#include "lib/jxl/base/span.h" +#include "lib/jxl/base/status.h" #include "lib/jxl/dec_ans.h" #include "lib/jxl/dec_bit_reader.h" #include "lib/jxl/enc_ans.h" #include "lib/jxl/enc_aux_out.h" #include "lib/jxl/enc_bit_writer.h" +#include "lib/jxl/test_memory_manager.h" +#include "lib/jxl/test_utils.h" #include "lib/jxl/testing.h" namespace jxl { @@ -23,29 +26,37 @@ namespace { void RoundtripTestcase(int n_histograms, int alphabet_size, const std::vector& input_values) { + JxlMemoryManager* memory_manager = jxl::test::MemoryManager(); constexpr uint16_t kMagic1 = 0x9e33; constexpr uint16_t kMagic2 = 0x8b04; - BitWriter writer; + BitWriter writer{memory_manager}; // Space for magic bytes. - BitWriter::Allotment allotment_magic1(&writer, 16); - writer.Write(16, kMagic1); - allotment_magic1.ReclaimAndCharge(&writer, 0, nullptr); + ASSERT_TRUE(writer.WithMaxBits(16, LayerType::Header, nullptr, [&] { + writer.Write(16, kMagic1); + return true; + })); std::vector context_map; EntropyEncodingData codes; std::vector> input_values_vec; input_values_vec.push_back(input_values); - BuildAndEncodeHistograms(HistogramParams(), n_histograms, input_values_vec, - &codes, &context_map, &writer, 0, nullptr); - WriteTokens(input_values_vec[0], codes, context_map, 0, &writer, 0, nullptr); + JXL_TEST_ASSIGN_OR_DIE( + size_t cost, + BuildAndEncodeHistograms(memory_manager, HistogramParams(), n_histograms, + input_values_vec, &codes, &context_map, &writer, + LayerType::Header, nullptr)); + (void)cost; + ASSERT_TRUE(WriteTokens(input_values_vec[0], codes, context_map, 0, &writer, + LayerType::Header, nullptr)); // Magic bytes + padding - BitWriter::Allotment allotment_magic2(&writer, 24); - writer.Write(16, kMagic2); - writer.ZeroPadToByte(); - allotment_magic2.ReclaimAndCharge(&writer, 0, nullptr); + ASSERT_TRUE(writer.WithMaxBits(24, LayerType::Header, nullptr, [&] { + writer.Write(16, kMagic2); + writer.ZeroPadToByte(); + return true; + })); // We do not truncate the output. Reading past the end reads out zeroes // anyway. @@ -55,10 +66,11 @@ void RoundtripTestcase(int n_histograms, int alphabet_size, std::vector dec_context_map; ANSCode decoded_codes; - ASSERT_TRUE( - DecodeHistograms(&br, n_histograms, &decoded_codes, &dec_context_map)); + ASSERT_TRUE(DecodeHistograms(memory_manager, &br, n_histograms, + &decoded_codes, &dec_context_map)); ASSERT_EQ(dec_context_map, context_map); - ANSSymbolReader reader(&decoded_codes, &br); + JXL_TEST_ASSIGN_OR_DIE(ANSSymbolReader reader, + ANSSymbolReader::Create(&decoded_codes, &br)); for (const Token& symbol : input_values) { uint32_t read_symbol = @@ -157,6 +169,7 @@ TEST(ANSTest, RandomUnbalancedStreamRoundtripBig) { } TEST(ANSTest, UintConfigRoundtrip) { + JxlMemoryManager* memory_manager = jxl::test::MemoryManager(); for (size_t log_alpha_size = 5; log_alpha_size <= 8; log_alpha_size++) { std::vector uint_config; std::vector uint_config_dec; @@ -169,10 +182,12 @@ TEST(ANSTest, UintConfigRoundtrip) { } uint_config.emplace_back(log_alpha_size, 0, 0); uint_config_dec.resize(uint_config.size()); - BitWriter writer; - BitWriter::Allotment allotment(&writer, 10 * uint_config.size()); - EncodeUintConfigs(uint_config, &writer, log_alpha_size); - allotment.ReclaimAndCharge(&writer, 0, nullptr); + BitWriter writer{memory_manager}; + ASSERT_TRUE(writer.WithMaxBits( + 10 * uint_config.size(), LayerType::Header, nullptr, [&] { + EncodeUintConfigs(uint_config, &writer, log_alpha_size); + return true; + })); writer.ZeroPadToByte(); BitReader br(writer.GetSpan()); EXPECT_TRUE(DecodeUintConfigs(log_alpha_size, &uint_config_dec, &br)); @@ -186,6 +201,7 @@ TEST(ANSTest, UintConfigRoundtrip) { } void TestCheckpointing(bool ans, bool lz77) { + JxlMemoryManager* memory_manager = jxl::test::MemoryManager(); std::vector> input_values(1); for (size_t i = 0; i < 1024; i++) { input_values[0].emplace_back(0, i % 4); @@ -207,13 +223,16 @@ void TestCheckpointing(bool ans, bool lz77) { : HistogramParams::LZ77Method::kNone; params.force_huffman = !ans; - BitWriter writer; + BitWriter writer{memory_manager}; { auto input_values_copy = input_values; - BuildAndEncodeHistograms(params, 1, input_values_copy, &codes, &context_map, - &writer, 0, nullptr); - WriteTokens(input_values_copy[0], codes, context_map, 0, &writer, 0, - nullptr); + JXL_TEST_ASSIGN_OR_DIE( + size_t cost, BuildAndEncodeHistograms( + memory_manager, params, 1, input_values_copy, &codes, + &context_map, &writer, LayerType::Header, nullptr)); + (void)cost; + ASSERT_TRUE(WriteTokens(input_values_copy[0], codes, context_map, 0, + &writer, LayerType::Header, nullptr)); writer.ZeroPadToByte(); } @@ -222,13 +241,15 @@ void TestCheckpointing(bool ans, bool lz77) { BitReader br(writer.GetSpan()); Status status = true; { - BitReaderScopedCloser bc(&br, &status); + BitReaderScopedCloser bc(br, status); std::vector dec_context_map; ANSCode decoded_codes; - ASSERT_TRUE(DecodeHistograms(&br, 1, &decoded_codes, &dec_context_map)); + ASSERT_TRUE(DecodeHistograms(memory_manager, &br, 1, &decoded_codes, + &dec_context_map)); ASSERT_EQ(dec_context_map, context_map); - ANSSymbolReader reader(&decoded_codes, &br); + JXL_TEST_ASSIGN_OR_DIE(ANSSymbolReader reader, + ANSSymbolReader::Create(&decoded_codes, &br)); ANSSymbolReader::Checkpoint checkpoint; size_t br_pos = 0; diff --git a/third_party/jpeg-xl/lib/jxl/base/common.h b/third_party/jpeg-xl/lib/jxl/base/common.h index d57328050ecaf..0893ef26b5a5a 100644 --- a/third_party/jpeg-xl/lib/jxl/base/common.h +++ b/third_party/jpeg-xl/lib/jxl/base/common.h @@ -70,6 +70,8 @@ std::unique_ptr make_unique(Args&&... args) { using std::make_unique; #endif +typedef std::array Color; + // Backported std::experimental::to_array template diff --git a/third_party/jpeg-xl/lib/jxl/base/compiler_specific.h b/third_party/jpeg-xl/lib/jxl/base/compiler_specific.h index 702ff8e058179..cb1a8a038641f 100644 --- a/third_party/jpeg-xl/lib/jxl/base/compiler_specific.h +++ b/third_party/jpeg-xl/lib/jxl/base/compiler_specific.h @@ -8,11 +8,14 @@ // Macros for compiler version + nonstandard keywords, e.g. __builtin_expect. -#include #include #include "lib/jxl/base/sanitizer_definitions.h" +#if JXL_ADDRESS_SANITIZER || JXL_MEMORY_SANITIZER || JXL_THREAD_SANITIZER +#include "sanitizer/common_interface_defs.h" // __sanitizer_print_stack_trace +#endif // defined(*_SANITIZER) + // #if is shorter and safer than #ifdef. *_VERSION are zero if not detected, // otherwise 100 * major + minor version. Note that other packages check for // #ifdef COMPILER_MSVC, so we cannot use that same name. @@ -62,14 +65,6 @@ #define JXL_NORETURN #endif -#if JXL_COMPILER_MSVC -#define JXL_UNREACHABLE_BUILTIN __assume(false) -#elif JXL_COMPILER_CLANG || JXL_COMPILER_GCC >= 405 -#define JXL_UNREACHABLE_BUILTIN __builtin_unreachable() -#else -#define JXL_UNREACHABLE_BUILTIN -#endif - #if JXL_COMPILER_MSVC #define JXL_MAYBE_UNUSED #else @@ -97,6 +92,11 @@ #define JXL_UNLIKELY(expr) __builtin_expect(!!(expr), 0) #endif +#if JXL_COMPILER_MSVC +#include +using ssize_t = intptr_t; +#endif + // Returns a void* pointer which the compiler then assumes is N-byte aligned. // Example: float* JXL_RESTRICT aligned = (float*)JXL_ASSUME_ALIGNED(in, 32); // @@ -150,8 +150,71 @@ #define JXL_FORMAT(idx_fmt, idx_arg) #endif +// C++ standard. +#if defined(_MSC_VER) && !defined(__clang__) && defined(_MSVC_LANG) && \ + _MSVC_LANG > __cplusplus +#define JXL_CXX_LANG _MSVC_LANG +#else +#define JXL_CXX_LANG __cplusplus +#endif + +// Known / distinguished C++ standards. +#define JXL_CXX_17 201703 + +// In most cases we consider build as "debug". Use `NDEBUG` for release build. +#if defined(JXL_IS_DEBUG_BUILD) +#undef JXL_IS_DEBUG_BUILD +#define JXL_IS_DEBUG_BUILD 1 +#elif defined(NDEBUG) +#define JXL_IS_DEBUG_BUILD 0 +#else +#define JXL_IS_DEBUG_BUILD 1 +#endif + +#if defined(JXL_CRASH_ON_ERROR) +#undef JXL_CRASH_ON_ERROR +#define JXL_CRASH_ON_ERROR 1 +#else +#define JXL_CRASH_ON_ERROR 0 +#endif + +#if JXL_CRASH_ON_ERROR && !JXL_IS_DEBUG_BUILD +#error "JXL_CRASH_ON_ERROR requires JXL_IS_DEBUG_BUILD" +#endif + +// Pass -DJXL_DEBUG_ON_ALL_ERROR at compile time to print debug messages on +// all error (fatal and non-fatal) status. +#if defined(JXL_DEBUG_ON_ALL_ERROR) +#undef JXL_DEBUG_ON_ALL_ERROR +#define JXL_DEBUG_ON_ALL_ERROR 1 +#else +#define JXL_DEBUG_ON_ALL_ERROR 0 +#endif + +#if JXL_DEBUG_ON_ALL_ERROR && !JXL_IS_DEBUG_BUILD +#error "JXL_DEBUG_ON_ALL_ERROR requires JXL_IS_DEBUG_BUILD" +#endif + +// Pass -DJXL_DEBUG_ON_ABORT={0} to disable the debug messages on +// (debug) JXL_ENSURE and JXL_DASSERT. +#if !defined(JXL_DEBUG_ON_ABORT) +#define JXL_DEBUG_ON_ABORT JXL_IS_DEBUG_BUILD +#endif // JXL_DEBUG_ON_ABORT + +#if JXL_DEBUG_ON_ABORT && !JXL_IS_DEBUG_BUILD +#error "JXL_DEBUG_ON_ABORT requires JXL_IS_DEBUG_BUILD" +#endif + +#if JXL_ADDRESS_SANITIZER || JXL_MEMORY_SANITIZER || JXL_THREAD_SANITIZER +#define JXL_PRINT_STACK_TRACE() __sanitizer_print_stack_trace(); +#else +#define JXL_PRINT_STACK_TRACE() +#endif + #if JXL_COMPILER_MSVC -using ssize_t = intptr_t; +#define JXL_CRASH() __debugbreak(), (void)abort() +#else +#define JXL_CRASH() (void)__builtin_trap() #endif #endif // LIB_JXL_BASE_COMPILER_SPECIFIC_H_ diff --git a/third_party/jpeg-xl/lib/jxl/base/data_parallel.h b/third_party/jpeg-xl/lib/jxl/base/data_parallel.h index a7f977b7ce9be..e39f46c75b929 100644 --- a/third_party/jpeg-xl/lib/jxl/base/data_parallel.h +++ b/third_party/jpeg-xl/lib/jxl/base/data_parallel.h @@ -10,8 +10,10 @@ // data-parallel computations. #include -#include -#include + +#include +#include +#include #include "lib/jxl/base/compiler_specific.h" #include "lib/jxl/base/status.h" @@ -44,25 +46,34 @@ class ThreadPool { // Precondition: begin <= end. template Status Run(uint32_t begin, uint32_t end, const InitFunc& init_func, - const DataFunc& data_func, const char* caller = "") { - JXL_ASSERT(begin <= end); + const DataFunc& data_func, const char* caller) { + JXL_ENSURE(begin <= end); if (begin == end) return true; RunCallState call_state(init_func, data_func); // The runner_ uses the C convention and returns 0 in case of error, so we // convert it to a Status. if (!runner_) { void* jpegxl_opaque = static_cast(&call_state); - if (call_state.CallInitFunc(jpegxl_opaque, 1) != 0) { + if (call_state.CallInitFunc(jpegxl_opaque, 1) != + JXL_PARALLEL_RET_SUCCESS) { return JXL_FAILURE("Failed to initialize thread"); } for (uint32_t i = begin; i < end; i++) { call_state.CallDataFunc(jpegxl_opaque, i, 0); } + if (call_state.HasError()) { + return JXL_FAILURE("[%s] failed", caller); + } return true; } - return (*runner_)(runner_opaque_, static_cast(&call_state), - &call_state.CallInitFunc, &call_state.CallDataFunc, begin, - end) == 0; + JxlParallelRetCode ret = (*runner_)( + runner_opaque_, static_cast(&call_state), + &call_state.CallInitFunc, &call_state.CallDataFunc, begin, end); + + if (ret != JXL_PARALLEL_RET_SUCCESS || call_state.HasError()) { + return JXL_FAILURE("[%s] failed", caller); + } + return true; } // Use this as init_func when no initialization is needed. @@ -79,24 +90,34 @@ class ThreadPool { // JxlParallelRunInit interface. static int CallInitFunc(void* jpegxl_opaque, size_t num_threads) { - const auto* self = + auto* self = static_cast*>(jpegxl_opaque); // Returns -1 when the internal init function returns false Status to // indicate an error. - return self->init_func_(num_threads) ? 0 : -1; + if (!self->init_func_(num_threads)) { + self->has_error_ = true; + return JXL_PARALLEL_RET_RUNNER_ERROR; + } + return JXL_PARALLEL_RET_SUCCESS; } // JxlParallelRunFunction interface. static void CallDataFunc(void* jpegxl_opaque, uint32_t value, size_t thread_id) { - const auto* self = + auto* self = static_cast*>(jpegxl_opaque); - return self->data_func_(value, thread_id); + if (self->has_error_) return; + if (!self->data_func_(value, thread_id)) { + self->has_error_ = true; + } } + bool HasError() const { return has_error_; } + private: const InitFunc& init_func_; const DataFunc& data_func_; + std::atomic has_error_{false}; }; // The caller supplied runner function and its opaque void*. diff --git a/third_party/jpeg-xl/lib/jxl/base/exif.h b/third_party/jpeg-xl/lib/jxl/base/exif.h index a3574a16ffda7..acaa1a1ce4361 100644 --- a/third_party/jpeg-xl/lib/jxl/base/exif.h +++ b/third_party/jpeg-xl/lib/jxl/base/exif.h @@ -3,8 +3,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#ifndef LIB_JXL_EXIF_H_ -#define LIB_JXL_EXIF_H_ +#ifndef LIB_JXL_BASE_EXIF_H_ +#define LIB_JXL_BASE_EXIF_H_ // Basic parsing of Exif (just enough for the render-impacting things // like orientation) @@ -87,4 +87,4 @@ JXL_INLINE void InterpretExif(const std::vector& exif, } // namespace jxl -#endif // LIB_JXL_EXIF_H_ +#endif // LIB_JXL_BASE_EXIF_H_ diff --git a/third_party/jpeg-xl/lib/jxl/base/float.h b/third_party/jpeg-xl/lib/jxl/base/float.h index 0f5b3b1f3a413..50af582b6f54a 100644 --- a/third_party/jpeg-xl/lib/jxl/base/float.h +++ b/third_party/jpeg-xl/lib/jxl/base/float.h @@ -62,9 +62,7 @@ static Status JXL_INLINE LoadFloatRow(const uint8_t* src, size_t count, case JXL_TYPE_UINT8: for (size_t i = 0; i < count; ++i) { - // Integer multiply uint8 value before scaling so that the UINT8 value - // and the corresponding UINT16 value convert to the same float - callback(i, (src[stride * i] * 257) * scale); + callback(i, src[stride * i] * scale); } return true; diff --git a/third_party/jpeg-xl/lib/jxl/base/include_jpeglib.h b/third_party/jpeg-xl/lib/jxl/base/include_jpeglib.h new file mode 100644 index 0000000000000..f72d13d04bad0 --- /dev/null +++ b/third_party/jpeg-xl/lib/jxl/base/include_jpeglib.h @@ -0,0 +1,20 @@ +// Copyright (c) the JPEG XL Project Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#ifndef LIB_JXL_BASE_INCLUDE_JPEGLIB_H_ +#define LIB_JXL_BASE_INCLUDE_JPEGLIB_H_ + +// Using this header ensures that includes go in the right order, +// not alphabetically sorted. + +// NOLINTBEGIN +/* clang-format off */ +#include // IWYU pragma: keep +#include // IWYU pragma: keep +#include // IWYU pragma: keep +/* clang-format on */ +// NOLINTEND + +#endif // LIB_JXL_BASE_INCLUDE_JPEGLIB_H_ diff --git a/third_party/jpeg-xl/lib/jxl/base/matrix_ops.h b/third_party/jpeg-xl/lib/jxl/base/matrix_ops.h index 1a969bd4f0a0c..e1f8753932581 100644 --- a/third_party/jpeg-xl/lib/jxl/base/matrix_ops.h +++ b/third_party/jpeg-xl/lib/jxl/base/matrix_ops.h @@ -3,11 +3,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#ifndef LIB_JXL_MATRIX_OPS_H_ -#define LIB_JXL_MATRIX_OPS_H_ +#ifndef LIB_JXL_BASE_MATRIX_OPS_H_ +#define LIB_JXL_BASE_MATRIX_OPS_H_ // 3x3 matrix operations. +#include #include // abs #include @@ -15,70 +16,71 @@ namespace jxl { +typedef std::array Vector3; +typedef std::array Vector3d; +typedef std::array Matrix3x3; +typedef std::array Matrix3x3d; + // Computes C = A * B, where A, B, C are 3x3 matrices. -template -void Mul3x3Matrix(const T* a, const T* b, T* c) { - alignas(16) T temp[3]; // For transposed column +template +void Mul3x3Matrix(const Matrix& a, const Matrix& b, Matrix& c) { for (size_t x = 0; x < 3; x++) { - for (size_t z = 0; z < 3; z++) { - temp[z] = b[z * 3 + x]; - } + alignas(16) Vector3d temp{b[0][x], b[1][x], b[2][x]}; // transpose for (size_t y = 0; y < 3; y++) { - double e = 0; - for (size_t z = 0; z < 3; z++) { - e += a[y * 3 + z] * temp[z]; - } - c[y * 3 + x] = e; + c[y][x] = a[y][0] * temp[0] + a[y][1] * temp[1] + a[y][2] * temp[2]; } } } // Computes C = A * B, where A is 3x3 matrix and B is vector. -template -void Mul3x3Vector(const T* a, const T* b, T* c) { +template +void Mul3x3Vector(const Matrix& a, const Vector& b, Vector& c) { for (size_t y = 0; y < 3; y++) { double e = 0; for (size_t x = 0; x < 3; x++) { - e += a[y * 3 + x] * b[x]; + e += a[y][x] * b[x]; } c[y] = e; } } // Inverts a 3x3 matrix in place. -template -Status Inv3x3Matrix(T* matrix) { +template +Status Inv3x3Matrix(Matrix& matrix) { // Intermediate computation is done in double precision. - double temp[9]; - temp[0] = static_cast(matrix[4]) * matrix[8] - - static_cast(matrix[5]) * matrix[7]; - temp[1] = static_cast(matrix[2]) * matrix[7] - - static_cast(matrix[1]) * matrix[8]; - temp[2] = static_cast(matrix[1]) * matrix[5] - - static_cast(matrix[2]) * matrix[4]; - temp[3] = static_cast(matrix[5]) * matrix[6] - - static_cast(matrix[3]) * matrix[8]; - temp[4] = static_cast(matrix[0]) * matrix[8] - - static_cast(matrix[2]) * matrix[6]; - temp[5] = static_cast(matrix[2]) * matrix[3] - - static_cast(matrix[0]) * matrix[5]; - temp[6] = static_cast(matrix[3]) * matrix[7] - - static_cast(matrix[4]) * matrix[6]; - temp[7] = static_cast(matrix[1]) * matrix[6] - - static_cast(matrix[0]) * matrix[7]; - temp[8] = static_cast(matrix[0]) * matrix[4] - - static_cast(matrix[1]) * matrix[3]; - double det = matrix[0] * temp[0] + matrix[1] * temp[3] + matrix[2] * temp[6]; + Matrix3x3d temp; + temp[0][0] = static_cast(matrix[1][1]) * matrix[2][2] - + static_cast(matrix[1][2]) * matrix[2][1]; + temp[0][1] = static_cast(matrix[0][2]) * matrix[2][1] - + static_cast(matrix[0][1]) * matrix[2][2]; + temp[0][2] = static_cast(matrix[0][1]) * matrix[1][2] - + static_cast(matrix[0][2]) * matrix[1][1]; + temp[1][0] = static_cast(matrix[1][2]) * matrix[2][0] - + static_cast(matrix[1][0]) * matrix[2][2]; + temp[1][1] = static_cast(matrix[0][0]) * matrix[2][2] - + static_cast(matrix[0][2]) * matrix[2][0]; + temp[1][2] = static_cast(matrix[0][2]) * matrix[1][0] - + static_cast(matrix[0][0]) * matrix[1][2]; + temp[2][0] = static_cast(matrix[1][0]) * matrix[2][1] - + static_cast(matrix[1][1]) * matrix[2][0]; + temp[2][1] = static_cast(matrix[0][1]) * matrix[2][0] - + static_cast(matrix[0][0]) * matrix[2][1]; + temp[2][2] = static_cast(matrix[0][0]) * matrix[1][1] - + static_cast(matrix[0][1]) * matrix[1][0]; + double det = matrix[0][0] * temp[0][0] + matrix[0][1] * temp[1][0] + + matrix[0][2] * temp[2][0]; if (std::abs(det) < 1e-10) { return JXL_FAILURE("Matrix determinant is too close to 0"); } double idet = 1.0 / det; - for (size_t i = 0; i < 9; i++) { - matrix[i] = temp[i] * idet; + for (size_t j = 0; j < 3; j++) { + for (size_t i = 0; i < 3; i++) { + matrix[j][i] = temp[j][i] * idet; + } } return true; } } // namespace jxl -#endif // LIB_JXL_MATRIX_OPS_H_ +#endif // LIB_JXL_BASE_MATRIX_OPS_H_ diff --git a/third_party/jpeg-xl/lib/jxl/base/random.h b/third_party/jpeg-xl/lib/jxl/base/random.h index b27815bf0031b..6922e282e83bc 100644 --- a/third_party/jpeg-xl/lib/jxl/base/random.h +++ b/third_party/jpeg-xl/lib/jxl/base/random.h @@ -20,7 +20,7 @@ namespace jxl { struct Rng { - explicit Rng(size_t seed) + explicit Rng(uint64_t seed) : s{static_cast(0x94D049BB133111EBull), static_cast(0xBF58476D1CE4E5B9ull) + seed} {} diff --git a/third_party/jpeg-xl/lib/jxl/base/rect.h b/third_party/jpeg-xl/lib/jxl/base/rect.h new file mode 100644 index 0000000000000..31fe12dfb9529 --- /dev/null +++ b/third_party/jpeg-xl/lib/jxl/base/rect.h @@ -0,0 +1,186 @@ +// Copyright (c) the JPEG XL Project Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#ifndef LIB_JXL_BASE_RECT_H_ +#define LIB_JXL_BASE_RECT_H_ + +#include +#include +#include +#include +#include +#include +#include // std::move + +#include "lib/jxl/base/compiler_specific.h" +#include "lib/jxl/base/status.h" + +namespace jxl { + +// Rectangular region in image(s). Factoring this out of Image instead of +// shifting the pointer by x0/y0 allows this to apply to multiple images with +// different resolutions (e.g. color transform and quantization field). +// Can compare using SameSize(rect1, rect2). +template +class RectT { + public: + // Most windows are xsize_max * ysize_max, except those on the borders where + // begin + size_max > end. + constexpr RectT(T xbegin, T ybegin, size_t xsize_max, size_t ysize_max, + T xend, T yend) + : x0_(xbegin), + y0_(ybegin), + xsize_(ClampedSize(xbegin, xsize_max, xend)), + ysize_(ClampedSize(ybegin, ysize_max, yend)) {} + + // Construct with origin and known size (typically from another Rect). + constexpr RectT(T xbegin, T ybegin, size_t xsize, size_t ysize) + : x0_(xbegin), y0_(ybegin), xsize_(xsize), ysize_(ysize) {} + + // Construct a rect that covers a whole image/plane/ImageBundle etc. + template + explicit RectT(const ImageT& image) + : RectT(0, 0, image.xsize(), image.ysize()) {} + + RectT() : RectT(0, 0, 0, 0) {} + + RectT(const RectT&) = default; + RectT& operator=(const RectT&) = default; + + // Construct a subrect that resides in an image/plane/ImageBundle etc. + template + RectT Crop(const ImageT& image) const { + return Intersection(RectT(image)); + } + + // Construct a subrect that resides in the [0, ysize) x [0, xsize) region of + // the current rect. + RectT Crop(size_t area_xsize, size_t area_ysize) const { + return Intersection(RectT(0, 0, area_xsize, area_ysize)); + } + + JXL_MUST_USE_RESULT RectT Intersection(const RectT& other) const { + return RectT(std::max(x0_, other.x0_), std::max(y0_, other.y0_), xsize_, + ysize_, std::min(x1(), other.x1()), + std::min(y1(), other.y1())); + } + + JXL_MUST_USE_RESULT RectT Translate(int64_t x_offset, + int64_t y_offset) const { + return RectT(x0_ + x_offset, y0_ + y_offset, xsize_, ysize_); + } + + template