Issue #2697 - Part 1: Import libjxl 0.11.1 files to the tree.

This commit is contained in:
Moonchild 2025-03-10 23:05:20 +01:00 • committed by roytam1
commit 845db2526f
910 changed files with 84393 additions and 51559 deletions

View file

@ -0,0 +1 @@
third_party

View file

@ -1,6 +1,4 @@
# Disabled checks: # Disabled checks:
# - google-readability-todo: We don't use the google TODO format.
#
# - modernize-deprecated-headers: We don't use std:: versions of the standard # - modernize-deprecated-headers: We don't use std:: versions of the standard
# types and functions like size_t or printf, so we should include <stdio.h> # types and functions like size_t or printf, so we should include <stdio.h>
# instead <cstdio>. # instead <cstdio>.
@ -27,17 +25,34 @@ Checks: >-
modernize-*, modernize-*,
performance-*, performance-*,
readability-*, readability-*,
-google-readability-todo, -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-deprecated-headers,
-modernize-return-braced-init-list, -modernize-return-braced-init-list,
-modernize-type-traits,
-modernize-use-auto, -modernize-use-auto,
-modernize-use-default-member-init, -modernize-use-default-member-init,
-modernize-use-nodiscard,
-modernize-use-trailing-return-type, -modernize-use-trailing-return-type,
-modernize-use-using, -modernize-use-using,
-performance-enum-size,
-readability-avoid-nested-conditional-operator,
-readability-else-after-return, -readability-else-after-return,
-readability-function-cognitive-complexity, -readability-function-cognitive-complexity,
-readability-identifier-length,
-readability-magic-numbers,
-readability-redundant-access-specifiers,
-readability-simplify-boolean-expr,
-readability-static-accessed-through-instance, -readability-static-accessed-through-instance,
-readability-suspicious-call-argument,
-readability-uppercase-literal-suffix, -readability-uppercase-literal-suffix,
-readability-use-anyofallof,
WarningsAsErrors: >- WarningsAsErrors: >-
@ -68,3 +83,5 @@ CheckOptions:
value: '1' value: '1'
- key: readability-implicit-bool-conversion.AllowIntegerConditions - key: readability-implicit-bool-conversion.AllowIntegerConditions
value: '1' value: '1'
- key: bugprone-signed-char-misuse.CharTypdefsToIgnore
value: 'int8_t'

View file

@ -1,7 +1,10 @@
# Build output directories # Build output directories
/build /build
/build* /build*
/docker/*.log /bazel*
# clangd
.cache
# The downloaded corpora files for benchmark. # The downloaded corpora files for benchmark.
/third_party/corpora /third_party/corpora

View file

@ -25,3 +25,6 @@
[submodule "third_party/testdata"] [submodule "third_party/testdata"]
path = testdata path = testdata
url = https://github.com/libjxl/testdata url = https://github.com/libjxl/testdata
[submodule "third_party/libjpeg-turbo"]
path = third_party/libjpeg-turbo
url = https://github.com/libjpeg-turbo/libjpeg-turbo.git

View file

@ -0,0 +1,30 @@
repos:
- repo: https://github.com/gherynos/pre-commit-java
rev: v0.2.4
hooks:
- id: Checkstyle
- repo: https://github.com/gitleaks/gitleaks
rev: v8.16.3
hooks:
- id: gitleaks
- repo: https://github.com/jumanjihouse/pre-commit-hooks
rev: 3.0.0
hooks:
- id: shellcheck
- repo: https://github.com/pocc/pre-commit-hooks
rev: v1.3.5
hooks:
- id: cpplint
- repo: https://github.com/pre-commit/mirrors-eslint
rev: v8.38.0
hooks:
- id: eslint
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/pylint-dev/pylint
rev: v2.17.2
hooks:
- id: pylint

View file

@ -11,7 +11,14 @@ version: 2
sphinx: sphinx:
configuration: doc/sphinx/conf.py configuration: doc/sphinx/conf.py
build:
os: ubuntu-22.04
tools:
python: "3"
apt_packages:
- doxygen
- graphviz
python: python:
version: "3.7"
install: install:
- requirements: doc/sphinx/requirements.txt - requirements: doc/sphinx/requirements.txt

View file

@ -1,38 +1,75 @@
# List of the project authors for copyright purposes. When contributing to the # List of the project authors.
# project add your name or your organization's name to this list. See # When contributing you can add your name to this list.
# CONTRIBUTING.md for details. # For a complete list of contributions made after the move
# from gitlab to github, see
# https://github.com/libjxl/libjxl/graphs/contributors.
# See CONTRIBUTING.md for details.
# #
# For organizations:
# Organization <email pattern: *@domain>
#
# For individuals:
# Name <email address>
# #
# Please keep each list sorted. If you wish to change your email address please # Please keep each list sorted. If you wish to change your email address please
# send a pull request. # send a pull request.
# Organizations: # Organizations:
Cloudinary Ltd. <*@cloudinary.com>
Google LLC <*@google.com> # - Cloudinary Ltd.:
Jon Sneyers <jon@cloudinary.com>
# - Google:
Evgenii Kliuchnikov <eustas@google.com>
Iulia Comșa <iuliacomsa@google.com>
Jan Wassenberg <janwas@google.com>
Jyrki Alakuijala <jyrki@google.com>
Lode Vandevenne <lode@google.com>
Luca Versari <veluca@google.com>
Marcin Kowalczyk <qrczak@google.com>
Martin Bruse <zond@google.com>
Moritz Firsching <firsching@google.com>
Sami Boukortt <sboukortt@google.com>
Sebastian Gomez <sggonzalez@google.com>
Thomas Fischbacher <tfish@google.com>
Zoltan Szabadka <szabadka@google.com>
# Individuals: # Individuals:
a-shvedov
Aditya Patadia <adityapatadia@users.noreply.github.com>
Ahmad Amsyar Asyadiq Bin Syaiful Bahri <27284123+Ahmad-Amsyar@users.noreply.github.com>
Alex Xu (Hello71) <alex_y_xu@yahoo.ca> Alex Xu (Hello71) <alex_y_xu@yahoo.ca>
Alexander Sago <cagelight@gmail.com> Alexander Sago <cagelight@gmail.com>
Alifian Caesar Khalid <alifiancaesar@gmail.com>
Alistair Barrow
Andrius Lukas Narbutas <andrius4669@gmail.com> Andrius Lukas Narbutas <andrius4669@gmail.com>
Aous Naman <aous@unsw.edu.au> Aous Naman <aous@unsw.edu.au>
Artem Selishchev Artem Selishchev
Aryan Pingle <realaryanpingle@gmail.com>
Biswapriyo Nath <nathbappai@gmail.com> Biswapriyo Nath <nathbappai@gmail.com>
CanadianBaconBoi <beamconnor@gmail.com> CanadianBaconBoi <beamconnor@gmail.com>
Damiano Albani <damiano.albani@gmail.com>
Damon Townsend
Daniel Novomeský <dnovomesky@gmail.com> Daniel Novomeský <dnovomesky@gmail.com>
David Burnett <vargolsoft@gmail.com> David Burnett <vargolsoft@gmail.com>
dependabot[bot]
Diego Pino <dpino@igalia.com>
Dirk Lemstra <dirk@lemstra.org> Dirk Lemstra <dirk@lemstra.org>
Dmitry Baryshev <dima8w@gmail.com>
Don Olmstead <don.j.olmstead@gmail.com> Don Olmstead <don.j.olmstead@gmail.com>
Dong Xu <xdong181@gmail.com>
estrogently <41487185+estrogently@users.noreply.github.com>
Even Rouault <even.rouault@spatialys.com> Even Rouault <even.rouault@spatialys.com>
Fred Brennan <copypaste@kittens.ph>
Gerhard Huber <support@pl32.com>
gi-man
Gilles Devillers (GilDev) <gildev@gmail.com>
Heiko Becker <heirecka@exherbo.org> Heiko Becker <heirecka@exherbo.org>
Jon Sneyers <jon@cloudinary.com> Ivan Kokorev
Jim Robinson <jimbo2150@gmail.com>
John Platts <john_platts@hotmail.com>
Jonathan Brown (Jonnyawsom3) <jonathanbr30@gmail.com>
Joshua Root <jmr@macports.org>
Kai Hollberg <Schweinepriester@users.noreply.github.com> Kai Hollberg <Schweinepriester@users.noreply.github.com>
Kerry Su <me@sshockwave.net>
Kleis Auke Wolthuizen <github@kleisauke.nl> Kleis Auke Wolthuizen <github@kleisauke.nl>
L. E. Segovia L. E. Segovia
ledoge
Leo Izen <leo.izen@gmail.com> Leo Izen <leo.izen@gmail.com>
Lovell Fuller Lovell Fuller
Maarten DB <anonymous.maarten@gmail.com> Maarten DB <anonymous.maarten@gmail.com>
@ -41,14 +78,26 @@ Martin Strunz
Mathieu Malaterre <mathieu.malaterre@gmail.com> Mathieu Malaterre <mathieu.malaterre@gmail.com>
Mikk Leini <mikk.leini@krakul.eu> Mikk Leini <mikk.leini@krakul.eu>
Misaki Kasumi <misakikasumi@outlook.com> Misaki Kasumi <misakikasumi@outlook.com>
Moonchild Straver <moonchild@palemoon.org>
Nicholas Hayes <0xC0000054@users.noreply.github.com>
Nigel Tao <nigeltao@golang.org>
oupson <oupson1er@gmail.com>
Petr Diblík Petr Diblík
Pieter Wuille Pieter Wuille
roland-rollo roland-rollo
Samuel Leong <wvvwvvvvwvvw@gmail.com> Samuel Leong <wvvwvvvvwvvw@gmail.com>
Sandro <sandro.jaeckel@gmail.com> Sandro <sandro.jaeckel@gmail.com>
sandstrom
Sergey Fedorov <vital.had@gmail.com>
Stephan T. Lavavej <stl@nuwen.net> Stephan T. Lavavej <stl@nuwen.net>
StepSecurity Bot <bot@stepsecurity.io>
Sylvestre Ledru <sylvestre@debian.org>
Thomas Bonfort <thomas.bonfort@airbus.com> Thomas Bonfort <thomas.bonfort@airbus.com>
Timo Rothenpieler <timo@rothenpieler.org>
tmkk <tmkkmac@gmail.com>
Vincent Torri <vincent.torri@gmail.com> Vincent Torri <vincent.torri@gmail.com>
Wonwoo Choi <chwo9843@gmail.com>
xiota xiota
Yonatan Nebenzhal <yonatan.nebenzhl@gmail.com> Yonatan Nebenzhal <yonatan.nebenzhl@gmail.com>
Ziemowit Zabawa <ziemek.zabawa@outlook.com> Ziemowit Zabawa <ziemek.zabawa@outlook.com>
源文雨 <41315874+fumiama@users.noreply.github.com>

View file

@ -5,7 +5,149 @@ 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/), 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). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased ## [0.11.1] - 2024-26-11
### Fixed
- Huffman lookup table size fix (#3871 -
[CVE-2024-11403](https://www.cve.org/cverecord?id=CVE-2024-11403))
- Check height limit in modular trees. (#3943 -
[CVE-2024-11498](https://www.cve.org/cverecord?id=CVE-2024-11498))
## [0.11.0] - 2024-09-13
### 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
### Fixed
- bugs in (lossless) encoding (#3367, #3359 and #3386)
- re-enable installation of MIME file (#3375)
- bugs in streaming mode (#3379 and #3380)
## [0.10.1] - 2024-02-28
### Fixed
- reduce allocations (#3336 and #3339),
fixing a significant speed regression present since 0.9.0
- bug in streaming encoding (#3331)
## [0.10.0] - 2024-02-21
### Added
- decoder API: added `JxlDecoderGetBoxSizeContents` for getting the size of the
content of a box without the headers.
- encoder API: implemented new api functions for streaming encoding.
### Changed / clarified
- decoder/encoder API: return failure when surface allocation fail
- encoder API / cjxl: updated modular effort levels to faster settings; the
effort range is now 1-10, with 11 available in advanced mode.
## [0.9.2] - 2024-02-07
### Fixed
- bugs in the gdk-pixbuf plugin
- some build issues
## [0.9.1] - 2024-01-08
### Fixed
- multiple build issues
## [0.9.0] - 2023-12-22
### Added
- encoder API: add `JxlEncoderSetExtraChannelDistance` to adjust the quality
of extra channels (like alpha) separately.
- encoder API: new api functions for streaming encoding:
- `JxlEncoderSetOutputProcessor`
- `JxlEncoderFlushInput`
- `JxlEncoderOutputProcessor` struct
- `JxlEncoderSetOutputCallback`
- `JxlChunkedFrameInputSource` struct
- `JxlEncoderAddChunkedFrame`
- encoder API: new options for more fine-grained control over metadata
preservation when using `JxlEncoderAddJPEGFrame`:
- `JXL_ENC_FRAME_SETTING_JPEG_KEEP_EXIF`
- `JXL_ENC_FRAME_SETTING_JPEG_KEEP_XMP`
- `JXL_ENC_FRAME_SETTING_JPEG_KEEP_JUMBF`
- encoder API: new function `JxlEncoderSetUpsamplingMode` to change the upsampling
method, e.g. to use nearest-neighbor upsampling for pixel art
- decoder API: implemented `JxlDecoderSetOutputColorProfile` and
`JxlDecoderSetCms` to enable decoding to desired colorspace.
- cjxl can now be used to explicitly add/update/strip Exif/XMP/JUMBF metadata using
the decoder-hints syntax, e.g. `cjxl input.ppm -x exif=input.exif output.jxl`
- djxl can now be used to extract Exif/XMP/JUMBF metadata
- encoder API: new function `JxlEncoderDistanceFromQuality` for convenience to
calculate a `distance` given a `quality`
### Removed
- API: the Butteraugli API (`jxl/butteraugli.h`) was removed.
- encoder and decoder API: all deprecated functions were removed:
`JxlDecoderDefaultPixelFormat`, `JxlEncoderOptionsSetLossless`,
`JxlEncoderOptionsSetEffort`, `JxlEncoderOptionsSetDecodingSpeed`,
`JxlEncoderOptionsSetDistance`, `JxlEncoderOptionsCreate`, as well as
the deprecated enumerator values `JXL_DEC_EXTENSIONS`, `JXL_ENC_NOT_SUPPORTED`,
`JXL_TYPE_BOOLEAN`, `JXL_TYPE_UINT32`, and deprecated type `JxlEncoderOptions`.
- decoder API: the signature of `JxlDecoderGetColorAsEncodedProfile`,
`JxlDecoderGetICCProfileSize`, and `JxlDecoderGetColorAsICCProfile`
changed: a deprecated unused argument was removed.
### Changed / clarified
- changed the name of the cjxl flag `photon_noise` to `photon_noise_iso`
- fixed how large boxes are decoded (#2958)
- fixed encoding files with unreadable patches (#3042, #3046)
## [0.8.2] - 2023-06-14
### Changed
- Security: Fix an integer underflow bug in patch decoding (#2551- CVE-2023-35790).
## [0.8.1] - 2023-02-03
### Changed
- Allow fast-lossless for 16-bit float input (#2093)
- Fix bug in palette (#2120)
- Security: Fix OOB read in exif.h (#2101 - [CVE-2023-0645](https://www.cve.org/cverecord?id=CVE-2023-0645))
## [0.8.0] - 2023-01-18
### Added
- decoder API: new function `JxlDecoderSetImageBitDepth` to set the bit depth
of the output buffer.
- decoder API proposal: add `JxlDecoderSetOutputColorProfile` and
`JxlDecoderSetCms` to enable decoding to desired colorspace; NB: not
implemented yet.
- encoder API: new function `JxlEncoderSetFrameBitDepth` to set the bit depth
of the input buffer.
- encoder API: add an effort 10 option for lossless compression; using this
setting requires calling `JxlEncoderAllowExpertOptions`.
- encoder API: new `JXL_ENC_FRAME_SETTING_JPEG_COMPRESS_BOXES` enum value to
allow explicit control of metadata compression
### Removed
- common API: removed `JxlIntrinsicSizeHeader`
- decoder API: removed deprecated `JXL_DEC_NEED_DC_OUT_BUFFER` and
`JXL_DEC_DC_IMAGE` events, `JxlDecoderDCOutBufferSize` and
`JxlDecoderSetDCOutBuffer` functions
### Changed / clarified
- encoder API: `JxlEncoderProcessOutput` requires at least 32 bytes of output
space to proceed and guarantees that at least one byte will be written
## [0.7] - 2022-07-21 ## [0.7] - 2022-07-21

View file

@ -3,44 +3,28 @@
# Use of this source code is governed by a BSD-style # Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file. # license that can be found in the LICENSE file.
# Ubuntu bionic ships with cmake 3.10. # Ubuntu focal ships with cmake 3.16.
cmake_minimum_required(VERSION 3.10) cmake_minimum_required(VERSION 3.16...3.27)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
# Honor VISIBILITY_INLINES_HIDDEN on all types of targets.
if(POLICY CMP0063)
cmake_policy(SET CMP0063 NEW)
endif()
# Pass CMAKE_EXE_LINKER_FLAGS to CC and CXX compilers when testing if they work.
if(POLICY CMP0065)
cmake_policy(SET CMP0065 NEW)
endif()
# Set PIE flags for POSITION_INDEPENDENT_CODE targets, added in 3.14.
if(POLICY CMP0083)
cmake_policy(SET CMP0083 NEW)
endif()
project(LIBJXL LANGUAGES C CXX) project(LIBJXL LANGUAGES C CXX)
include(CheckCXXSourceCompiles) # TODO(sboukortt): remove once oss-fuzz passes -DBUILD_SHARED_LIBS=OFF
check_cxx_source_compiles( if(JPEGXL_ENABLE_FUZZERS)
"int main() { message(STATUS "Fuzzer build detected, building static libs")
#if !defined(__EMSCRIPTEN__) set(BUILD_SHARED_LIBS OFF)
static_assert(false, \"__EMSCRIPTEN__ is not defined\"); endif()
#endif
return 0;
}"
JPEGXL_EMSCRIPTEN
)
message(STATUS "CMAKE_SYSTEM_PROCESSOR is ${CMAKE_SYSTEM_PROCESSOR}") message(STATUS "CMAKE_SYSTEM_PROCESSOR is ${CMAKE_SYSTEM_PROCESSOR}")
include(CheckCXXCompilerFlag) include(CheckCXXCompilerFlag)
check_cxx_compiler_flag("-fsanitize=fuzzer-no-link" CXX_FUZZERS_SUPPORTED) check_cxx_compiler_flag("-fsanitize=fuzzer-no-link" CXX_FUZZERS_SUPPORTED)
check_cxx_compiler_flag("-Xclang -mconstructor-aliases" CXX_CONSTRUCTOR_ALIASES_SUPPORTED)
check_cxx_compiler_flag("-fmacro-prefix-map=OLD=NEW" CXX_MACRO_PREFIX_MAP) check_cxx_compiler_flag("-fmacro-prefix-map=OLD=NEW" CXX_MACRO_PREFIX_MAP)
check_cxx_compiler_flag("-fno-rtti" CXX_NO_RTTI_SUPPORTED) 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. # Enabled PIE binaries by default if supported.
include(CheckPIESupported OPTIONAL RESULT_VARIABLE CHECK_PIE_SUPPORTED) include(CheckPIESupported OPTIONAL RESULT_VARIABLE CHECK_PIE_SUPPORTED)
if(CHECK_PIE_SUPPORTED) if(CHECK_PIE_SUPPORTED)
@ -50,6 +34,19 @@ if(CHECK_PIE_SUPPORTED)
endif() endif()
endif() endif()
if(PROVISION_DEPENDENCIES)
# Run script to provision dependencies.
find_program (BASH_PROGRAM bash)
if(BASH_PROGRAM)
execute_process(
COMMAND ${BASH_PROGRAM} ${CMAKE_CURRENT_SOURCE_DIR}/deps.sh
RESULT_VARIABLE PROVISION_DEPENDENCIES_RESULT)
endif()
if(NOT PROVISION_DEPENDENCIES_RESULT EQUAL "0")
message(FATAL_ERROR "${CMAKE_CURRENT_SOURCE_DIR}/deps.sh failed with ${PROVISION_DEPENDENCIES_RESULT}")
endif()
endif()
### Project build options: ### Project build options:
if(CXX_FUZZERS_SUPPORTED) if(CXX_FUZZERS_SUPPORTED)
# Enabled by default except on arm64, Windows and Apple builds. # Enabled by default except on arm64, Windows and Apple builds.
@ -82,14 +79,29 @@ check_cxx_source_compiles(
JXL_HWY_DISABLED_TARGETS_FORCED JXL_HWY_DISABLED_TARGETS_FORCED
) )
set(WARNINGS_AS_ERRORS_DEFAULT false) if((SANITIZER STREQUAL "msan") OR EMSCRIPTEN)
if((SANITIZER STREQUAL "msan") OR JPEGXL_EMSCRIPTEN)
set(BUNDLE_LIBPNG_DEFAULT YES) set(BUNDLE_LIBPNG_DEFAULT YES)
else() else()
set(BUNDLE_LIBPNG_DEFAULT NO) set(BUNDLE_LIBPNG_DEFAULT NO)
endif() endif()
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. # Standard cmake naming for building shared libraries.
get_property(SHARED_LIBS_SUPPORTED GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS) get_property(SHARED_LIBS_SUPPORTED GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS)
option(BUILD_SHARED_LIBS "Build shared libraries instead of static ones" ${SHARED_LIBS_SUPPORTED}) option(BUILD_SHARED_LIBS "Build shared libraries instead of static ones" ${SHARED_LIBS_SUPPORTED})
@ -100,6 +112,16 @@ set(JPEGXL_ENABLE_DEVTOOLS false CACHE BOOL
"Build JPEGXL developer tools.") "Build JPEGXL developer tools.")
set(JPEGXL_ENABLE_TOOLS true CACHE BOOL set(JPEGXL_ENABLE_TOOLS true CACHE BOOL
"Build JPEGXL user tools: cjxl and djxl.") "Build JPEGXL user tools: cjxl and djxl.")
set(JPEGXL_ENABLE_JPEGLI ${ENABLE_JPEGLI_DEFAULT} CACHE BOOL
"Build jpegli library.")
set(JPEGXL_ENABLE_JPEGLI_LIBJPEG true CACHE BOOL
"Build libjpeg.so shared library based on jpegli.")
set(JPEGXL_INSTALL_JPEGLI_LIBJPEG false CACHE BOOL
"Install jpegli version of libjpeg.so system-wide.")
set(JPEGLI_LIBJPEG_LIBRARY_VERSION "62.3.0" CACHE STRING
"Library version of the libjpeg.so shared library that we build.")
set(JPEGLI_LIBJPEG_LIBRARY_SOVERSION "62" CACHE STRING
"Library so-version of the libjpeg.so shared library that we build.")
set(JPEGXL_ENABLE_DOXYGEN true CACHE BOOL set(JPEGXL_ENABLE_DOXYGEN true CACHE BOOL
"Generate C API documentation using Doxygen.") "Generate C API documentation using Doxygen.")
set(JPEGXL_ENABLE_MANPAGES true CACHE BOOL set(JPEGXL_ENABLE_MANPAGES true CACHE BOOL
@ -116,10 +138,8 @@ set(JPEGXL_ENABLE_SJPEG true CACHE BOOL
"Build JPEGXL with support for encoding with sjpeg.") "Build JPEGXL with support for encoding with sjpeg.")
set(JPEGXL_ENABLE_OPENEXR true CACHE BOOL set(JPEGXL_ENABLE_OPENEXR true CACHE BOOL
"Build JPEGXL with support for OpenEXR if available.") "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.") "Build with skcms instead of lcms2.")
set(JPEGXL_BUNDLE_SKCMS true CACHE BOOL
"When building with skcms, bundle it into libjxl.a.")
set(JPEGXL_ENABLE_VIEWERS false CACHE BOOL set(JPEGXL_ENABLE_VIEWERS false CACHE BOOL
"Build JPEGXL viewer tools for evaluation.") "Build JPEGXL viewer tools for evaluation.")
set(JPEGXL_ENABLE_TCMALLOC ${ENABLE_TCMALLOC_DEFAULT} CACHE BOOL set(JPEGXL_ENABLE_TCMALLOC ${ENABLE_TCMALLOC_DEFAULT} CACHE BOOL
@ -128,29 +148,40 @@ set(JPEGXL_ENABLE_PLUGINS false CACHE BOOL
"Build third-party plugins to support JPEG XL in other applications.") "Build third-party plugins to support JPEG XL in other applications.")
set(JPEGXL_ENABLE_COVERAGE false CACHE BOOL set(JPEGXL_ENABLE_COVERAGE false CACHE BOOL
"Enable code coverage tracking for libjxl. This also enables debug and disables optimizations.") "Enable code coverage tracking for libjxl. This also enables debug and disables optimizations.")
set(JPEGXL_ENABLE_PROFILER false CACHE BOOL
"Builds in support for profiling (printed by tools if extra flags given)")
set(JPEGXL_ENABLE_SIZELESS_VECTORS false CACHE BOOL set(JPEGXL_ENABLE_SIZELESS_VECTORS false CACHE BOOL
"Builds in support for SVE/RVV vectorization") "Builds in support for SVE/RVV vectorization")
set(JPEGXL_ENABLE_TRANSCODE_JPEG true CACHE BOOL set(JPEGXL_ENABLE_TRANSCODE_JPEG true CACHE BOOL
"Builds in support for decoding transcoded JXL files back to JPEG,\ "Builds in support for decoding transcoded JXL files back to JPEG,\
disabling it makes the decoder reject JXL_DEC_JPEG_RECONSTRUCTION events,\ disabling it makes the decoder reject JXL_DEC_JPEG_RECONSTRUCTION events,\
(default enabled)") (default enabled)")
set(JPEGXL_ENABLE_BOXES true CACHE BOOL
"Builds in support for decoding boxes in JXL files,\
disabling it makes the decoder reject JXL_DEC_BOX events,\
(default enabled)")
set(JPEGXL_STATIC false CACHE BOOL set(JPEGXL_STATIC false CACHE BOOL
"Build tools as static binaries.") "Build tools as static binaries.")
set(JPEGXL_WARNINGS_AS_ERRORS ${WARNINGS_AS_ERRORS_DEFAULT} CACHE BOOL set(JPEGXL_WARNINGS_AS_ERRORS false CACHE BOOL
"Treat warnings as errors during compilation.") "Treat warnings as errors during compilation.")
set(JPEGXL_DEP_LICENSE_DIR "" CACHE STRING set(JPEGXL_DEP_LICENSE_DIR "" CACHE STRING
"Directory where to search for system dependencies \"copyright\" files.") "Directory where to search for system dependencies \"copyright\" files.")
set(JPEGXL_FORCE_NEON false CACHE BOOL set(JPEGXL_FORCE_NEON false CACHE BOOL
"Set flags to enable NEON in arm if not enabled by your toolchain.") "Set flags to enable NEON in arm if not enabled by your toolchain.")
set(JPEGXL_TEST_TOOLS false CACHE BOOL
"Run scripts that test the encoding / decoding tools.")
set(JPEGXL_ENABLE_AVX512 false CACHE BOOL
"Build with AVX512 support (faster on CPUs that support it, but larger binary size).")
set(JPEGXL_ENABLE_AVX512_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_THREADS true CACHE BOOL
"Builds WASM modules with threads support")
# Force system dependencies. # Force system dependencies.
set(JPEGXL_FORCE_SYSTEM_BROTLI false CACHE BOOL set(JPEGXL_FORCE_SYSTEM_BROTLI false CACHE BOOL
"Force using system installed brotli instead of third_party/brotli source.") "Force using system installed brotli instead of third_party/brotli source.")
set(JPEGXL_FORCE_SYSTEM_GTEST false CACHE BOOL 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 set(JPEGXL_FORCE_SYSTEM_LCMS2 false CACHE BOOL
"Force using system installed lcms2 instead of third_party/lcms source.") "Force using system installed lcms2 instead of third_party/lcms source.")
set(JPEGXL_FORCE_SYSTEM_HWY false CACHE BOOL set(JPEGXL_FORCE_SYSTEM_HWY false CACHE BOOL
@ -162,37 +193,49 @@ if (NOT CMAKE_C_COMPILER_ID STREQUAL CMAKE_CXX_COMPILER_ID)
message(FATAL_ERROR "Different C/C++ compilers set: " message(FATAL_ERROR "Different C/C++ compilers set: "
"${CMAKE_C_COMPILER_ID} vs ${CMAKE_CXX_COMPILER_ID}") "${CMAKE_C_COMPILER_ID} vs ${CMAKE_CXX_COMPILER_ID}")
endif() endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
# Android NDK's toolchain.cmake fakes the clang version in
# CMAKE_CXX_COMPILER_VERSION with an incorrect number, so ignore this.
if (NOT CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION MATCHES "clang"
AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5)
message(FATAL_ERROR
"Minimum Clang version required is Clang 5, please update.")
endif()
elseif (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7)
message(FATAL_ERROR
"Minimum GCC version required is 7, please update.")
endif()
endif()
message(STATUS message(STATUS
"Compiled IDs C:${CMAKE_C_COMPILER_ID}, C++:${CMAKE_CXX_COMPILER_ID}") "Compiled IDs C:${CMAKE_C_COMPILER_ID}, C++:${CMAKE_CXX_COMPILER_ID}")
set(JXL_HWY_INCLUDE_DIRS "$<BUILD_INTERFACE:$<TARGET_PROPERTY:$<IF:$<TARGET_EXISTS:hwy::hwy>,hwy::hwy,hwy>,INTERFACE_INCLUDE_DIRECTORIES>>")
# Always disable SSSE3 since it is rare to have SSSE3 but not SSE4
set(HWY_DISABLED_TARGETS "HWY_SSSE3")
if (NOT JPEGXL_ENABLE_AVX512)
message(STATUS "Disabled AVX512 (set JPEGXL_ENABLE_AVX512 to enable it)")
set(HWY_DISABLED_TARGETS "${HWY_DISABLED_TARGETS}|HWY_AVX3")
add_definitions(-DFJXL_ENABLE_AVX512=0)
endif()
if (NOT JPEGXL_ENABLE_AVX512_SPR)
message(STATUS "Disabled AVX512_SPR (set JPEGXL_ENABLE_AVX512_SPR to enable it)")
set(HWY_DISABLED_TARGETS "${HWY_DISABLED_TARGETS}|HWY_AVX3_SPR")
endif()
if (NOT JPEGXL_ENABLE_AVX512_ZEN4)
message(STATUS "Disabled AVX512_ZEN4 (set JPEGXL_ENABLE_AVX512_ZEN4 to enable it)")
set(HWY_DISABLED_TARGETS "${HWY_DISABLED_TARGETS}|HWY_AVX3_ZEN4")
endif()
# CMAKE_EXPORT_COMPILE_COMMANDS is used to generate the compilation database # CMAKE_EXPORT_COMPILE_COMMANDS is used to generate the compilation database
# used by clang-tidy. # used by clang-tidy.
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
if(JPEGXL_STATIC) if(JPEGXL_STATIC)
set(BUILD_SHARED_LIBS 0) 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 "$<$<NOT:$<CONFIG:Debug>>:MultiThreaded>" CACHE STRING "")
# Clang developers say that in case to use "static" we have to build stdlib # 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", # ourselves; for real use case we don't care about stdlib, as it is "granted",
# so just linking all other libraries is fine. # 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_FIND_LIBRARY_SUFFIXES .a)
set(CMAKE_EXE_LINKER_FLAGS string(APPEND CMAKE_EXE_LINKER_FLAGS " -static-libgcc -static-libstdc++")
"${CMAKE_EXE_LINKER_FLAGS} -static -static-libgcc -static-libstdc++")
endif() endif()
endif() # JPEGXL_STATIC endif() # JPEGXL_STATIC
@ -202,7 +245,16 @@ find_package(Threads REQUIRED)
# These settings are important to drive check_cxx_source_compiles # These settings are important to drive check_cxx_source_compiles
# See CMP0067 (min cmake version is 3.10 anyway) # See CMP0067 (min cmake version is 3.10 anyway)
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) set(CMAKE_CXX_STANDARD 11)
endif()
endif()
set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED YES) set(CMAKE_CXX_STANDARD_REQUIRED YES)
@ -243,7 +295,7 @@ if(JPEGXL_STATIC)
endif() endif()
endif() # JPEGXL_STATIC endif() # JPEGXL_STATIC
if (JPEGXL_EMSCRIPTEN) if (EMSCRIPTEN AND JPEGXL_ENABLE_WASM_THREADS)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread")
@ -257,10 +309,14 @@ if (CXX_NO_RTTI_SUPPORTED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
endif() endif()
# Internal flags for coverage builds:
set(JPEGXL_COVERAGE_FLAGS)
set(JPEGXL_COVERAGE_LINK_FLAGS)
if (MSVC) if (MSVC)
# TODO(janwas): add flags # TODO(janwas): add flags
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
else () else ()
# Global compiler flags for all targets here and in subdirectories. # Global compiler flags for all targets here and in subdirectories.
add_definitions( add_definitions(
# Avoid changing the binary based on the current time and date. # Avoid changing the binary based on the current time and date.
@ -269,34 +325,27 @@ add_definitions(
-D__TIME__="redacted" -D__TIME__="redacted"
) )
# Avoid log spam from fopen etc.
if(MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
endif()
# TODO(eustas): JXL currently compiles, but does not pass tests... # TODO(eustas): JXL currently compiles, but does not pass tests...
if (NOT JXL_HWY_DISABLED_TARGETS_FORCED AND NOT JPEGXL_ENABLE_SIZELESS_VECTORS) if (NOT JXL_HWY_DISABLED_TARGETS_FORCED)
add_definitions(-DHWY_DISABLED_TARGETS=\(HWY_SVE|HWY_SVE2|HWY_SVE_256|HWY_SVE2_128|HWY_RVV\)) if (NOT JPEGXL_ENABLE_SIZELESS_VECTORS)
message("Warning: HWY_SVE, HWY_SVE2, HWY_SVE_256, HWY_SVE2_128 and HWY_RVV CPU targets are disabled") set(HWY_DISABLED_TARGETS "${HWY_DISABLED_TARGETS}|HWY_SVE|HWY_SVE2|HWY_SVE_256|HWY_SVE2_128|HWY_RVV")
endif()
add_compile_options($<$<NOT:$<COMPILE_LANGUAGE:RC>>:-DHWY_DISABLED_TARGETS=\(${HWY_DISABLED_TARGETS}\)>)
endif() endif()
# In CMake before 3.12 it is problematic to pass repeated flags like -Xclang.
# For this reason we place them in CMAKE_CXX_FLAGS instead.
# See https://gitlab.kitware.com/cmake/cmake/issues/15826
# Machine flags. # Machine flags.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -funwind-tables") add_compile_options(-funwind-tables)
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Xclang -mrelax-all") add_compile_options("SHELL:-Xclang -mrelax-all")
endif() endif()
if (CXX_CONSTRUCTOR_ALIASES_SUPPORTED) if (CXX_CONSTRUCTOR_ALIASES_SUPPORTED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Xclang -mconstructor-aliases") add_compile_options("SHELL:-Xclang -mconstructor-aliases")
endif() endif()
if(WIN32) if(WIN32)
# Not supported by clang-cl, but frame pointers are default on Windows # Not supported by clang-cl, but frame pointers are default on Windows
else() else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-omit-frame-pointer") add_compile_options(-fno-omit-frame-pointer)
endif() endif()
# CPU flags - remove once we have NEON dynamic dispatch # CPU flags - remove once we have NEON dynamic dispatch
@ -305,14 +354,10 @@ endif()
if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm") if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm")
if(JPEGXL_FORCE_NEON) if(JPEGXL_FORCE_NEON)
# GCC requires these flags, otherwise __ARM_NEON is undefined. # GCC requires these flags, otherwise __ARM_NEON is undefined.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} \ add_compile_options(-mfpu=neon-vfpv4 -mfloat-abi=hard)
-mfpu=neon-vfpv4 -mfloat-abi=hard")
endif() endif()
endif() endif()
# Force build with optimizations in release mode.
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2")
add_compile_options( add_compile_options(
# Ignore this to allow redefining __DATE__ and others. # Ignore this to allow redefining __DATE__ and others.
-Wno-builtin-macro-redefined -Wno-builtin-macro-redefined
@ -324,6 +369,15 @@ add_compile_options(
if (JPEGXL_WARNINGS_AS_ERRORS) if (JPEGXL_WARNINGS_AS_ERRORS)
add_compile_options(-Werror) add_compile_options(-Werror)
endif () endif ()
if(JPEGXL_ENABLE_COVERAGE)
set(JPEGXL_COVERAGE_FLAGS
-g -O0 -fprofile-arcs -ftest-coverage
)
set(JPEGXL_COVERAGE_LINK_FLAGS
--coverage
)
endif() # JPEGXL_ENABLE_COVERAGE
endif () # !MSVC endif () # !MSVC
include(GNUInstallDirs) include(GNUInstallDirs)
@ -364,7 +418,6 @@ if(DOXYGEN_FOUND)
set(DOXYGEN_GENERATE_HTML "YES") set(DOXYGEN_GENERATE_HTML "YES")
set(DOXYGEN_GENERATE_XML "YES") set(DOXYGEN_GENERATE_XML "YES")
set(DOXYGEN_STRIP_FROM_PATH "${CMAKE_CURRENT_SOURCE_DIR}/lib/include") set(DOXYGEN_STRIP_FROM_PATH "${CMAKE_CURRENT_SOURCE_DIR}/lib/include")
set(DOXYGEN_USE_MDFILE_AS_MAINPAGE "README.md")
if(JPEGXL_WARNINGS_AS_ERRORS) if(JPEGXL_WARNINGS_AS_ERRORS)
set(DOXYGEN_WARN_AS_ERROR "YES") set(DOXYGEN_WARN_AS_ERROR "YES")
endif() endif()
@ -407,7 +460,7 @@ if(JPEGXL_ENABLE_MANPAGES)
find_program(ASCIIDOC a2x) find_program(ASCIIDOC a2x)
if(ASCIIDOC) if(ASCIIDOC)
file(STRINGS "${ASCIIDOC}" ASCIIDOC_SHEBANG LIMIT_COUNT 1) file(STRINGS "${ASCIIDOC}" ASCIIDOC_SHEBANG LIMIT_COUNT 1)
if(ASCIIDOC_SHEBANG MATCHES "/sh|/bash") if(ASCIIDOC_SHEBANG MATCHES "sh$" OR ASCIIDOC_SHEBANG MATCHES "libexec/bin/python$" OR MINGW)
set(ASCIIDOC_PY_FOUND ON) set(ASCIIDOC_PY_FOUND ON)
# Run the program directly and set ASCIIDOC as empty. # Run the program directly and set ASCIIDOC as empty.
set(ASCIIDOC_PY "${ASCIIDOC}") set(ASCIIDOC_PY "${ASCIIDOC}")
@ -470,3 +523,25 @@ endif ()
# Binary tools # Binary tools
add_subdirectory(tools) add_subdirectory(tools)
macro(list_test_targets out dir)
get_property(dir_targets DIRECTORY ${dir} PROPERTY BUILDSYSTEM_TARGETS)
foreach(target ${dir_targets})
if (target MATCHES ".*_test")
list(APPEND ${out} ${target})
endif()
endforeach()
get_property(subdirectories DIRECTORY ${dir} PROPERTY SUBDIRECTORIES)
foreach(subdir ${subdirectories})
list_test_targets(${out} ${subdir})
endforeach()
endmacro()
set(all_tests_list)
list_test_targets(all_tests_list ${CMAKE_CURRENT_SOURCE_DIR})
if(all_tests_list)
add_custom_target(all_tests)
add_dependencies(all_tests ${all_tests_list})
endif()

View file

@ -75,7 +75,9 @@ information on using pull requests.
functionality. Reviewers may ask you to split a Pull Request and it is functionality. Reviewers may ask you to split a Pull Request and it is
easier to create a smaller change from the beginning. easier to create a smaller change from the beginning.
* Describe your commits. Add a meaningful description to your commit message, explain what you are changing if it is not trivially obvious, but more importantly explain *why* you are making those changes. For example "Fix * Describe your commits. Add a meaningful description to your commit message,
explain what you are changing if it is not trivially obvious, but more
importantly explain *why* you are making those changes. For example "Fix
build" is not a good commit message, describe what build and if it makes sense build" is not a good commit message, describe what build and if it makes sense
why is this fixing it or why was it failing without this. It is very likely why is this fixing it or why was it failing without this. It is very likely
that people far in the future without any context you have right now will be that people far in the future without any context you have right now will be
@ -113,8 +115,7 @@ information on using pull requests.
* Sign the CLA (only needed once per user, see above). * Sign the CLA (only needed once per user, see above).
* AUTHORS: If this is your first contribution, add your name or your * AUTHORS: You can add your name to the [AUTHORS](AUTHORS) file.
company name to the [AUTHORS](AUTHORS) file for copyright tracking purposes.
* Style guide. Check `./ci.sh lint`. * Style guide. Check `./ci.sh lint`.

View file

@ -0,0 +1,12 @@
# 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 = "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")

132
media/libjxl/src/MODULE.bazel.lock generated Normal file
View file

@ -0,0 +1,132 @@
{
"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~//crosstool:setup.bzl%apple_cc_configure_extension": {
"general": {
"bzlTransitiveDigest": "PjIds3feoYE8SGbbIq2SFTZy3zmxeO2tQevJZNDo7iY=",
"usagesDigest": "aLmqbvowmHkkBPve05yyDNGN7oh7QE9kBADr3QIZTZs=",
"recordedFileInputs": {},
"recordedDirentsInputs": {},
"envVariables": {},
"generatedRepoSpecs": {
"local_config_apple_cc": {
"bzlFile": "@@apple_support~//crosstool:setup.bzl",
"ruleClassName": "_apple_cc_autoconf",
"attributes": {}
},
"local_config_apple_cc_toolchains": {
"bzlFile": "@@apple_support~//crosstool:setup.bzl",
"ruleClassName": "_apple_cc_autoconf_toolchains",
"attributes": {}
}
},
"recordedRepoMappingEntries": [
[
"apple_support~",
"bazel_tools",
"bazel_tools"
]
]
}
},
"@@platforms//host:extension.bzl%host_platform": {
"general": {
"bzlTransitiveDigest": "xelQcPZH8+tmuOHVjL9vDxMnnQNMlwj0SlvgoqBkm4U=",
"usagesDigest": "meSzxn3DUCcYEhq4HQwExWkWtU4EjriRBQLsZN+Q0SU=",
"recordedFileInputs": {},
"recordedDirentsInputs": {},
"envVariables": {},
"generatedRepoSpecs": {
"host_platform": {
"bzlFile": "@@platforms//host:extension.bzl",
"ruleClassName": "host_platform_repo",
"attributes": {}
}
},
"recordedRepoMappingEntries": []
}
}
}
}

View file

@ -1,20 +0,0 @@
## Disclaimer
Haiku builds are not officially supported, i.e. the build might not work at all,
some tests may fail and some sub-projects are excluded from build.
This manual outlines Haiku-specific setup. For general building and testing
instructions see "[README](README.md)" and
"[Building and Testing changes](doc/building_and_testing.md)".
## Dependencies
```shell
pkgman install llvm9_clang ninja cmake doxygen libjpeg_turbo_devel giflib_devel
```
## Building
```shell
TEST_STACK_LIMIT=none CMAKE_FLAGS="-I/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/8.3.0/include/c++ -I/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/8.3.0/include/c++/x86_64-unknown-haiku" CMAKE_SHARED_LINKER_FLAGS="-shared -Xlinker -soname=libjpegxl.so -lpthread" ./ci.sh opt
```

View file

@ -1,41 +0,0 @@
## Disclaimer
OSX builds have "best effort" support, i.e. build might not work at all, some
tests may fail and some sub-projects are excluded from build.
This manual outlines OSX specific setup. For general building and testing
instructions see "[README](README.md)" and
"[Building and Testing changes](doc/building_and_testing.md)".
[Homebrew](https://brew.sh/) is a popular package manager. JPEG XL library and
binaries could be installed using it:
```bash
brew install jpeg-xl
```
## Dependencies
Make sure that `brew doctor` does not report serious problems and up-to-date
version of XCode is installed.
Installing (actually, building) `clang` might take a couple hours.
```bash
brew install llvm
```
```bash
brew install coreutils cmake giflib jpeg-turbo libpng ninja zlib
```
Before building the project check that `which clang` is
`/usr/local/opt/llvm/bin/clang`, not the one provided by XCode. If not, update
`PATH` environment variable.
Also, setting `CMAKE_PREFIX_PATH` might be necessary for correct include paths
resolving, e.g.:
```bash
export CMAKE_PREFIX_PATH=`brew --prefix giflib`:`brew --prefix jpeg-turbo`:`brew --prefix libpng`:`brew --prefix zlib`
```

View file

@ -12,6 +12,10 @@ https://github.com/libjxl/libjxl/actions/workflows/fuzz.yml)
https://github.com/libjxl/libjxl/actions/workflows/release.yaml) https://github.com/libjxl/libjxl/actions/workflows/release.yaml)
[![Doc](https://readthedocs.org/projects/libjxl/badge/?version=latest)]( [![Doc](https://readthedocs.org/projects/libjxl/badge/?version=latest)](
https://libjxl.readthedocs.io/en/latest/?badge=latest) https://libjxl.readthedocs.io/en/latest/?badge=latest)
[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/7845/badge)](
https://www.bestpractices.dev/projects/7845)
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/libjxl/libjxl/badge)](
https://securityscorecards.dev/viewer/?uri=github.com/libjxl/libjxl)
[![codecov](https://codecov.io/gh/libjxl/libjxl/branch/main/graph/badge.svg)]( [![codecov](https://codecov.io/gh/libjxl/libjxl/branch/main/graph/badge.svg)](
https://codecov.io/gh/libjxl/libjxl) https://codecov.io/gh/libjxl/libjxl)
@ -21,109 +25,62 @@ This repository contains a reference implementation of JPEG XL (encoder and
decoder), called `libjxl`. This software library is decoder), called `libjxl`. This software library is
[used by many applications that support JPEG XL](doc/software_support.md). [used by many applications that support JPEG XL](doc/software_support.md).
JPEG XL is in the final stages of standardization and its codestream and file format JPEG XL was standardized in 2022 as [ISO/IEC 18181](https://jpeg.org/jpegxl/workplan.html).
are frozen. The [core codestream](doc/format_overview.md#codestream-features) is specified in 18181-1,
the [file format](doc/format_overview.md#file-format-features) in 18181-2.
[Decoder conformance](https://github.com/libjxl/conformance) is defined in 18181-3,
and 18181-4 is the [reference software](https://github.com/libjxl/libjxl).
The library API, command line options, and tools in this repository are subject The library API, command line options, and tools in this repository are subject
to change, however files encoded with `cjxl` conform to the JPEG XL format to change, however files encoded with `cjxl` conform to the JPEG XL specification
specification and can be decoded with current and future `djxl` decoders or and can be decoded with current and future `djxl` decoders or the `libjxl` decoding library.
`libjxl` decoding library.
## Quick start guide ## Installation
For more details and other workflows see the "Advanced guide" below. In most Linux distributions, installing `libjxl` is just a matter of using the package management system.
For example in Debian-based distributions: `apt install libjxl-tools` will install `cjxl` and `djxl`
and other tools like `benchmark_xl` are available in the package `libjxl-devtools`.
On MacOS, you can use [Homebrew](https://brew.sh/): `brew install jpeg-xl`.
### Checking out the code [![libjxl packaging status](https://repology.org/badge/vertical-allrepos/libjxl.svg?exclude_unsupported=1&columns=3&exclude_sources=modules,site&header=libjxl%20packaging%20status)](https://repology.org/project/libjxl/versions)
```bash From the [releases page](https://github.com/libjxl/libjxl/releases/) the following can be downloaded:
git clone https://github.com/libjxl/libjxl.git --recursive --shallow-submodules - Windows binaries
``` - Debian and Ubuntu .deb packages
This repository uses git submodules to handle some third party dependencies Of course you can also [build libjxl from sources](BUILDING.md).
under `third_party`, that's why is important to pass `--recursive`. If you
didn't check out with `--recursive`, or any submodule has changed, run:
```bash
git submodule update --init --recursive --depth 1 --recommend-shallow
```
The `--shallow-submodules` and `--depth 1 --recommend-shallow` options create ## Usage
shallow clones which only downloads the commits requested, and is all that is
needed to build `libjxl`. Should full clones be necessary, you could always run:
```bash
git submodule foreach git fetch --unshallow
git submodule update --init --recursive
```
which pulls the rest of the commits in the submodules.
Important: If you downloaded a zip file or tarball from the web interface you
won't get the needed submodules and the code will not compile. You can download
these external dependencies from source running `./deps.sh`. The git workflow
described above is recommended instead.
### Installing dependencies
Required dependencies for compiling the code, in a Debian/Ubuntu based
distribution run:
```bash
sudo apt install cmake pkg-config libbrotli-dev
```
Optional dependencies for supporting other formats in the `cjxl`/`djxl` tools,
in a Debian/Ubuntu based distribution run:
```bash
sudo apt install libgif-dev libjpeg-dev libopenexr-dev libpng-dev libwebp-dev
```
We recommend using a recent Clang compiler (version 7 or newer), for that
install clang and set `CC` and `CXX` variables.
```bash
sudo apt install clang
export CC=clang CXX=clang++
```
### Building
```bash
cd libjxl
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF ..
cmake --build . -- -j$(nproc)
```
The encoder/decoder tools will be available in the `build/tools` directory.
### <a name="installing"></a> Installing
```bash
sudo cmake --install .
```
### Basic encoder/decoder
To encode a source image to JPEG XL with default settings: To encode a source image to JPEG XL with default settings:
```bash ```bash
build/tools/cjxl input.png output.jxl cjxl input.png output.jxl
``` ```
For more settings run `build/tools/cjxl --help` or for a full list of options The desired visual fidelity can be selected using the `--distance` parameter
run `build/tools/cjxl -v -v --help`. (in units of just-noticeable difference, where 0 is lossless and the most useful lossy range is 0.5 .. 3.0),
or using `--quality` (on a scale from 0 to 100, roughly matching libjpeg).
The [encode effort](doc/encode_effort.md) can be selected using the `--effort` parameter.
For more settings run `cjxl --help` or for a full list of options
run `cjxl -v -v --help`.
To decode a JPEG XL file run: To decode a JPEG XL file run:
```bash ```bash
build/tools/djxl input.jxl output.png djxl input.jxl output.png
``` ```
When possible `cjxl`/`djxl` are able to read/write the following When possible, `cjxl`/`djxl` are able to read/write the following image formats:
image formats: .exr, .gif, .jpeg/.jpg, .pfm, .pgm/.ppm, .pgx, .png. 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`).
### Benchmarking ### Benchmarking
@ -135,26 +92,12 @@ benchmarking purposes.
For more comprehensive benchmarking options, see the For more comprehensive benchmarking options, see the
[benchmarking guide](doc/benchmarking.md). [benchmarking guide](doc/benchmarking.md).
## Advanced guide ### Library API
### Building with Docker Besides the `libjxl` library [API documentation](https://libjxl.readthedocs.io/en/latest/),
there are [example applications](examples/) and [plugins](plugins/) that can be used as a reference or
starting point for developers who wish to integrate `libjxl` in their project.
We build a common environment based on Debian/Ubuntu using Docker. Other
systems may have different combinations of versions and dependencies that
have not been tested and may not work. For those cases we recommend using the
Docker container as explained in the
[step by step guide](doc/developing_in_docker.md).
### Building JPEG XL for developers
For experienced developers, we provide build instructions for several other environments:
* [Building on Debian](doc/developing_in_debian.md)
* Building on Windows with [vcpkg](doc/developing_in_windows_vcpkg.md) (Visual Studio 2019)
* Building on Windows with [MSYS2](doc/developing_in_windows_msys.md)
* [Cross Compiling for Windows with Crossroad](doc/developing_with_crossroad.md)
If you encounter any difficulties, please use Docker instead.
## License ## License
@ -187,6 +130,7 @@ format: Cloudinary and Google.
* [Test coverage on Codecov.io](https://app.codecov.io/gh/libjxl/libjxl) - for * [Test coverage on Codecov.io](https://app.codecov.io/gh/libjxl/libjxl) - for
developers developers
* [libjxl documentation on readthedocs.io](https://libjxl.readthedocs.io/) * [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 ### Contact

View file

@ -0,0 +1,37 @@
# Copyright (c) the JPEG XL Project Authors. All rights reserved.
#
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
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",
)
local_repository(
name = "brotli",
path = "third_party/brotli",
)
new_local_repository(
name = "skcms",
build_file_content = """
cc_library(
name = "skcms",
srcs = [
"skcms.cc",
"src/skcms_internals.h",
"src/skcms_Transform.h",
"src/Transform_inl.h",
],
hdrs = ["skcms.h"],
visibility = ["//visibility:public"],
)
""",
path = "third_party/skcms",
)

View file

@ -7,7 +7,8 @@
# Tests implemented in bash. These typically will run checks about the source # Tests implemented in bash. These typically will run checks about the source
# code rather than the compiled one. # code rather than the compiled one.
MYDIR=$(dirname $(realpath "$0")) SELF=$(realpath "$0")
MYDIR=$(dirname "${SELF}")
set -u set -u
@ -18,15 +19,12 @@ test_includes() {
if [ ! -e "$f" ]; then if [ ! -e "$f" ]; then
continue continue
fi fi
# Check that the public files (in lib/include/ directory) don't use the full # Check that the full paths to the public headers are not used, since users
# path to the public header since users of the library will include the # of the library will include the library as: #include "jxl/foobar.h".
# library as: #include "jxl/foobar.h".
if [[ "${f#lib/include/}" != "${f}" ]]; then
if grep -i -H -n -E '#include\s*[<"]lib/include/jxl' "$f" >&2; then if grep -i -H -n -E '#include\s*[<"]lib/include/jxl' "$f" >&2; then
echo "Don't add \"include/\" to the include path of public headers." >&2 echo "Don't add \"include/\" to the include path of public headers." >&2
ret=1 ret=1
fi fi
fi
if [[ "${f#third_party/}" == "$f" ]]; then if [[ "${f#third_party/}" == "$f" ]]; then
# $f is not in third_party/ # $f is not in third_party/
@ -103,9 +101,9 @@ test_printf_size_t() {
ret=1 ret=1
fi fi
if grep -n -E 'gmock\.h' \ if grep -n -E '[^_]gtest\.h' \
$(git ls-files | grep -E '(\.c|\.cc|\.cpp|\.h)$' | grep -v -F /test_utils.h); then $(git ls-files | grep -E '(\.c|\.cc|\.cpp|\.h)$' | grep -v -F /testing.h); then
echo "Don't include gmock directly, instead include 'test_utils.h'. " >&2 echo "Don't include gtest directly, instead include 'testing.h'. " >&2
ret=1 ret=1
fi fi
@ -122,7 +120,7 @@ test_printf_size_t() {
fi fi
done done
for f in $(git ls-files | grep -E "\.h$" | grep -v -E '(printf_macros\.h|test_utils\.h)' | for f in $(git ls-files | grep -E "\.h$" | grep -v -E '(printf_macros\.h|testing\.h)' |
xargs grep -n 'PRI[udx]S'); do xargs grep -n 'PRI[udx]S'); do
# Having PRIuS / PRIdS in a header file means that printf_macros.h may # Having PRIuS / PRIdS in a header file means that printf_macros.h may
# be included before a system header, in particular before gtest headers. # be included before a system header, in particular before gtest headers.

View file

@ -5,23 +5,29 @@
# license that can be found in the LICENSE file. # license that can be found in the LICENSE file.
# Continuous integration helper module. This module is meant to be called from # Continuous integration helper module. This module is meant to be called from
# the .gitlab-ci.yml file during the continuous integration build, as well as # workflows during the continuous integration build, as well as from the
# from the command line for developers. # command line for developers.
set -eu set -eu
OS=`uname -s` OS=`uname -s`
MYDIR=$(dirname $(realpath "$0")) SELF=$(realpath "$0")
MYDIR=$(dirname "${SELF}")
### Environment parameters: ### Environment parameters:
TEST_STACK_LIMIT="${TEST_STACK_LIMIT:-256}" 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_BUILD_TYPE=${CMAKE_BUILD_TYPE:-RelWithDebInfo}
CMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH:-} CMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH:-}
CMAKE_C_COMPILER_LAUNCHER=${CMAKE_C_COMPILER_LAUNCHER:-} CMAKE_C_COMPILER_LAUNCHER=${CMAKE_C_COMPILER_LAUNCHER:-}
CMAKE_CXX_COMPILER_LAUNCHER=${CMAKE_CXX_COMPILER_LAUNCHER:-} CMAKE_CXX_COMPILER_LAUNCHER=${CMAKE_CXX_COMPILER_LAUNCHER:-}
CMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM:-} CMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM:-}
SKIP_BUILD="${SKIP_BUILD:-0}"
SKIP_TEST="${SKIP_TEST:-0}" SKIP_TEST="${SKIP_TEST:-0}"
FASTER_MSAN_BUILD="${FASTER_MSAN_BUILD:-0}"
TARGETS="${TARGETS:-all doc}"
TEST_SELECTOR="${TEST_SELECTOR:-}" TEST_SELECTOR="${TEST_SELECTOR:-}"
BUILD_TARGET="${BUILD_TARGET:-}" BUILD_TARGET="${BUILD_TARGET:-}"
ENABLE_WASM_SIMD="${ENABLE_WASM_SIMD:-0}" ENABLE_WASM_SIMD="${ENABLE_WASM_SIMD:-0}"
@ -32,6 +38,8 @@ else
fi fi
# Whether we should post a message in the MR when the build fails. # Whether we should post a message in the MR when the build fails.
POST_MESSAGE_ON_ERROR="${POST_MESSAGE_ON_ERROR:-1}" POST_MESSAGE_ON_ERROR="${POST_MESSAGE_ON_ERROR:-1}"
# By default, do a lightweight debian HWY package build.
HWY_PKG_OPTIONS="${HWY_PKG_OPTIONS:---set-envvar=HWY_EXTRA_CONFIG=-DBUILD_TESTING=OFF -DHWY_ENABLE_EXAMPLES=OFF -DHWY_ENABLE_CONTRIB=OFF}"
# Set default compilers to clang if not already set # Set default compilers to clang if not already set
export CC=${CC:-clang} export CC=${CC:-clang}
@ -69,13 +77,24 @@ if [[ "${ENABLE_WASM_SIMD}" -ne "0" ]]; then
CMAKE_EXE_LINKER_FLAGS="${CMAKE_EXE_LINKER_FLAGS} -msimd128" CMAKE_EXE_LINKER_FLAGS="${CMAKE_EXE_LINKER_FLAGS} -msimd128"
fi fi
if [[ "${ENABLE_WASM_SIMD}" -eq "2" ]]; then
CMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS} -DHWY_WANT_WASM2"
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 if [[ ! -z "${HWY_BASELINE_TARGETS}" ]]; then
CMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS} -DHWY_BASELINE_TARGETS=${HWY_BASELINE_TARGETS}" CMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS} -DHWY_BASELINE_TARGETS=${HWY_BASELINE_TARGETS}"
fi fi
# Version inferred from the CI variables. # Version inferred from the CI variables.
CI_COMMIT_SHA=${CI_COMMIT_SHA:-${GITHUB_SHA:-}} CI_COMMIT_SHA=${GITHUB_SHA:-}
JPEGXL_VERSION=${JPEGXL_VERSION:-${CI_COMMIT_SHA:0:8}} JPEGXL_VERSION=${JPEGXL_VERSION:-}
# Benchmark parameters # Benchmark parameters
STORE_IMAGES=${STORE_IMAGES:-1} STORE_IMAGES=${STORE_IMAGES:-1}
@ -118,17 +137,34 @@ if [[ "${BUILD_TARGET%%-*}" != "arm" ]]; then
) )
fi 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. # Default to "cat" if "colordiff" is not installed or if stdout is not a tty.
if [[ -t 1 ]]; then if [[ -t 1 ]]; then
COLORDIFF_BIN=$(which colordiff cat | head -n 1) COLORDIFF_BIN=$(which colordiff cat 2>/dev/null | head -n 1)
else else
COLORDIFF_BIN="cat" COLORDIFF_BIN="cat"
fi 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 # "false" will disable wine64 when not installed. This won't allow
# cross-compiling. # 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:-}" CLANG_VERSION="${CLANG_VERSION:-}"
# Detect the clang version suffix and store it in CLANG_VERSION. For example, # Detect the clang version suffix and store it in CLANG_VERSION. For example,
@ -139,6 +175,7 @@ detect_clang_version() {
fi fi
local clang_version=$("${CC:-clang}" --version | head -n1) local clang_version=$("${CC:-clang}" --version | head -n1)
clang_version=${clang_version#"Debian "} clang_version=${clang_version#"Debian "}
clang_version=${clang_version#"Ubuntu "}
local llvm_tag local llvm_tag
case "${clang_version}" in case "${clang_version}" in
"clang version 6."*) "clang version 6."*)
@ -171,27 +208,6 @@ on_exit() {
local retcode="$1" local retcode="$1"
# Always cleanup the CLEANUP_FILES. # Always cleanup the CLEANUP_FILES.
cleanup cleanup
# Post a message in the MR when requested with POST_MESSAGE_ON_ERROR but only
# if the run failed and we are not running from a MR pipeline.
if [[ ${retcode} -ne 0 && -n "${CI_BUILD_NAME:-}" &&
-n "${POST_MESSAGE_ON_ERROR}" && -z "${CI_MERGE_REQUEST_ID:-}" &&
"${CI_BUILD_REF_NAME}" = "master" ]]; then
load_mr_vars_from_commit
{ set +xeu; } 2>/dev/null
local message="**Run ${CI_BUILD_NAME} @ ${CI_COMMIT_SHORT_SHA} failed.**
Check the output of the job at ${CI_JOB_URL:-} to see if this was your problem.
If it was, please rollback this change or fix the problem ASAP, broken builds
slow down development. Check if the error already existed in the previous build
as well.
Pipeline: ${CI_PIPELINE_URL}
Previous build commit: ${CI_COMMIT_BEFORE_SHA}
"
cmd_post_mr_comment "${message}"
fi
} }
trap 'retcode=$?; { set +x; } 2>/dev/null; on_exit ${retcode}' INT TERM EXIT trap 'retcode=$?; { set +x; } 2>/dev/null; on_exit ${retcode}' INT TERM EXIT
@ -203,7 +219,7 @@ trap 'retcode=$?; { set +x; } 2>/dev/null; on_exit ${retcode}' INT TERM EXIT
# running from a merge request pipeline). # running from a merge request pipeline).
MR_HEAD_SHA="" MR_HEAD_SHA=""
# The common ancestor between the current commit and the tracked branch, such # The common ancestor between the current commit and the tracked branch, such
# as master. This includes a list # as main. This includes a list
MR_ANCESTOR_SHA="" MR_ANCESTOR_SHA=""
# Populate MR_HEAD_SHA and MR_ANCESTOR_SHA. # Populate MR_HEAD_SHA and MR_ANCESTOR_SHA.
@ -216,30 +232,23 @@ merge_request_commits() {
# changes on the Pull Request if needed. This fetches 10 more commits which # changes on the Pull Request if needed. This fetches 10 more commits which
# should be enough given that PR normally should have 1 commit. # should be enough given that PR normally should have 1 commit.
git -C "${MYDIR}" fetch -q origin "${GITHUB_SHA}" --depth 10 git -C "${MYDIR}" fetch -q origin "${GITHUB_SHA}" --depth 10
if [ "${GITHUB_EVENT_NAME}" = "pull_request" ]; then
MR_HEAD_SHA="$(git rev-parse "FETCH_HEAD^2" 2>/dev/null || MR_HEAD_SHA="$(git rev-parse "FETCH_HEAD^2" 2>/dev/null ||
echo "${GITHUB_SHA}")" echo "${GITHUB_SHA}")"
else else
# CI_BUILD_REF is the reference currently being build in the CI workflow. MR_HEAD_SHA="${GITHUB_SHA}"
MR_HEAD_SHA=$(git -C "${MYDIR}" rev-parse -q "${CI_BUILD_REF:-HEAD}") fi
else
MR_HEAD_SHA=$(git -C "${MYDIR}" rev-parse -q "HEAD")
fi fi
if [[ -n "${CI_MERGE_REQUEST_IID:-}" ]]; then if [[ -n "${GITHUB_BASE_REF:-}" ]]; then
# Merge request pipeline in CI. In this case the upstream is called "origin"
# but it refers to the forked project that's the source of the merge
# request. We need to get the target of the merge request, for which we need
# to query that repository using our CI_JOB_TOKEN.
echo "machine gitlab.com login gitlab-ci-token password ${CI_JOB_TOKEN}" \
>> "${HOME}/.netrc"
git -C "${MYDIR}" fetch "${CI_MERGE_REQUEST_PROJECT_URL}" \
"${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}"
MR_ANCESTOR_SHA=$(git -C "${MYDIR}" rev-parse -q FETCH_HEAD)
elif [[ -n "${GITHUB_BASE_REF:-}" ]]; then
# Pull request workflow in GitHub Actions. GitHub checkout action uses # Pull request workflow in GitHub Actions. GitHub checkout action uses
# "origin" as the remote for the git checkout. # "origin" as the remote for the git checkout.
git -C "${MYDIR}" fetch -q origin "${GITHUB_BASE_REF}" git -C "${MYDIR}" fetch -q origin "${GITHUB_BASE_REF}"
MR_ANCESTOR_SHA=$(git -C "${MYDIR}" rev-parse -q FETCH_HEAD) MR_ANCESTOR_SHA=$(git -C "${MYDIR}" rev-parse -q FETCH_HEAD)
else else
# We are in a local branch, not a merge request. # We are in a local branch, not a pull request workflow.
MR_ANCESTOR_SHA=$(git -C "${MYDIR}" rev-parse -q HEAD@{upstream} || true) MR_ANCESTOR_SHA=$(git -C "${MYDIR}" rev-parse -q HEAD@{upstream} || true)
fi fi
@ -258,40 +267,6 @@ merge_request_commits() {
set -x set -x
} }
# Load the MR iid from the landed commit message when running not from a
# merge request workflow. This is useful to post back results at the merge
# request when running pipelines from master.
load_mr_vars_from_commit() {
{ set +x; } 2>/dev/null
if [[ -z "${CI_MERGE_REQUEST_IID:-}" ]]; then
local mr_iid=$(git rev-list --format=%B --max-count=1 HEAD |
grep -F "${CI_PROJECT_URL}" | grep -F "/merge_requests" | head -n 1)
# mr_iid contains a string like this if it matched:
# Part-of: <https://gitlab.com/wg1/jpeg-xlm/merge_requests/123456>
if [[ -n "${mr_iid}" ]]; then
mr_iid=$(echo "${mr_iid}" |
sed -E 's,^.*merge_requests/([0-9]+)>.*$,\1,')
CI_MERGE_REQUEST_IID="${mr_iid}"
CI_MERGE_REQUEST_PROJECT_ID=${CI_PROJECT_ID}
fi
fi
set -x
}
# Posts a comment to the current merge request.
cmd_post_mr_comment() {
{ set +x; } 2>/dev/null
local comment="$1"
if [[ -n "${BOT_TOKEN:-}" && -n "${CI_MERGE_REQUEST_IID:-}" ]]; then
local url="${CI_API_V4_URL}/projects/${CI_MERGE_REQUEST_PROJECT_ID}/merge_requests/${CI_MERGE_REQUEST_IID}/notes"
curl -X POST -g \
-H "PRIVATE-TOKEN: ${BOT_TOKEN}" \
--data-urlencode "body=${comment}" \
--output /dev/null \
"${url}"
fi
set -x
}
# Set up and export the environment variables needed by the child processes. # Set up and export the environment variables needed by the child processes.
export_env() { export_env() {
@ -452,14 +427,17 @@ cmake_configure() {
} }
cmake_build_and_test() { cmake_build_and_test() {
if [[ "${SKIP_BUILD}" -eq "1" ]]; then
return 0
fi
# gtest_discover_tests() runs the test binaries to discover the list of tests # gtest_discover_tests() runs the test binaries to discover the list of tests
# at build time, which fails under qemu. # at build time, which fails under qemu.
ASAN_OPTIONS=detect_leaks=0 cmake --build "${BUILD_DIR}" -- all doc ASAN_OPTIONS=detect_leaks=0 cmake --build "${BUILD_DIR}" -- $TARGETS
# Pack test binaries if requested. # Pack test binaries if requested.
if [[ "${PACK_TEST:-}" == "1" ]]; then if [[ "${PACK_TEST:-}" == "1" ]]; then
(cd "${BUILD_DIR}" (cd "${BUILD_DIR}"
${FIND_BIN} -name '*.cmake' -a '!' -path '*CMakeFiles*' ${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} lib/ -name 'libg*.so*'
${FIND_BIN} -type d -name tests -a '!' -path '*CMakeFiles*' ${FIND_BIN} -type d -name tests -a '!' -path '*CMakeFiles*'
) | tar -C "${BUILD_DIR}" -cf "${BUILD_DIR}/tests.tar.xz" -T - \ ) | tar -C "${BUILD_DIR}" -cf "${BUILD_DIR}/tests.tar.xz" -T - \
@ -507,7 +485,7 @@ strip_dead_code() {
### Externally visible commands ### Externally visible commands
cmd_debug() { cmd_debug() {
CMAKE_BUILD_TYPE="Debug" CMAKE_BUILD_TYPE="DebugOpt"
cmake_configure "$@" cmake_configure "$@"
cmake_build_and_test cmake_build_and_test
} }
@ -521,7 +499,7 @@ cmd_release() {
cmd_opt() { cmd_opt() {
CMAKE_BUILD_TYPE="RelWithDebInfo" CMAKE_BUILD_TYPE="RelWithDebInfo"
CMAKE_CXX_FLAGS+=" -DJXL_DEBUG_WARNING -DJXL_DEBUG_ON_ERROR" CMAKE_CXX_FLAGS+=" -DJXL_IS_DEBUG_BUILD"
cmake_configure "$@" cmake_configure "$@"
cmake_build_and_test cmake_build_and_test
} }
@ -547,6 +525,7 @@ cmd_coverage_report() {
# Only print coverage information for the libjxl directories. The rest # Only print coverage information for the libjxl directories. The rest
# is not part of the code under test. # is not part of the code under test.
--filter '.*jxl/.*' --filter '.*jxl/.*'
--exclude '.*_gbench.cc'
--exclude '.*_test.cc' --exclude '.*_test.cc'
--exclude '.*_testonly..*' --exclude '.*_testonly..*'
--exclude '.*_debug.*' --exclude '.*_debug.*'
@ -576,7 +555,7 @@ cmd_test() {
(cd "${BUILD_DIR}" (cd "${BUILD_DIR}"
export UBSAN_OPTIONS=print_stacktrace=1 export UBSAN_OPTIONS=print_stacktrace=1
[[ "${TEST_STACK_LIMIT}" == "none" ]] || ulimit -s "${TEST_STACK_LIMIT}" [[ "${TEST_STACK_LIMIT}" == "none" ]] || ulimit -s "${TEST_STACK_LIMIT}"
ctest -j $(nproc --all || echo 1) --output-on-failure "$@") ctest -j $(nproc --all || echo 1) ${TEST_SELECTOR} --output-on-failure "$@")
} }
cmd_gbench() { cmd_gbench() {
@ -600,6 +579,7 @@ cmd_msanfuzz() {
# Install msan if needed before changing the flags. # Install msan if needed before changing the flags.
detect_clang_version detect_clang_version
local msan_prefix="${HOME}/.msan/${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 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 # Install msan libraries for this version if needed or if an older version
# with libc++abi was installed. # with libc++abi was installed.
@ -613,9 +593,9 @@ cmd_msanfuzz() {
cmd_asan() { cmd_asan() {
SANITIZER="asan" SANITIZER="asan"
CMAKE_C_FLAGS+=" -DJXL_ENABLE_ASSERT=1 -g -DADDRESS_SANITIZER \ CMAKE_C_FLAGS+=" -g -DADDRESS_SANITIZER \
-fsanitize=address ${UBSAN_FLAGS[@]}" -fsanitize=address ${UBSAN_FLAGS[@]}"
CMAKE_CXX_FLAGS+=" -DJXL_ENABLE_ASSERT=1 -g -DADDRESS_SANITIZER \ CMAKE_CXX_FLAGS+=" -g -DADDRESS_SANITIZER \
-fsanitize=address ${UBSAN_FLAGS[@]}" -fsanitize=address ${UBSAN_FLAGS[@]}"
strip_dead_code strip_dead_code
cmake_configure "$@" -DJPEGXL_ENABLE_TCMALLOC=OFF cmake_configure "$@" -DJPEGXL_ENABLE_TCMALLOC=OFF
@ -625,16 +605,13 @@ cmd_asan() {
cmd_tsan() { cmd_tsan() {
SANITIZER="tsan" SANITIZER="tsan"
local tsan_args=( local tsan_args=(
-DJXL_ENABLE_ASSERT=1
-g -g
-DTHREAD_SANITIZER -DTHREAD_SANITIZER
${UBSAN_FLAGS[@]}
-fsanitize=thread -fsanitize=thread
) )
CMAKE_C_FLAGS+=" ${tsan_args[@]}" CMAKE_C_FLAGS+=" ${tsan_args[@]}"
CMAKE_CXX_FLAGS+=" ${tsan_args[@]}" CMAKE_CXX_FLAGS+=" ${tsan_args[@]}"
CMAKE_BUILD_TYPE="RelWithDebInfo"
cmake_configure "$@" -DJPEGXL_ENABLE_TCMALLOC=OFF cmake_configure "$@" -DJPEGXL_ENABLE_TCMALLOC=OFF
cmake_build_and_test cmake_build_and_test
} }
@ -652,15 +629,20 @@ cmd_msan() {
local msan_c_flags=( local msan_c_flags=(
-fsanitize=memory -fsanitize=memory
-fno-omit-frame-pointer -fno-omit-frame-pointer
-fsanitize-memory-track-origins
-DJXL_ENABLE_ASSERT=1
-g -g
-DMEMORY_SANITIZER -DMEMORY_SANITIZER
# Force gtest to not use the cxxbai. # Force gtest to not use the cxxbai.
-DGTEST_HAS_CXXABI_H_=0 -DGTEST_HAS_CXXABI_H_=0
) )
if [[ "${FASTER_MSAN_BUILD}" -ne "1" ]]; then
msan_c_flags=(
"${msan_c_flags[@]}"
-fsanitize-memory-track-origins
)
fi
local msan_cxx_flags=( local msan_cxx_flags=(
"${msan_c_flags[@]}" "${msan_c_flags[@]}"
@ -680,16 +662,22 @@ cmd_msan() {
-Wl,-rpath -Wl,"${msan_prefix}"/lib/ -Wl,-rpath -Wl,"${msan_prefix}"/lib/
) )
CMAKE_C_FLAGS+=" ${msan_c_flags[@]} ${UBSAN_FLAGS[@]}" CMAKE_C_FLAGS+=" ${msan_c_flags[@]}"
CMAKE_CXX_FLAGS+=" ${msan_cxx_flags[@]} ${UBSAN_FLAGS[@]}" CMAKE_CXX_FLAGS+=" ${msan_cxx_flags[@]}"
CMAKE_EXE_LINKER_FLAGS+=" ${msan_linker_flags[@]}" CMAKE_EXE_LINKER_FLAGS+=" ${msan_linker_flags[@]}"
CMAKE_MODULE_LINKER_FLAGS+=" ${msan_linker_flags[@]}" CMAKE_MODULE_LINKER_FLAGS+=" ${msan_linker_flags[@]}"
CMAKE_SHARED_LINKER_FLAGS+=" ${msan_linker_flags[@]}" CMAKE_SHARED_LINKER_FLAGS+=" ${msan_linker_flags[@]}"
strip_dead_code 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 "$@" \ cmake_configure "$@" \
-DCMAKE_CROSSCOMPILING=1 -DRUN_HAVE_STD_REGEX=0 -DRUN_HAVE_POSIX_REGEX=0 \ -DCMAKE_CROSSCOMPILING=1 -DRUN_HAVE_STD_REGEX=0 -DRUN_HAVE_POSIX_REGEX=0 \
-DJPEGXL_ENABLE_TCMALLOC=OFF -DJPEGXL_WARNINGS_AS_ERRORS=OFF \ -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 cmake_build_and_test
} }
@ -698,6 +686,8 @@ cmd_msan() {
cmd_msan_install() { cmd_msan_install() {
local tmpdir=$(mktemp -d) local tmpdir=$(mktemp -d)
CLEANUP_FILES+=("${tmpdir}") CLEANUP_FILES+=("${tmpdir}")
local msan_root="${HOME}/.msan"
mkdir -p "${msan_root}"
# Detect the llvm to install: # Detect the llvm to install:
export CC="${CC:-clang}" export CC="${CC:-clang}"
export CXX="${CXX:-clang++}" export CXX="${CXX:-clang++}"
@ -705,50 +695,70 @@ cmd_msan_install() {
# Allow overriding the LLVM checkout. # Allow overriding the LLVM checkout.
local llvm_root="${LLVM_ROOT:-}" local llvm_root="${LLVM_ROOT:-}"
if [ -z "${llvm_root}" ]; then if [ -z "${llvm_root}" ]; then
local llvm_tag="llvmorg-${CLANG_VERSION}.0.0" declare -A llvm_tag_by_version=(
case "${CLANG_VERSION}" in ["6.0"]="6.0.1"
"6.0") ["7"]="7.1.0"
llvm_tag="llvmorg-6.0.1" ["8"]="8.0.1"
;; ["9"]="9.0.2"
"7") ["10"]="10.0.1"
llvm_tag="llvmorg-7.0.1" ["11"]="11.1.0"
;; ["12"]="12.0.1"
esac ["13"]="13.0.1"
local llvm_targz="${tmpdir}/${llvm_tag}.tar.gz" ["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}" \ curl -L --show-error -o "${llvm_targz}" \
"https://github.com/llvm/llvm-project/archive/${llvm_tag}.tar.gz" "https://github.com/llvm/llvm-project/archive/${llvm_tag}.tar.gz"
fi
tar -C "${tmpdir}" -zxf "${llvm_targz}" tar -C "${tmpdir}" -zxf "${llvm_targz}"
llvm_root="${tmpdir}/llvm-project-${llvm_tag}" llvm_root="${tmpdir}/llvm-project-${llvm_tag}"
fi fi
local msan_prefix="${HOME}/.msan/${CLANG_VERSION}" local msan_prefix="${msan_root}/${CLANG_VERSION}"
rm -rf "${msan_prefix}" rm -rf "${msan_prefix}"
declare -A CMAKE_EXTRAS local TARGET_OPTS=""
CMAKE_EXTRAS[libcxx]="\ if [[ -n "${BUILD_TARGET}" ]]; then
-DLIBCXX_CXX_ABI=libstdc++ \ TARGET_OPTS=" \
-DLIBCXX_INSTALL_EXPERIMENTAL_LIBRARY=ON" -DCMAKE_C_COMPILER_TARGET=\"${BUILD_TARGET}\" \
-DCMAKE_CXX_COMPILER_TARGET=\"${BUILD_TARGET}\" \
-DCMAKE_SYSTEM_PROCESSOR=\"${BUILD_TARGET%%-*}\" \
"
fi
for project in libcxx; do local build_dir="${tmpdir}/build-llvm"
local proj_build="${tmpdir}/build-${project}" mkdir -p "${build_dir}"
local proj_dir="${llvm_root}/${project}" cd ${llvm_root}
mkdir -p "${proj_build}" cmake -B"${build_dir}" \
cmake -B"${proj_build}" -H"${proj_dir}" \
-G Ninja \ -G Ninja \
-S runtimes \
-DCMAKE_BUILD_TYPE=Release \ -DCMAKE_BUILD_TYPE=Release \
-DLLVM_USE_SANITIZER=Memory \ -DLLVM_USE_SANITIZER=Memory \
-DLLVM_PATH="${llvm_root}/llvm" \ -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind;compiler-rt" \
-DLLVM_CONFIG_PATH="$(which llvm-config llvm-config-7 llvm-config-6.0 | \ -DLIBCXXABI_ENABLE_SHARED=ON \
head -n1)" \ -DLIBCXXABI_ENABLE_STATIC=OFF \
-DLIBCXX_ENABLE_SHARED=ON \
-DLIBCXX_ENABLE_STATIC=OFF \
-DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS}" \ -DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS}" \
-DCMAKE_C_FLAGS="${CMAKE_C_FLAGS}" \ -DCMAKE_C_FLAGS="${CMAKE_C_FLAGS}" \
-DCMAKE_EXE_LINKER_FLAGS="${CMAKE_EXE_LINKER_FLAGS}" \ -DCMAKE_EXE_LINKER_FLAGS="${CMAKE_EXE_LINKER_FLAGS}" \
-DCMAKE_SHARED_LINKER_FLAGS="${CMAKE_SHARED_LINKER_FLAGS}" \ -DCMAKE_SHARED_LINKER_FLAGS="${CMAKE_SHARED_LINKER_FLAGS}" \
-DCMAKE_INSTALL_PREFIX="${msan_prefix}" \ -DCMAKE_INSTALL_PREFIX="${msan_prefix}" \
${CMAKE_EXTRAS[${project}]} -DLLVM_PATH="${llvm_root}/llvm" \
cmake --build "${proj_build}" -DLLVM_CONFIG_PATH="$(which llvm-config-${CLANG_VERSION} llvm-config | head -n1)" \
ninja -C "${proj_build}" install ${TARGET_OPTS}
done cmake --build "${build_dir}"
ninja -C "${build_dir}" install
} }
# Internal build step shared between all cmd_ossfuzz_* commands. # Internal build step shared between all cmd_ossfuzz_* commands.
@ -788,7 +798,7 @@ _cmd_ossfuzz() {
-e MSAN_LIBS_PATH="/work/msan" \ -e MSAN_LIBS_PATH="/work/msan" \
-e JPEGXL_EXTRA_ARGS="${jpegxl_extra_args}" \ -e JPEGXL_EXTRA_ARGS="${jpegxl_extra_args}" \
-v "${MYDIR}":/src/libjxl \ -v "${MYDIR}":/src/libjxl \
-v "${MYDIR}/tools/ossfuzz-build.sh":/src/build.sh \ -v "${MYDIR}/tools/scripts/ossfuzz-build.sh":/src/build.sh \
-v "${real_build_dir}":/work \ -v "${real_build_dir}":/work \
gcr.io/oss-fuzz/libjxl gcr.io/oss-fuzz/libjxl
} }
@ -822,9 +832,13 @@ cmd_ossfuzz_ninja() {
cmd_fast_benchmark() { cmd_fast_benchmark() {
local small_corpus_tar="${BENCHMARK_CORPORA}/jyrki-full.tar" 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}" mkdir -p "${BENCHMARK_CORPORA}"
curl --show-error -o "${small_corpus_tar}" -z "${small_corpus_tar}" \ if [ -f "${small_corpus_tar}" ]; then
"https://storage.googleapis.com/artifacts.jpegxl.appspot.com/corpora/jyrki-full.tar" 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) local tmpdir=$(mktemp -d)
CLEANUP_FILES+=("${tmpdir}") CLEANUP_FILES+=("${tmpdir}")
@ -862,7 +876,7 @@ cmd_benchmark() {
png_filename="${filename%.ppm}.png" png_filename="${filename%.ppm}.png"
png_filename=$(echo "${png_filename}" | tr '/' '_') png_filename=$(echo "${png_filename}" | tr '/' '_')
sem --bg --id "${sem_id}" -j"${nprocs}" -- \ sem --bg --id "${sem_id}" -j"${nprocs}" -- \
"${BUILD_DIR}/tools/decode_and_encode" \ "${TOOLS_DIR}/decode_and_encode" \
"${tmpdir}/${filename}" "${mode}" "${tmpdir}/${png_filename}" "${tmpdir}/${filename}" "${mode}" "${tmpdir}/${png_filename}"
images+=( "${png_filename}" ) images+=( "${png_filename}" )
done < <(cd "${tmpdir}"; ${FIND_BIN} . -name '*.ppm' -type f) done < <(cd "${tmpdir}"; ${FIND_BIN} . -name '*.ppm' -type f)
@ -875,6 +889,8 @@ cmd_benchmark() {
get_mem_available() { get_mem_available() {
if [[ "${OS}" == "Darwin" ]]; then if [[ "${OS}" == "Darwin" ]]; then
echo $(vm_stat | grep -F 'Pages free:' | awk '{print $3 * 4}') 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 else
echo $(grep -F MemAvailable: /proc/meminfo | awk '{print $2}') echo $(grep -F MemAvailable: /proc/meminfo | awk '{print $2}')
fi fi
@ -887,45 +903,46 @@ run_benchmark() {
local output_dir="${BUILD_DIR}/benchmark_results" local output_dir="${BUILD_DIR}/benchmark_results"
mkdir -p "${output_dir}" mkdir -p "${output_dir}"
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 # 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 # of threads depends on the available memory, and the passed memory per
# thread. We also add a 2 GiB of constant memory. # thread. We also add a 2 GiB of constant memory.
local mem_available="$(get_mem_available)" local mem_available="$(get_mem_available)"
# Check that we actually have a MemAvailable value. # Check that we actually have a MemAvailable value.
[[ -n "${mem_available}" ]] [[ -n "${mem_available}" ]]
local num_threads=$(( (${mem_available} - 1048576) / ${mem_per_thread} )) num_threads=$(( (${mem_available} - 1048576) / ${mem_per_thread} ))
if [[ ${num_threads} -le 0 ]]; then if [[ ${num_threads} -le 0 ]]; then
num_threads=1 num_threads=1
fi fi
fi
local benchmark_args=( local benchmark_args=(
--input "${src_img_dir}/*.png" --input "${src_img_dir}/*.png"
--codec=jpeg:yuv420:q85,webp:q80,jxl:d1:6,jxl:d1:6:downsampling=8,jxl:d5:6,jxl:d5:6:downsampling=8,jxl:m:d0:2,jxl:m:d0:3,jxl:m:d2:2 --codec=jpeg:yuv420:q85,webp:q80,jxl:d1:6,jxl:d1:6:downsampling=8,jxl:d5:6,jxl:d5:6:downsampling=8,jxl:m:d0:2,jxl:m:d0:3,jxl:m:d2:2
--output_dir "${output_dir}" --output_dir "${output_dir}"
--noprofiler --show_progress --show_progress
--num_threads="${num_threads}" --num_threads="${num_threads}"
--decode_reps=11
--encode_reps=11
) )
if [[ "${STORE_IMAGES}" == "1" ]]; then if [[ "${STORE_IMAGES}" == "1" ]]; then
benchmark_args+=(--save_decompressed --save_compressed) benchmark_args+=(--save_decompressed --save_compressed)
fi fi
( (
[[ "${TEST_STACK_LIMIT}" == "none" ]] || ulimit -s "${TEST_STACK_LIMIT}" [[ "${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" 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]} return ${PIPESTATUS[0]}
) )
if [[ -n "${CI_BUILD_NAME:-}" ]]; then
{ set +x; } 2>/dev/null
local message="Results for ${CI_BUILD_NAME} @ ${CI_COMMIT_SHORT_SHA} (job ${CI_JOB_URL:-}):
$(cat "${output_dir}/results.txt")
"
cmd_post_mr_comment "${message}"
set -x
fi
} }
# Helper function to wait for the CPU temperature to cool down on ARM. # Helper function to wait for the CPU temperature to cool down on ARM.
@ -1066,7 +1083,7 @@ cmd_arm_benchmark() {
local src_img local src_img
for src_img in "${jpg_images[@]}" "${images[@]}"; do for src_img in "${jpg_images[@]}" "${images[@]}"; do
local src_img_hash=$(sha1sum "${src_img}" | cut -f 1 -d ' ') 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##*.}" local src_ext="${src_img##*.}"
for enc_binary in "${enc_binaries[@]}"; do for enc_binary in "${enc_binaries[@]}"; do
local enc_binary_base=$(basename "${enc_binary}") local enc_binary_base=$(basename "${enc_binary}")
@ -1115,7 +1132,7 @@ cmd_arm_benchmark() {
local dec_output local dec_output
wait_for_temp 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 | --num_reps=5 --num_threads="${num_threads}" 2>&1 | tee /dev/stderr |
grep -E "M[BP]/s \[") grep -E "M[BP]/s \[")
local img_size=$(echo "${dec_output}" | cut -f 1 -d ',') local img_size=$(echo "${dec_output}" | cut -f 1 -d ',')
@ -1131,7 +1148,7 @@ cmd_arm_benchmark() {
if [[ "${src_ext}" == "jpg" ]]; then if [[ "${src_ext}" == "jpg" ]]; then
wait_for_temp wait_for_temp
local dec_file="${BUILD_DIR}/arm_benchmark/${enc_file_hash}.jpg" 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 | \ "${dec_file}" --num_reps=5 --num_threads="${num_threads}" 2>&1 | \
tee /dev/stderr | grep -E "M[BP]/s \[") tee /dev/stderr | grep -E "M[BP]/s \[")
local jpeg_dec_mps_speed=$(_speed_from_output "${dec_output}") local jpeg_dec_mps_speed=$(_speed_from_output "${dec_output}")
@ -1153,18 +1170,6 @@ cmd_arm_benchmark() {
cmd_cpuset "${RUNNER_CPU_ALL:-}" cmd_cpuset "${RUNNER_CPU_ALL:-}"
cat "${runs_file}" cat "${runs_file}"
if [[ -n "${CI_BUILD_NAME:-}" ]]; then
load_mr_vars_from_commit
{ set +x; } 2>/dev/null
local message="Results for ${CI_BUILD_NAME} @ ${CI_COMMIT_SHORT_SHA} (job ${CI_JOB_URL:-}):
\`\`\`
$(column -t -s " " "${runs_file}")
\`\`\`
"
cmd_post_mr_comment "${message}"
set -x
fi
} }
# Generate a corpus and run the fuzzer on that corpus. # Generate a corpus and run the fuzzer on that corpus.
@ -1173,33 +1178,58 @@ cmd_fuzz() {
local fuzzer_crash_dir=$(realpath "${BUILD_DIR}/fuzzer_crash") local fuzzer_crash_dir=$(realpath "${BUILD_DIR}/fuzzer_crash")
mkdir -p "${corpus_dir}" "${fuzzer_crash_dir}" mkdir -p "${corpus_dir}" "${fuzzer_crash_dir}"
# Generate step. # Generate step.
"${BUILD_DIR}/tools/fuzzer_corpus" "${corpus_dir}" "${TOOLS_DIR}/fuzzer_corpus" "${corpus_dir}"
# Run step: # Run step:
local nprocs=$(nproc --all || echo 1) local nprocs=$(nproc --all || echo 1)
( (
cd "${BUILD_DIR}" cd "${TOOLS_DIR}"
"tools/djxl_fuzzer" "${fuzzer_crash_dir}" "${corpus_dir}" \ djxl_fuzzer "${fuzzer_crash_dir}" "${corpus_dir}" \
-max_total_time="${FUZZER_MAX_TIME}" -jobs=${nprocs} \ -max_total_time="${FUZZER_MAX_TIME}" -jobs=${nprocs} \
-artifact_prefix="${fuzzer_crash_dir}/" -artifact_prefix="${fuzzer_crash_dir}/"
) )
} }
# Runs the linter (clang-format) on the pending CLs. # Runs the linters (clang-format, build_cleaner, buildirier) on the pending CLs.
cmd_lint() { cmd_lint() {
merge_request_commits merge_request_commits
{ set +x; } 2>/dev/null { set +x; } 2>/dev/null
local versions=(${1:-6.0 7 8 9 10 11}) local versions=(${1:-16 15 14 13 12 11 10 9 8 7 6.0})
local clang_format_bins=("${versions[@]/#/clang-format-}" clang-format) local clang_format_bins=("${versions[@]/#/clang-format-}" clang-format)
local tmpdir=$(mktemp -d) local tmpdir=$(mktemp -d)
CLEANUP_FILES+=("${tmpdir}") CLEANUP_FILES+=("${tmpdir}")
local ret=0 local ret=0
local build_patch="${tmpdir}/build_cleaner.patch" local build_patch="${tmpdir}/build_cleaner.patch"
if ! "${MYDIR}/tools/build_cleaner.py" >"${build_patch}"; then if ! "${MYDIR}/tools/scripts/build_cleaner.py" >"${build_patch}"; then
ret=1 ret=1
echo "build_cleaner.py findings:" >&2 echo "build_cleaner.py findings:" >&2
"${COLORDIFF_BIN}" <"${build_patch}" "${COLORDIFF_BIN}" <"${build_patch}"
echo "Run \`tools/build_cleaner.py --update\` to apply them" >&2 echo "Run \`tools/scripts/build_cleaner.py --update\` to apply them" >&2
fi
# 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$"`
set -x
buildifier -d ${bazel_files} >"${buildifier_patch}"|| true
{ set +x; } 2>/dev/null
if [ -s "${buildifier_patch}" ]; then
ret=1
echo 'buildifier have found some problems in Bazel build files:' >&2
"${COLORDIFF_BIN}" <"${buildifier_patch}"
echo 'To fix them run (from the base directory):' >&2
echo ' buildifier `git ls-files | grep -E "/BUILD$|WORKSPACE|.bzl$"`' >&2
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 fi
local installed=() local installed=()
@ -1218,7 +1248,7 @@ cmd_lint() {
git -C "${MYDIR}" "${clang_format}" --binary "${clang_format}" \ git -C "${MYDIR}" "${clang_format}" --binary "${clang_format}" \
--style=file --diff "${MR_ANCESTOR_SHA}" -- >"${tmppatch}" || true --style=file --diff "${MR_ANCESTOR_SHA}" -- >"${tmppatch}" || true
{ set +x; } 2>/dev/null { set +x; } 2>/dev/null
if grep -E '^--- ' "${tmppatch}">/dev/null; then if grep -E '^--- ' "${tmppatch}" | grep -v 'a/third_party' >/dev/null; then
if [[ -n "${LINT_OUTPUT:-}" ]]; then if [[ -n "${LINT_OUTPUT:-}" ]]; then
cp "${tmppatch}" "${LINT_OUTPUT}" cp "${tmppatch}" "${LINT_OUTPUT}"
fi fi
@ -1326,6 +1356,7 @@ cmd_debian_stats() {
build_debian_pkg() { build_debian_pkg() {
local srcdir="$1" local srcdir="$1"
local srcpkg="$2" local srcpkg="$2"
local options="${3:-}"
local debsdir="${BUILD_DIR}/debs" local debsdir="${BUILD_DIR}/debs"
local builddir="${debsdir}/${srcpkg}" local builddir="${debsdir}/${srcpkg}"
@ -1341,7 +1372,7 @@ build_debian_pkg() {
done done
( (
cd "${builddir}" cd "${builddir}"
debuild -b -uc -us debuild "${options}" -b -uc -us
) )
} }
@ -1353,7 +1384,7 @@ cmd_debian_build() {
build_debian_pkg "${MYDIR}" "jpeg-xl" build_debian_pkg "${MYDIR}" "jpeg-xl"
;; ;;
highway) highway)
build_debian_pkg "${MYDIR}/third_party/highway" "highway" build_debian_pkg "${MYDIR}/third_party/highway" "highway" "${HWY_PKG_OPTIONS}"
;; ;;
*) *)
echo "ERROR: Must pass a valid source package name to build." >&2 echo "ERROR: Must pass a valid source package name to build." >&2
@ -1374,7 +1405,7 @@ cmd_bump_version() {
local newver="${1:-}" local newver="${1:-}"
if ! which dch >/dev/null; then if ! which dch >/dev/null; then
echo "Run:\n sudo apt install debhelper" echo "Missing dch\nTo install it run:\n sudo apt install devscripts"
exit 1 exit 1
fi fi
@ -1402,9 +1433,13 @@ cmd_bump_version() {
-e "s/(set\\(JPEGXL_MINOR_VERSION) [0-9]+\\)/\\1 ${minor})/" \ -e "s/(set\\(JPEGXL_MINOR_VERSION) [0-9]+\\)/\\1 ${minor})/" \
-e "s/(set\\(JPEGXL_PATCH_VERSION) [0-9]+\\)/\\1 ${patch})/" \ -e "s/(set\\(JPEGXL_PATCH_VERSION) [0-9]+\\)/\\1 ${patch})/" \
-i lib/CMakeLists.txt -i lib/CMakeLists.txt
sed -E \
-e "s/(LIBJXL_VERSION: )\"[0-9.]+\"/\\1\"${major}.${minor}.${patch}\"/" \
-e "s/(LIBJXL_ABI_VERSION: )\"[0-9.]+\"/\\1\"${major}.${minor}\"/" \
-i .github/workflows/conformance.yml
# Update lib.gni # Update lib.gni
tools/build_cleaner.py --update tools/scripts/build_cleaner.py --update
# Mark the previous version as "unstable". # Mark the previous version as "unstable".
DEBCHANGE_RELEASE_HEURISTIC=log dch -M --distribution unstable --release '' DEBCHANGE_RELEASE_HEURISTIC=log dch -M --distribution unstable --release ''
@ -1418,11 +1453,11 @@ cmd_authors() {
merge_request_commits merge_request_commits
local emails local emails
local names local names
readarray -t emails < <(git log --format='%ae' "${MR_HEAD_SHA}...${MR_ANCESTOR_SHA}") readarray -t emails < <(git log --format='%ae' "${MR_ANCESTOR_SHA}..${MR_HEAD_SHA}")
readarray -t names < <(git log --format='%an' "${MR_HEAD_SHA}...${MR_ANCESTOR_SHA}") readarray -t names < <(git log --format='%an' "${MR_ANCESTOR_SHA}..${MR_HEAD_SHA}")
for i in "${!names[@]}"; do for i in "${!names[@]}"; do
echo "Checking name '${names[$i]}' with email '${emails[$i]}' ..." echo "Checking name '${names[$i]}' with email '${emails[$i]}' ..."
"${MYDIR}"/tools/check_author.py "${emails[$i]}" "${names[$i]}" "${MYDIR}"/tools/scripts/check_author.py "${emails[$i]}" "${names[$i]}"
done done
} }
@ -1450,7 +1485,7 @@ Where cmd is one of:
benchmark Run the benchmark over the default corpus. benchmark Run the benchmark over the default corpus.
fast_benchmark Run the benchmark over the small corpus. fast_benchmark Run the benchmark over the small corpus.
coverage Buils and run tests with coverage support. Runs coverage_report as coverage Build and run tests with coverage support. Runs coverage_report as
well. well.
coverage_report Generate HTML, XML and text coverage report after a coverage coverage_report Generate HTML, XML and text coverage report after a coverage
run. run.
@ -1483,6 +1518,7 @@ You can pass some optional environment variables as well:
- FUZZER_MAX_TIME: "fuzz" command fuzzer running timeout in seconds. - FUZZER_MAX_TIME: "fuzz" command fuzzer running timeout in seconds.
- LINT_OUTPUT: Path to the output patch from the "lint" command. - LINT_OUTPUT: Path to the output patch from the "lint" command.
- SKIP_CPUSET=1: Skip modifying the cpuset in the arm_benchmark. - SKIP_CPUSET=1: Skip modifying the cpuset in the arm_benchmark.
- SKIP_BUILD=1: Skip the build stage, cmake configure only.
- SKIP_TEST=1: Skip the test stage. - SKIP_TEST=1: Skip the test stage.
- STORE_IMAGES=0: Makes the benchmark discard the computed images. - STORE_IMAGES=0: Makes the benchmark discard the computed images.
- TEST_STACK_LIMIT: Stack size limit (ulimit -s) during tests, in KiB. - TEST_STACK_LIMIT: Stack size limit (ulimit -s) during tests, in KiB.

View file

@ -31,11 +31,6 @@ foreach(brlib IN ITEMS ${brlibs})
set_property(TARGET ${brlib} PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${BROTLI_INCLUDE_DIR}) set_property(TARGET ${brlib} PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${BROTLI_INCLUDE_DIR})
target_link_libraries(${brlib} INTERFACE ${${BRPREFIX}_LIBRARY}) target_link_libraries(${brlib} INTERFACE ${${BRPREFIX}_LIBRARY})
set_property(TARGET ${brlib} PROPERTY INTERFACE_COMPILE_OPTIONS ${PC_${BRPREFIX}_CFLAGS_OTHER}) set_property(TARGET ${brlib} PROPERTY INTERFACE_COMPILE_OPTIONS ${PC_${BRPREFIX}_CFLAGS_OTHER})
add_library(${brlib}-static INTERFACE IMPORTED GLOBAL)
set_property(TARGET ${brlib}-static PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${BROTLI_INCLUDE_DIR})
target_link_libraries(${brlib}-static INTERFACE ${${BRPREFIX}_LIBRARY})
set_property(TARGET ${brlib}-static PROPERTY INTERFACE_COMPILE_OPTIONS ${PC_${BRPREFIX}_CFLAGS_OTHER})
else() else()
add_library(${brlib} INTERFACE IMPORTED GLOBAL) add_library(${brlib} INTERFACE IMPORTED GLOBAL)
target_include_directories(${brlib} target_include_directories(${brlib}
@ -46,11 +41,6 @@ foreach(brlib IN ITEMS ${brlibs})
INTERFACE ${PC_${BRPREFIX}_LDFLAGS_OTHER}) INTERFACE ${PC_${BRPREFIX}_LDFLAGS_OTHER})
target_compile_options(${brlib} target_compile_options(${brlib}
INTERFACE ${PC_${BRPREFIX}_CFLAGS_OTHER}) INTERFACE ${PC_${BRPREFIX}_CFLAGS_OTHER})
# TODO(deymo): Remove the -static library versions, this target is
# currently needed by brunsli.cmake. When importing it this way, the
# brotli*-static target is just an alias.
add_library(${brlib}-static ALIAS ${brlib})
endif() endif()
endif() endif()
endforeach() endforeach()

View file

@ -10,7 +10,7 @@ if (PkgConfig_FOUND)
endif () endif ()
find_path(HWY_INCLUDE_DIR find_path(HWY_INCLUDE_DIR
NAMES hwy/highway.h NAMES hwy/base.h hwy/highway.h
HINTS ${PC_HWY_INCLUDEDIR} ${PC_HWY_INCLUDE_DIRS} HINTS ${PC_HWY_INCLUDEDIR} ${PC_HWY_INCLUDE_DIRS}
) )
@ -19,20 +19,30 @@ find_library(HWY_LIBRARY
HINTS ${PC_HWY_LIBDIR} ${PC_HWY_LIBRARY_DIRS} 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 (HWY_INCLUDE_DIR AND NOT HWY_VERSION)
if (EXISTS "${HWY_INCLUDE_DIR}/hwy/highway.h") set(HWY_VERSION "")
file(READ "${HWY_INCLUDE_DIR}/hwy/highway.h" HWY_VERSION_CONTENT) 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]+)" _dummy "${HWY_VERSION_CONTENT}") string(REGEX MATCH "#define HWY_MAJOR +([0-9]+)" _sink "${HWY_VERSION_CONTENT}")
set(HWY_VERSION_MAJOR "${CMAKE_MATCH_1}") set(HWY_VERSION_MAJOR "${CMAKE_MATCH_1}")
string(REGEX MATCH "#define +HWY_MINOR +([0-9]+)" _dummy "${HWY_VERSION_CONTENT}") string(REGEX MATCH "#define +HWY_MINOR +([0-9]+)" _sink "${HWY_VERSION_CONTENT}")
set(HWY_VERSION_MINOR "${CMAKE_MATCH_1}") set(HWY_VERSION_MINOR "${CMAKE_MATCH_1}")
string(REGEX MATCH "#define +HWY_PATCH +([0-9]+)" _dummy "${HWY_VERSION_CONTENT}") string(REGEX MATCH "#define +HWY_PATCH +([0-9]+)" _sink "${HWY_VERSION_CONTENT}")
set(HWY_VERSION_PATCH "${CMAKE_MATCH_1}") 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}") 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()
endif () endif ()

View file

@ -1,4 +1,46 @@
jpeg-xl (0.7) UNRELEASED; urgency=medium jpeg-xl (0.11.1) UNRELEASED; urgency=medium
* Bump JPEG XL version to 0.11.1.
-- JPEG XL Maintainers <jpegxl@google.com> Tue, 26 Nov 2024 12:09:23 +0100
jpeg-xl (0.11.0) unstable; urgency=medium
* Bump JPEG XL version to 0.11.0.
-- JPEG XL Maintainers <jpegxl@google.com> Tue, 06 Aug 2024 14:35:34 +0200
jpeg-xl (0.10.2) unstable; urgency=medium
* Bump JPEG XL version to 0.10.2.
-- JPEG XL Maintainers <jpegxl@google.com> Thu, 07 Mar 2024 13:50:05 +0100
jpeg-xl (0.10.1) unstable; urgency=medium
* Bump JPEG XL version to 0.10.1.
-- JPEG XL Maintainers <jpegxl@google.com> Wed, 28 Feb 2024 12:52:20 +0100
jpeg-xl (0.10.0) unstable; urgency=medium
* Bump JPEG XL version to 0.10.0.
-- JPEG XL Maintainers <jpegxl@google.com> Wed, 21 Feb 2024 08:37:00 +0100
jpeg-xl (0.9.0) unstable; urgency=medium
* Bump JPEG XL version to 0.9.0.
-- JPEG XL Maintainers <jpegxl@google.com> Tue, 21 Nov 2023 10:32:59 +0100
jpeg-xl (0.8) unstable; urgency=medium
* Bump JPEG XL version to 0.8.
-- JPEG XL Maintainers <jpegxl@google.com> Wed, 11 Jan 2023 16:12:34 +0000
jpeg-xl (0.7) unstable; urgency=medium
* Bump JPEG XL version to 0.7. * Bump JPEG XL version to 0.7.

View file

@ -11,10 +11,9 @@ Build-Depends:
libgdk-pixbuf-2.0-dev | libgdk-pixbuf2.0-dev, libgdk-pixbuf-2.0-dev | libgdk-pixbuf2.0-dev,
libgif-dev, libgif-dev,
libgimp2.0-dev, libgimp2.0-dev,
libgmock-dev,
libgoogle-perftools-dev, libgoogle-perftools-dev,
libgtest-dev, libgtest-dev,
libhwy-dev (>= 0.15.0), libhwy-dev (>= 1.0.0),
libjpeg-dev, libjpeg-dev,
libopenexr-dev, libopenexr-dev,
libpng-dev, libpng-dev,

View file

@ -5,6 +5,11 @@ Files: *
Copyright: 2020 the JPEG XL Project Copyright: 2020 the JPEG XL Project
License: BSD-3-clause License: BSD-3-clause
Files: third_party/libjpeg-turbo/*
Copyright (C)2009-2023 D. R. Commander. All Rights Reserved.
Copyright (C)2015 Viktor Szathmáry. All Rights Reserved.
License: BSD-3-clause
Files: third_party/sjpeg/* Files: third_party/sjpeg/*
Copyright: 2017 Google, Inc Copyright: 2017 Google, Inc
License: Apache-2.0 License: Apache-2.0

View file

@ -1,4 +1,3 @@
usr/include/jxl/*.h usr/include/jxl/*.h
usr/lib/*/*.a
usr/lib/*/*.so usr/lib/*/*.so
usr/lib/*/pkgconfig/*.pc usr/lib/*/pkgconfig/*.pc

View file

@ -8,10 +8,14 @@ include /usr/share/dpkg/pkg-info.mk
override_dh_auto_configure: override_dh_auto_configure:
# TODO(deymo): Remove the DCMAKE_BUILD_TYPE once builds without NDEBUG # TODO(deymo): Remove the DCMAKE_BUILD_TYPE once builds without NDEBUG
# are as useful as Release builds. # are as useful as Release builds.
# TODO(szabadka) Re-enable jpegli after tests are fixed on Ubuntu 20.04,
# and debian:buster
dh_auto_configure -- \ dh_auto_configure -- \
-DJPEGXL_VERSION=$(DEB_VERSION) \ -DJPEGXL_VERSION=$(DEB_VERSION) \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DJPEGXL_FORCE_SYSTEM_GTEST=ON \ -DJPEGXL_FORCE_SYSTEM_GTEST=ON \
-DJPEGXL_FORCE_SYSTEM_BROTLI=ON \ -DJPEGXL_FORCE_SYSTEM_BROTLI=ON \
-DJPEGXL_FORCE_SYSTEM_HWY=ON \ -DJPEGXL_FORCE_SYSTEM_HWY=ON \
-DJPEGXL_ENABLE_JPEGLI=OFF \
-DJPEGXL_ENABLE_JPEGLI_LIBJPEG=OFF \
-DJPEGXL_ENABLE_PLUGINS=ON -DJPEGXL_ENABLE_PLUGINS=ON

View file

@ -5,20 +5,24 @@
# license that can be found in the LICENSE file. # license that can be found in the LICENSE file.
# This file downloads the dependencies needed to build JPEG XL into third_party. # This file downloads the dependencies needed to build JPEG XL into third_party.
# These dependencies are normally pulled by gtest. # These dependencies are normally pulled by git.
set -eu set -eu
MYDIR=$(dirname $(realpath "$0")) SELF=$(realpath "$0")
MYDIR=$(dirname "${SELF}")
# Git revisions we use for the given submodules. Update these whenever you # Git revisions we use for the given submodules. Update these whenever you
# update a git submodule. # update a git submodule.
THIRD_PARTY_BROTLI="35ef5c554d888bef217d449346067de05e269b30" TESTDATA="873045a9c42ed60721756e26e2a6b32e17415205"
THIRD_PARTY_HIGHWAY="22e3d7276f4157d4a47586ba9fd91dd6303f441a" THIRD_PARTY_BROTLI="36533a866ed1ca4b75cf049f4521e4ec5fe24727"
THIRD_PARTY_SKCMS="64374756e03700d649f897dbd98c95e78c30c7da" THIRD_PARTY_GOOGLETEST="58d77fa8070e8cec2dc1ed015d66b454c8d78850"
THIRD_PARTY_SJPEG="868ab558fad70fcbe8863ba4e85179eeb81cc840" THIRD_PARTY_HIGHWAY="457c891775a7397bdb0376bb1031e6e027af1c48"
THIRD_PARTY_ZLIB="cacf7f1d4e3d44d871b605da3b647f07d718623f" THIRD_PARTY_SKCMS="42030a771244ba67f86b1c1c76a6493f873c5f91"
THIRD_PARTY_LIBPNG="a40189cf881e9f0db80511c382292a5604c3c3d1" THIRD_PARTY_SJPEG="e5ab13008bb214deb66d5f3e17ca2f8dbff150bf"
THIRD_PARTY_ZLIB="51b7f2abdade71cd9bb0e7a373ef2610ec6f9daf" # v1.3.1
THIRD_PARTY_LIBPNG="f135775ad4e5d4408d2e12ffcc71bb36e6b48551" # v1.6.40
THIRD_PARTY_LIBJPEG_TURBO="8ecba3647edb6dd940463fedf38ca33a8e2a73d1" # 2.1.5.1
# Download the target revision from GitHub. # Download the target revision from GitHub.
download_github() { download_github() {
@ -26,7 +30,7 @@ download_github() {
local project="$2" local project="$2"
local varname=`echo "$path" | tr '[:lower:]' '[:upper:]'` local varname=`echo "$path" | tr '[:lower:]' '[:upper:]'`
varname="${varname/\//_}" varname="${varname//[\/-]/_}"
local sha local sha
eval "sha=\${${varname}}" eval "sha=\${${varname}}"
@ -57,9 +61,16 @@ download_github() {
mv "${local_fn}.tmp" "${local_fn}" mv "${local_fn}.tmp" "${local_fn}"
} }
is_git_repository() {
local dir="$1"
local toplevel=$(git rev-parse --show-toplevel)
[[ "${dir}" == "${toplevel}" ]]
}
main() { main() {
if git -C "${MYDIR}" rev-parse; then if is_git_repository "${MYDIR}"; then
cat >&2 <<EOF cat >&2 <<EOF
Current directory is a git repository, downloading dependencies via git: Current directory is a git repository, downloading dependencies via git:
@ -71,13 +82,16 @@ EOF
fi fi
# Sources downloaded from a tarball. # Sources downloaded from a tarball.
download_github testdata libjxl/testdata
download_github third_party/brotli google/brotli 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/highway google/highway
download_github third_party/sjpeg webmproject/sjpeg download_github third_party/sjpeg webmproject/sjpeg
download_github third_party/skcms \ download_github third_party/skcms \
"https://skia.googlesource.com/skcms/+archive/" "https://skia.googlesource.com/skcms/+archive/"
download_github third_party/zlib madler/zlib download_github third_party/zlib madler/zlib
download_github third_party/libpng glennrp/libpng download_github third_party/libpng glennrp/libpng
download_github third_party/libjpeg-turbo libjpeg-turbo/libjpeg-turbo
echo "Done." echo "Done."
} }

View file

@ -14,13 +14,17 @@
@addtogroup libjxl @addtogroup libjxl
@{ @{
@defgroup libjxl_decoder JPEG XL Decoder @defgroup libjxl_decoder JPEG XL Decoder API
@defgroup libjxl_encoder JPEG XL Encoder @defgroup libjxl_encoder JPEG XL Encoder API
@defgroup libjxl_common JPEG XL common definitions @defgroup libjxl_common Common API concepts
@defgroup libjxl_butteraugli Butteraugli metric @defgroup libjxl_metadata Image and frame metadata
@defgroup libjxl_color Color encoding and conversion
@defgroup libjxl_cpp C++ helpers
@} @}

View file

@ -1,8 +1,7 @@
# Building and Testing # Building and Testing
This file describes the building and testing facilities provided by the `ci.sh` This file describes the building and testing facilities provided by the `ci.sh`
script. It assumes you already have the build environment set up, preferably script. It assumes you already have the build environment set up.
Docker (see [instructions](developing_in_docker.md)).
## Basic building ## Basic building
@ -62,11 +61,7 @@ environment variable in `./ci.sh`. For some targets such the Windows targets
`ci.sh` sets up extra environment variables that are needed for testing. `ci.sh` sets up extra environment variables that are needed for testing.
This assumes that you already have a cross-compiling environment set up and the This assumes that you already have a cross-compiling environment set up and the
library dependencies are already installed for the target architecture as well library dependencies are already installed for the target architecture as well.
which is tricky to do in some cases. For this reason we provide a [jpegxl docker
container](developing_in_docker.md) already configured to cross-compile and run
for other architectures which is also used in our continuous integration
pipeline.
For example, to compile for the `aarch64-linux-gnu` target triplet you can run: For example, to compile for the `aarch64-linux-gnu` target triplet you can run:
@ -92,9 +87,9 @@ Linter checks will verify that the format of your patch conforms to the project
style. For this, we run clang-format only on the lines that were changed by style. For this, we run clang-format only on the lines that were changed by
your commits. your commits.
If your local git branch is tracking `origin/master` and you landed a few If your local git branch is tracking `origin/main` and you landed a few
commits in your branch, running this lint command will check all the changes commits in your branch, running this lint command will check all the changes
made from the common ancestor with `origin/master` to the latest changes, made from the common ancestor with `origin/main` to the latest changes,
including uncommitted changes. The output of the program will show the patch including uncommitted changes. The output of the program will show the patch
that should be applied to fix your commits. You can apply these changes with the that should be applied to fix your commits. You can apply these changes with the
following command from the base directory of the git checkout: following command from the base directory of the git checkout:

View file

@ -4,15 +4,12 @@ This file describes the building and testing of JPEG XL
[Web Assembly](https://webassembly.org/) bundles and wrappers. [Web Assembly](https://webassembly.org/) bundles and wrappers.
These instructions assume an up-to-date Debian/Ubuntu system. These instructions assume an up-to-date Debian/Ubuntu system.
For other platforms, or if you encounter any difficulties,
please instead use the [Docker container](developing_in_docker.md).
For the sake of simplicity, it is considered, that the following environment For the sake of simplicity, it is considered, that the following environment
variables are set: variables are set:
* `OPT` - path to the directory containing additional software; * `OPT` - path to the directory containing additional software;
the `emsdk` directory with the Emscripten SDK should reside there; the `emsdk` directory with the Emscripten SDK should reside there.
in the Docker container (mentioned above) this should be `/opt`
## Requirements ## Requirements
@ -40,28 +37,6 @@ cd emsdk
./emsdk activate latest ./emsdk activate latest
``` ```
[v8](https://v8.dev/) is a JavaScript engine used for running tests.
v8 has better WASM SIMD support than NodeJS 14.
To install it use [JSVU](https://github.com/GoogleChromeLabs/jsvu):
```bash
# Fix some v8 version know to work well.
export v8_version="8.5.133"
# Install JSVU
npm install jsvu -g
# Trick JSVU to install to specific location instead of user "home".
# Note: "os" flag should match the host OS.
HOME=$OPT jsvu --os=linux64 "v8@${v8_version}"
# Link v8 binary to version-indepentent path.
ln -s "$OPT/.jsvu/v8-${v8_version}" "$OPT/.jsvu/v8"
```
In [Docker container](developing_in_docker.md)
CMake, Emscripten SDK and V8 are pre-installed.
## Building and testing the project ## Building and testing the project
```bash ```bash
@ -69,15 +44,19 @@ CMake, Emscripten SDK and V8 are pre-installed.
# $OPT/emsdk. # $OPT/emsdk.
source $OPT/emsdk/emsdk_env.sh source $OPT/emsdk/emsdk_env.sh
# Specify JS engine binary # This should set the $EMSDK variable.
export V8=$OPT/.jsvu/v8 # If your node version is <16.4.0, you might need to update to a newer version or override
# the node binary with a version which supports SIMD:
echo "NODE_JS='/path/to/node_binary'" >> $EMSDK/.emscripten
# If building using the jpegxl-builder docker container prefix the following commands with: # Assuming you are in the root level of the cloned libjxl repo,
# CMAKE_FLAGS=-I/usr/wasm32/include # either build with regular WASM:
# ex. CMAKE_FLAGS=-I/usr/wasm32/include BUILD_TARGET=wasm32 emconfigure ./ci.sh release
# Either build with regular WASM:
BUILD_TARGET=wasm32 emconfigure ./ci.sh release BUILD_TARGET=wasm32 emconfigure ./ci.sh release
# or with SIMD WASM: # or with SIMD WASM:
BUILD_TARGET=wasm32 ENABLE_WASM_SIMD=1 emconfigure ./ci.sh release BUILD_TARGET=wasm32 ENABLE_WASM_SIMD=1 emconfigure ./ci.sh release
``` ```
## Example site
Once you have build the wasm binary, you can give it a try by building a site
that decodes jxl images, see [wasm_demo](../tools/wasm_demo/README.md).

View file

@ -4,7 +4,7 @@
<!--* <!--*
# Document freshness: For more information, see go/fresh-source. # Document freshness: For more information, see go/fresh-source.
freshness: { owner: 'janwas' reviewed: '2019-02-01' } freshness: { owner: 'sboukortt' reviewed: '2022-09-27' }
*--> *-->
## Why ## Why

View file

@ -0,0 +1,71 @@
### Reasoning
Given the differences in compilers / environment it is not always clear why some
build / test fails in workflows. In this document we gather practices that
would help debugging workflows.
### Debugging workflows on GitHub
To connect to real workflow on GitHub one can use "tmate" plugin. To do that,
add the following snippet in workflow .yml:
```
- name: Setup tmate session
# Or other condition that pin-points a single strategy matrix item
if: failure()
uses: mxschmitt/action-tmate@a283f9441d2d96eb62436dc46d7014f5d357ac22 # v3.17
timeout-minutes: 15
```
When the plugin is executed it dumps to log a command to "ssh" to that instance.
NB: since session is wrapped in tmux, scrolling might be very inconvenient.
### Debugging build_test_cross.yml locally
"cross" workflows are executed in container, so those are easy to reproduce
locally. Here is a snippet that reflects how setup / compilation are (currently)
done in the workflow:
```
docker run -it -v`pwd`:/libjxl debian:bookworm bash
cd /libjxl
export ARCH=i386 # arm64 armhf
export MAIN_LIST="amd64,${ARCH}"
export BUILD_DIR=build
export CC=clang-14
export CXX=clang++-14
export BUILD_TARGET=i686-linux-gnu # aarch64-linux-gnu arm-linux-gnueabihf
rm -f /var/lib/man-db/auto-update
apt-get update -y
apt-get install -y ca-certificates debian-ports-archive-keyring python3
dpkg --add-architecture ${ARCH}
python3 ./tools/scripts/transform_sources_list.py "${MAIN_LIST}"
apt update
apt-get install -y \
clang-14 cmake doxygen g++-aarch64-linux-gnu graphviz libbrotli-dev:${ARCH} \
libc6-dev-${ARCH}-cross libgdk-pixbuf2.0-dev:${ARCH} libgif-dev:${ARCH} \
libgtk2.0-dev:${ARCH} libilmbase-dev:${ARCH} libjpeg-dev:${ARCH} \
libopenexr-dev:${ARCH} libpng-dev:${ARCH} libstdc++-12-dev-${ARCH}-cross \
libstdc++-12-dev:${ARCH} libwebp-dev:${ARCH} ninja-build pkg-config \
qemu-user-static unzip xdg-utils xvfb
#apt-get install -y binutils-${BUILD_TARGET} gcc-${BUILD_TARGET}
#apt-get install -y \
# libgoogle-perftools-dev:${ARCH} libgoogle-perftools4:${ARCH} \
# libtcmalloc-minimal4:${ARCH} libunwind-dev:${ARCH}
#export CMAKE_FLAGS="-march=armv8-a+sve"
SKIP_TEST=1 ./ci.sh release \
-DJPEGXL_FORCE_SYSTEM_BROTLI=ON \
-DJPEGXL_ENABLE_JNI=OFF
# -DCMAKE_CROSSCOMPILING_EMULATOR=/usr/bin/qemu-aarch64-static
# -DJPEGXL_ENABLE_OPENEXR=off
# -DJPEGXL_ENABLE_SIZELESS_VECTORS=on
# -DCMAKE_CXX_FLAGS=-DJXL_HIGH_PRECISION=0
```

View file

@ -3,7 +3,6 @@
These instructions assume an up-to-date Debian/Ubuntu system. These instructions assume an up-to-date Debian/Ubuntu system.
For other platforms, please instead use the following: For other platforms, please instead use the following:
* [Developing in Docker](developing_in_docker.md).
* [Cross Compiling for Windows with Crossroad](developing_with_crossroad.md). * [Cross Compiling for Windows with Crossroad](developing_with_crossroad.md).
## Minimum build dependencies ## Minimum build dependencies
@ -13,7 +12,8 @@ dependencies that need to be installed on your system first:
```bash ```bash
sudo apt install cmake clang doxygen g++ extra-cmake-modules \ sudo apt install cmake clang doxygen g++ extra-cmake-modules \
libgif-dev libjpeg-dev ninja-build libgoogle-perftools-dev libgif-dev libjpeg-dev ninja-build libgoogle-perftools-dev \
graphviz
``` ```
Make sure your default `clang` compiler is at least version 6 by running Make sure your default `clang` compiler is at least version 6 by running
@ -34,8 +34,8 @@ Optionally, to compile some of the extra tool support and tests you can install
the following packages: the following packages:
```bash ```bash
sudo apt install qtbase5-dev libqt5x11extras5-dev libwebp-dev libgimp2.0-dev \ sudo apt install qt6-base-dev libwebp-dev libgimp2.0-dev libopenexr-dev \
libopenexr-dev libgtest-dev libgmock-dev libbenchmark-dev libbenchmark-tools libgtest-dev libbenchmark-dev libbenchmark-tools
``` ```
For the lint/coverage commands, you will also need additional packages: For the lint/coverage commands, you will also need additional packages:

View file

@ -1,114 +0,0 @@
# Developing in Docker
Docker allows software to be run in a packaged container, isolated from the
host system. This allows code to be run in a standard environment instead
of dealing with different build environments during development. It also
simplifies resolving external dependencies by including them in the automated
setup of the container environment.
## Set up the container
You can read installation instructions and download Docker for your
operating system at [Get Docker](https://docs.docker.com/get-docker/).
The image used by our builders is an Ubuntu Bionic image with all the
required dependencies and build tools installed. You can pull this image
from `gcr.io/jpegxl/jpegxl-builder` using the following command:
```bash
sudo docker pull gcr.io/jpegxl/jpegxl-builder
```
To use the Docker image you can run the following command:
```bash
sudo docker run -it --rm \
--user $(id -u):$(id -g) \
-v $HOME/jpeg-xl:/jpeg-xl -w /jpeg-xl \
gcr.io/jpegxl/jpegxl-builder bash
```
This creates and runs a container that will be deleted after you exit the
terminal (`--rm` flag).
The `-v` flag is to map the directory containing your jpeg-xl checkout in your
host (assumed to be at `$HOME/jpeg-xl`) to a directory inside the container at
/jpeg-xl. Since the container is accessing the host folder directly,
changes made on the host will will be seen immediately in the container,
and vice versa.
On OSX, the path must be one of those shared and whitelisted with Docker. $HOME
(which is a subdirectory of /Users/) is known to work with the factory-default
settings of Docker.
On OSX, you may ignore the warning that Docker "cannot find name for group ID".
This warning may also appear on some Linux computers.
On Windows, you can run the following from the jpeg-xl directory obtained from
Gitlab:
```bash
docker run -u root:root -it --rm -v %cd%:/jpeg-xl -w /jpeg-xl \
gcr.io/jpegxl/jpegxl-builder
```
## Basic building
Inside the Docker container, you can compile everything and run unit tests.
We need to specify `clang-7` because the default `clang` compiler is
not installed on the image.
```bash
CC=clang-7 CXX=clang++-7 ./ci.sh opt
```
This writes binaries to `/jpeg-xl/build/tools` and runs unit tests.
More information on [build modes and testing](building_and_testing.md) is
available.
If a `build` directory already exists and was configured for a different
compiler, `cmake` will complain. This can be avoided by renaming or removing
the existing `build` directory or setting the `BUILD_DIR` environment variable.
## Cross-compiling environments (optional)
We have installed the required cross-compiling tools in the main Docker image
`jpegxl-builder`. This allows compiling for other architectures, such as arm.
Tests will be emulated under `qemu`.
The Docker container has several `qemu-*-static` binaries (such as
`qemu-aarch64-static`) that emulate other architectures on x86_64. These
binaries are automatically used when running foreign architecture programs
in the container only if `binfmt` is installed and configured on the *host*
to use binaries from `/usr/bin` . This is the default location on Ubuntu/Debian.
You need to install both `binfmt-support` and `qemu-user-static` on the host,
since `binfmt-support` configures only `binfmt` signatures of architectures
that are installed. If these are configured elsewhere on other distributions,
you can symlink them to `/usr/bin/qemu-*-static` inside the Docker container.
To install binfmt support in your Ubuntu host run *outside* the container:
```bash
sudo apt install binfmt-support qemu-user-static
```
Then to cross-compile and run unit tests execute the following commands:
```bash
export BUILD_TARGET=aarch64-linux-gnu CC=clang-7 CXX=clang++-7
./ci.sh release
```
The `BUILD_TARGET=aarch64-linux-gnu` environment variable tells the `ci.sh`
script to cross-compile for that target. This also changes the default
`BUILD_DIR` to `build-aarch64` since you never want to mix them with the `build`
of your host. You can also explicitly set a `BUILD_DIR` environment variable
that will be used instead. The list of supported `BUILD_TARGET` values for this
container is:
* *the empty string* (for native x86_64 support)
* aarch64-linux-gnu
* arm-linux-gnueabihf
* i686-linux-gnu
* x86_64-w64-mingw32 (for Windows builds)

View file

@ -17,7 +17,7 @@ After that "Life of a Pull Request" describes the common everyday workflows.
### Configure your SSH access ### Configure your SSH access
The easiest way to configure access to your Github repository is to use SSH The easiest way to configure access to your GitHub repository is to use SSH
keys. For that you need an SSH private and public key, ideally a strong one. You keys. For that you need an SSH private and public key, ideally a strong one. You
can use different keys for different sites if you want. In this example, we will can use different keys for different sites if you want. In this example, we will
create one for using in GitHub only. create one for using in GitHub only.
@ -93,7 +93,7 @@ fork. You can use any other name for your fork if you want. Use the following
commands to set things up, replacing `{{USERNAME}}` with your GitHub username: commands to set things up, replacing `{{USERNAME}}` with your GitHub username:
```bash ```bash
git clone git https://github.com/libjxl/libjxl --recursive git clone https://github.com/libjxl/libjxl --recursive
cd libjxl cd libjxl
git remote set-url --push origin git@github.com:{{USERNAME}}/libjxl.git git remote set-url --push origin git@github.com:{{USERNAME}}/libjxl.git
git remote add myfork git@github.com:{{USERNAME}}/libjxl.git git remote add myfork git@github.com:{{USERNAME}}/libjxl.git
@ -231,7 +231,7 @@ git push origin mybranch
This will push your local branch "mybranch" to a remote in your fork called This will push your local branch "mybranch" to a remote in your fork called
"mybranch". The name can be anything, but keep in mind that it is public. A link "mybranch". The name can be anything, but keep in mind that it is public. A link
to the URL to create a merge request will be displayed. to the URL to create a pull request will be displayed.
``` ```
Enumerating objects: 627, done. Enumerating objects: 627, done.
@ -309,7 +309,7 @@ In that case, you can use the force flag:
git submodule update --init --recursive --force git submodule update --init --recursive --force
``` ```
### Iterating changes in your merge request ### Iterating changes in your pull request
To address reviewer changes you need to amend the local changes in your branch To address reviewer changes you need to amend the local changes in your branch
first. Make the changes you need in your commit locally by running `git commit first. Make the changes you need in your commit locally by running `git commit
@ -325,7 +325,7 @@ ones), you need to force the operation to replace the old version.
git push origin mybranch --force git push origin mybranch --force
``` ```
The merge request should now be updated with the new changes. The pull request should now be updated with the new changes.
### Merging your changes ### Merging your changes
@ -342,7 +342,7 @@ verify that all the tests pass again after including the latest changes.
### Trying locally a pending Pull Request ### Trying locally a pending Pull Request
If you want to review in your computer a pending pull request proposed by If you want to review in your computer a pending pull request proposed by
another user you can fetch the merge request commit with the following command, another user you can fetch the pull request commit with the following command,
replacing `NNNN` with the pull request number: replacing `NNNN` with the pull request number:
```bash ```bash

View file

@ -4,7 +4,6 @@ These instructions assume an up-to-date Windows 10 (e.g. build 19041.928) with
**Microsoft Visual Studio 2019** (e.g. Version 16.9.0 Preview 4.0) installed. If **Microsoft Visual Studio 2019** (e.g. Version 16.9.0 Preview 4.0) installed. If
unavailable, please use another build environment: unavailable, please use another build environment:
* [Docker container](developing_in_docker.md)
* [MSYS2 on Windows](developing_in_windows_msys.md) * [MSYS2 on Windows](developing_in_windows_msys.md)
* [Crossroad on Linux](developing_with_crossroad.md) (cross compilation for Windows) * [Crossroad on Linux](developing_with_crossroad.md) (cross compilation for Windows)
@ -59,11 +58,6 @@ vcpkg above.
"value": "False", "value": "False",
"type": "BOOL" "type": "BOOL"
}, },
{
"name": "BUILD_GMOCK",
"value": "True",
"type": "BOOL"
},
{ {
"name": "gtest_force_shared_crt", "name": "gtest_force_shared_crt",
"value": "True", "value": "True",

View file

@ -0,0 +1,32 @@
# Encode effort settings
Various trade-offs between encode speed and compression performance can be selected in libjxl. In `cjxl`, this is done via the `--effort` (`-e`) option.
Higher effort means slower encoding; generally the higher the effort, the more coding tools are used, computationally more expensive heuristics are used,
and more exhaustive search is performed.
Generally efforts range between `1` and `9`, but there is also `e10` you pass the flag `--allow_expert_options` (in combination with "lossless", i.e. `-d 0`). It is considered an expert option because it can be extremely slow.
For lossy compression, higher effort results in better visual quality at a given filesize, and also better
encoder consistency, i.e. less image-dependent variation in the actual visual quality that is achieved. This means that for lossy compression,
higher effort does not necessarily mean smaller filesizes for every image — some images may be somewhat lower quality than desired when using
lower effort heuristics, and to improve consistency, higher effort heuristics may decide to use more bytes for them.
For lossless compression, higher effort should result in smaller filesizes, although this is not guaranteed;
in particular, e2 can be better than e3 for non-photographic images, and e3 can be better than e4 for photographic images.
The following table describes what the various effort settings do:
|Effort | Modular (lossless) | VarDCT (lossy) |
|-------|--------------------|----------------|
| e1 | fast-lossless, fixed YCoCg RCT, fixed ClampedGradient predictor, simple palette detection, no MA tree (one context for everything), Huffman, simple rle-only lz77 | |
| e2 | global channel palette, fixed MA tree (context based on Gradient-error), ANS, otherwise same as e1 | |
| e3 | same as e2 but fixed Weighted predictor and fixed MA tree with context based on WP-error | only 8x8, basically XYB jpeg with ANS |
| e4 | try both ClampedGradient and Weighted predictor, learned MA tree, global palette | simple variable blocks heuristics, adaptive quantization, coefficient reordering |
| e5 | e4 + patches, local palette / local channel palette, different local RCTs | e4 + gabor-like transform, chroma from luma |
| e6 | e5 + more RCTs and MA tree properties | e5 + error diffusion, full variable blocks heuristics |
| e7 | e6 + more RCTs and MA tree properties | e6 + patches (including dots) |
| e8 | e7 + more RCTs, MA tree properties and Weighted predictor parameters | e7 + Butteraugli iterations for adaptive quantization |
| e9 | e8 + more RCTs, MA tree properties and Weighted predictor parameters, try all predictors | e8 + more Butteraugli iterations |
| e10 | e9 + previous-channel MA tree properties, different group dimensions, exhaustively try various e9 options | |
For the entropy coding (context clustering, lz77 search, hybriduint configuration): slower/more exhaustive search as effort goes up.

View file

@ -103,7 +103,7 @@ clang package for that version outside the container and using `clang-NN`
(for example `clang-11`) instead of `clang` in the following commands: (for example `clang-11`) instead of `clang` in the following commands:
```bash ```bash
symbolizer=$($(realpath $(which clang)) -print-prog-name=llvm-symbolizer) symbolizer=$($(realpath "$(which clang)") -print-prog-name=llvm-symbolizer)
export MSAN_SYMBOLIZER_PATH="${symbolizer}" export MSAN_SYMBOLIZER_PATH="${symbolizer}"
export UBSAN_SYMBOLIZER_PATH="${symbolizer}" export UBSAN_SYMBOLIZER_PATH="${symbolizer}"
export ASAN_SYMBOLIZER_PATH="${symbolizer}" export ASAN_SYMBOLIZER_PATH="${symbolizer}"
@ -135,16 +135,9 @@ perform an invalid operation (read/write out of bounds, perform an undefined
behavior operation, etc). You can help the fuzzer find invalid situations by behavior operation, etc). You can help the fuzzer find invalid situations by
adding asserts: adding asserts:
* `JXL_ASSERT()` is enabled in Release mode by default. It can be disabled * `JXL_DASSERT` is only enabled in Debug builds, which includes all the ASan,
with `-DJXL_ENABLE_ASSERT=0` but the intention is that it will run for all
the users in released code. If performance of the check is not an issue (like
checks done once per image, once per channel, once per group, etc) a
JXL_ASSERT is appropriate. A failed assert is preferable to an out of bounds
write.
* `JXL_DASSERT()` is only enabled in Debug builds, which includes all the ASan,
MSan and UBSan builds. Performance of these checks is not an issue if kept MSan and UBSan builds. Performance of these checks is not an issue if kept
within reasonable limits (automated msan/asan test should finish withing 1 within reasonable limits (automated msan/asan test should finish within 1
hour for example). Fuzzing is more effective when the given input runs hour for example). Fuzzing is more effective when the given input runs
faster, so keep that in mind when adding a complex DASSERT that runs multiple faster, so keep that in mind when adding a complex DASSERT that runs multiple
times per output pixel. times per output pixel.

View file

@ -29,7 +29,7 @@ number. Released tags don't each one have their own release branch, all releases
from the same MAJOR.MINOR version will share the same branch. The first commit from the same MAJOR.MINOR version will share the same branch. The first commit
after the branch-off points between the main branch and the release branch after the branch-off points between the main branch and the release branch
should be tagged with the suffix `-snapshot` and the name of the next should be tagged with the suffix `-snapshot` and the name of the next
MAJOR.MINOR version, in order to get meaningful ouput for `git --describe`. MAJOR.MINOR version, in order to get meaningful output for `git describe`.
The main purpose of the release branch is to stabilize the code before a The main purpose of the release branch is to stabilize the code before a
release. This involves including fixes to existing bugs but **not** including release. This involves including fixes to existing bugs but **not** including
@ -93,6 +93,15 @@ branches](https://docs.github.com/en/github/administering-a-repository/defining-
in our repository, however you can push to a protected branch when *creating* it in our repository, however you can push to a protected branch when *creating* it
but you can't directly push to it after it is created. To include more changes but you can't directly push to it after it is created. To include more changes
in the release branch see the "Cherry-picking fixes to a release" section below. in the release branch see the "Cherry-picking fixes to a release" section below.
Remember to tag the first commit in the `main` branch after the branch of point
with the suffix `-snapshot`, so for instances, if you just made the
branch `v0.5.x`, run
```
git checkout [hash of first commit after the branch off point]
git tag v0.5-snapshot
git push git@github.com:libjxl/libjxl.git v0.5-snapshot
```
## Creating a merge label ## Creating a merge label
@ -128,10 +137,12 @@ To help update it, run this helper command (in a Debian-based system):
This will update the version in the following files: This will update the version in the following files:
* `lib/CMakeLists.txt` * `lib/CMakeLists.txt`
* `lib/lib.gni`, automatically updated with `tools/build_cleaner.py --update`. * `lib/lib.gni`, automatically updated with
`tools/scripts/build_cleaner.py --update`.
* `debian/changelog` to create the Debian package release with the new version. * `debian/changelog` to create the Debian package release with the new version.
Debian changelog shouldn't repeat the library changelog, instead it should Debian changelog shouldn't repeat the library changelog, instead it should
include changes to the packaging scripts. include changes to the packaging scripts.
* `.github/workflows/conformance.yml`
If there were incompatible API/ABI changes, make sure to also adapt the If there were incompatible API/ABI changes, make sure to also adapt the
corresponding section in corresponding section in
@ -180,6 +191,15 @@ commits you need to cherry-pick, ideally in the same order they were merged on
the `main` branch. At the end you will have a local branch with multiple commits the `main` branch. At the end you will have a local branch with multiple commits
on top of the release branch. on top of the release branch.
To update the version number, for example from v0.8.0 to v0.8.1 run this helper
command (in a Debian-based system):
```bash
./ci.sh bump_version 0.8.1
```
as described above and commit the changes.
Finally, upload your changes to *your fork* like normal, except that when Finally, upload your changes to *your fork* like normal, except that when
creating a pull request select the desired release branch as a target: creating a pull request select the desired release branch as a target:
@ -263,5 +283,67 @@ instructions:
the release itself that are not included in the CHANGELOG.md, although prefer the release itself that are not included in the CHANGELOG.md, although prefer
to include those in the CHANGELOG.md file. You can switch to the Preview tab to include those in the CHANGELOG.md file. You can switch to the Preview tab
to see the results. to see the results.
* Copy-paste the following note:
```markdown
**Note:** This release is for evaluation purposes and may contain bugs, including security bugs, that may not be individually documented when fixed. See the [SECURITY.md](SECURITY.md) file for details. Always prefer to use the latest release.
Please provide feedback and report bugs [here](https://github.com/libjxl/libjxl/issues).
```
* Finally click "Publish release" and go celebrate with the team. 🎉 * Finally click "Publish release" and go celebrate with the team. 🎉
* The branch v0.7.x will be pushed to gitlab automatically, but make sure to
manually push the *tag* of the release also to
https://gitlab.com/wg1/jpeg-xl, by doing configuring `gitlab` to be the remote `git@gitlab.com:wg1/jpeg-xl.git` and then running:
```bash
git push gitlab v0.7.1
```
and possibly also push the tag for the snapshot to gitlab, if it wasn't done yet:
```bash
git push gitlab v0.7-snapshot
```
### How to build downstream projects
```bash
docker run -it debian:bookworm /bin/bash
apt update
apt install -y clang cmake git libbrotli-dev nasm pkg-config ninja-build
export CC=clang
export CXX=clang++
mkdir -p /src
cd /src
git clone --recurse-submodules --depth 1 -b v0.9.x \
https://github.com/libjxl/libjxl.git
git clone --recurse-submodules --depth 1 \
https://github.com/ImageMagick/ImageMagick.git
git clone --recurse-submodules --depth 1 \
https://github.com/FFmpeg/FFmpeg.git
cd /src/libjxl
cmake -B build -G Ninja .
cmake --build build -j`nproc`
cmake --install build --prefix="/usr"
cd /src/ImageMagick
./configure --with-jxl=yes
# check for "JPEG XL --with-jxl=yes yes"
make -j `nproc`
./utilities/magick -version
cd /src/FFmpeg
./configure --disable-all --disable-debug --enable-avcodec --enable-avfilter \
--enable-avformat --enable-libjxl --enable-encoder=libjxl \
--enable-decoder=libjxl --enable-ffmpeg
# check for libjxl decoder/encoder support
make -j `nproc`
ldd ./ffmpeg
./ffmpeg -version
```

View file

@ -12,20 +12,34 @@ Please add missing software to this list.
## Browsers ## Browsers
- Chromium: behind a flag since version 91, [tracking bug](https://bugs.chromium.org/p/chromium/issues/detail?id=1178058) - Chromium: behind a flag from version 91 to 109, [tracking bug](https://bugs.chromium.org/p/chromium/issues/detail?id=1178058)
- Firefox: behind a flag since version 90, [tracking bug](https://bugzilla.mozilla.org/show_bug.cgi?id=1539075) - Firefox: behind a flag since version 90, [tracking bug](https://bugzilla.mozilla.org/show_bug.cgi?id=1539075)
- Safari: not supported, [tracking bug](https://bugs.webkit.org/show_bug.cgi?id=208235) - Safari: supported since version 17 [release notes](https://developer.apple.com/documentation/safari-release-notes/safari-17-release-notes), [tracking bug](https://bugs.webkit.org/show_bug.cgi?id=208235)
- Edge: behind a flag since version 91, start with `.\msedge.exe --enable-features=JXL` - Edge: behind a flag since version 91, start with `.\msedge.exe --enable-features=JXL`
- Opera: behind a flag since version 77. - Opera: behind a flag since version 77.
- For all browsers and to track browsers progress see [Can I Use](https://caniuse.com/jpegxl). - Basilisk: supported since version v2023.01.07, [release notes](https://www.basilisk-browser.org/releasenotes.shtml)
- Pale Moon: supported since version 31.4.0, [release notes](https://www.palemoon.org/releasenotes-archived.shtml#v31.4.0)
- Waterfox: [enabled by default](https://github.com/WaterfoxCo/Waterfox/pull/2936)
For all browsers and to track browsers progress see [Can I Use](https://caniuse.com/jpegxl).
## Image libraries ## Image libraries
- [ImageMagick](https://imagemagick.org/): supported since 7.0.10-54 - [ImageMagick](https://imagemagick.org/): supported since 7.0.10-54
- [libvips](https://libvips.github.io/libvips/): supported since 8.11 - [libvips](https://libvips.github.io/libvips/): supported since 8.11
- [Imlib2](https://github.com/alistair7/imlib2-jxl) - [Imlib2](https://docs.enlightenment.org/api/imlib2/html/)
- [FFmpeg](https://github.com/FFmpeg/FFmpeg/search?q=jpeg-xl&type=commits) - [FFmpeg](https://github.com/FFmpeg/FFmpeg/search?q=jpeg-xl&type=commits)
- [GDAL](https://gdal.org/drivers/raster/jpegxl.html): supported since 3.4.0 as a TIFF codec, and 3.6.0 as standalone format - [GDAL](https://gdal.org/drivers/raster/jpegxl.html): supported since 3.4.0 as a TIFF codec, and 3.6.0 as standalone format
- [GraphicsMagick](http://www.graphicsmagick.org/NEWS.html#march-26-2022): supported since 1.3.38
- [SAIL](https://sail.software): supported since 0.9.0
- [JPEG XL Coder](https://github.com/awxkee/jxl-coder): Supports version from Android 5.0 (API Level 21)
- [SDWebImageJPEGXLCoder](https://github.com/SDWebImage/SDWebImageJPEGXLCoder): supported since 0.1.0
## Metadata manipulation libraries
- [ExifTool by Phil Harvey](https://exiftool.org/): supported since 12.25
- [Exiv2](https://exiv2.org): supported since 0.27.4
- [Ashampoo Kim](https://github.com/ashampoo/kim): supported since 0.10
## OS-level support / UI frameworks / file browser plugins ## OS-level support / UI frameworks / file browser plugins
@ -41,25 +55,43 @@ Please add missing software to this list.
## Image editors ## Image editors
- [Adobe Camera Raw (since version 15)](https://helpx.adobe.com/camera-raw/using/hdr-output.html)
- [Affinity (since V2)](https://affinity.serif.com/en-gb/whats-new/)
- [darktable (since 4.2)](https://github.com/darktable-org/darktable/releases/tag/release-4.2.0)
- [GIMP (since 2.99.8)](https://www.gimp.org/news/2021/10/20/gimp-2-99-8-released/); plugin for older versions available in libjxl repo - [GIMP (since 2.99.8)](https://www.gimp.org/news/2021/10/20/gimp-2-99-8-released/); plugin for older versions available in libjxl repo
- [Graphic Converter (since 11.5)](https://www.lemkesoft.de/en/products/graphicconverter/)
- [Krita](https://invent.kde.org/graphics/krita/-/commit/13e5d2e5b9f0eac5c8064b7767f0b62264a0797b) - [Krita](https://invent.kde.org/graphics/krita/-/commit/13e5d2e5b9f0eac5c8064b7767f0b62264a0797b)
- [Paint.NET](https://www.getpaint.net/index.html); supported since 4.3.12 - requires a [plugin](https://github.com/0xC0000054/pdn-jpegxl) to be downloaded and installed.
- Photoshop: no plugin available yet, no official support yet - Photoshop: no plugin available yet, no official support yet
- [XL Converter](https://github.com/JacobDev1/xl-converter)
- [Image Toolbox (supported since 2.6.0)](https://github.com/T8RIN/ImageToolbox)
- [JPEG XL Toolbox by SUIKA LTD](https://apps.apple.com/app/jpeg-xl-toolbox/id6470681357)
- [RawTherapee (since 5.11)](https://github.com/Beep6581/RawTherapee); Currently only opening of JXL files is supported. [Exporting is expected for the 6.0 release](https://github.com/Beep6581/RawTherapee/pull/7097)
## Image viewers ## Image viewers
- [XnView](https://www.xnview.com/en/) - [Aspect](https://aspect.bildhuus.com)
- [ImageGlass](https://imageglass.org/) - [ImageGlass](https://imageglass.org/)
- [IrfanView](https://www.irfanview.com/); supported since 4.59 - requires a [plugin](https://www.irfanview.com/plugins.htm) to be downloaded and enabled. - [IrfanView](https://www.irfanview.com/); supported since 4.59 - requires a [plugin](https://www.irfanview.com/plugins.htm) to be downloaded and enabled.
- [jpegview](https://github.com/sylikc/jpegview/releases)
- [Swayimg](https://github.com/artemsen/swayimg)
- [Tachiyomi](https://github.com/tachiyomiorg/tachiyomi/releases/tag/v0.12.1) - [Tachiyomi](https://github.com/tachiyomiorg/tachiyomi/releases/tag/v0.12.1)
- [XnView](https://www.xnview.com/en/)
- Any viewer based on Qt, KDE, GDK-pixbuf, EFL, ImageMagick, libvips or imlib2 (see above) - Any viewer based on Qt, KDE, GDK-pixbuf, EFL, ImageMagick, libvips or imlib2 (see above)
- Qt viewers: gwenview, digiKam, KolourPaint, KPhotoAlbum, LXImage-Qt, qimgv, qView, nomacs, VookiImageViewer, PhotoQt - Qt viewers: gwenview, digiKam, KolourPaint, KPhotoAlbum, LXImage-Qt, qimgv, qView, nomacs, VookiImageViewer, PhotoQt
- GTK viewers: Eye of Gnome (eog), gThumb, Geeqie - GTK viewers: Eye of Gnome (eog), gThumb, Geeqie
- EFL viewers: entice, ephoto - EFL viewers: entice, ephoto
- [Swayimg](https://github.com/artemsen/swayimg)
## Duplicate image finders
- [AntiDupl.NET](https://github.com/ermig1979/AntiDupl/releases)
## Online tools ## Online tools
- [Gumlet](https://www.gumlet.com/blog/jpeg-xl/)
- [Squoosh](https://squoosh.app/) - [Squoosh](https://squoosh.app/)
- [Cloudinary](https://cloudinary.com/blog/cloudinary_supports_jpeg_xl) - [Cloudinary](https://cloudinary.com/blog/cloudinary_supports_jpeg_xl)
- [MConverter](https://mconverter.eu/) - [MConverter](https://mconverter.eu/)
- [jpegxl.io](https://jpegxl.io/) - [jpegxl.io](https://jpegxl.io/)
- [EXIF Viewer](https://stefan-oltmann.de/exif-viewer)
- [Immich](https://immich.app/), a self-hosted image gallery service

View file

@ -1,5 +1,5 @@
API reference libjxl API reference
============= ====================
``libjxl`` exposes a C API for encoding and decoding JPEG XL files with some ``libjxl`` exposes a C API for encoding and decoding JPEG XL files with some
C++ header-only helpers for C++ users. C++ header-only helpers for C++ users.
@ -11,5 +11,7 @@ C++ header-only helpers for C++ users.
api_decoder api_decoder
api_encoder api_encoder
api_common api_common
api_butteraugli api_metadata
api_color
api_threads api_threads
api_cpp

View file

@ -1,6 +0,0 @@
Butteraugli API - ``jxl/butteraugli.h``
=======================================
.. doxygengroup:: libjxl_butteraugli
:members:
:private-members:

View file

@ -0,0 +1,6 @@
Color encoding and conversion
=============================
.. doxygengroup:: libjxl_color
:members:
:private-members:

View file

@ -0,0 +1,6 @@
C++ helpers
===========
.. doxygengroup:: libjxl_cpp
:members:
:private-members:

View file

@ -0,0 +1,6 @@
Image and frame metadata
========================
.. doxygengroup:: libjxl_metadata
:members:
:private-members:

View file

@ -1,6 +0,0 @@
#### Table M.8 – "Adobe" marker template
```
0xEE, 0x00, 0x0E, 0x41, 0x64, 0x6F, 0x62, 0x65, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x01
```

File diff suppressed because it is too large Load diff

View file

@ -1,11 +0,0 @@
#!/usr/bin/env bash
# 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.
cat dct_gen.md \
is_zero_base.md num_nonzeros_base.md brn_proto.md app0.md icc.md ducky.md \
adobe.md stock_counts.md stock_values.md symbol_order.md stock_quant.md \
quant.md freq_context.md num_nonzero_context.md nonzero_buckets.md \
context_modes.md > all_tables.md

View file

@ -1,6 +0,0 @@
#### Table M.4 – APP0 template
```
0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00
```

View file

@ -1,23 +0,0 @@
#### Table M.3 – Protocol Buffer descriptor of top-level structure of losslessly compressed JPEG stream
```protobuf
message Header {
optional uint64 width = 1;
optional uint64 height = 2;
required uint64 version_and_component_count_code = 3;
optional uint64 subsampling_code = 4;
}
message Jpeg {
required bytes signature = 1;
required Header header = 2;
optional bytes meta_data = 3;
optional bytes jpeg1_internals = 4;
optional bytes quant_data = 5;
optional bytes histogram_data = 6;
optional bytes dc_data = 7;
optional bytes ac_data = 8;
optional bytes original_jpg = 9;
}
```

View file

@ -1,13 +0,0 @@
#### Table M.29 – context_modes table
```
0, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,
0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0,
0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0
```
```
0, 1, 1, 1, 1, 0, 0, 0, 2, 3, 1, 1, 1, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0,
0, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
```

View file

@ -1,241 +0,0 @@
#### Electronic Insert I.1 – DCT-II / DCT-III code generator
```python
#######################################################################
# DCT-II / DCT-III generator
#
# Based on:
# "A low multiplicative complexity fast recursive DCT-2 algorithm"
# by Maxim Vashkevich and Alexander Petrovsky / arXiv / 20 Jul 2012
#######################################################################
import math
import sys
N = 8
#######################################################################
# Base transforms / generators
#######################################################################
CNTR = 0
def makeTmp():
global CNTR
result = "t{:02d}".format(CNTR)
CNTR = CNTR + 1
return result
def makeVar(i):
return "i{:02d}".format(i)
def add(x, y):
tmp = makeTmp()
print(tmp + " = " + x + " + " + y + ";")
return tmp
def sub(x, y):
tmp = makeTmp()
print(tmp + " = " + x + " - " + y + ";")
return tmp
def mul(x, c):
tmp = makeTmp()
print(tmp + " = " + x + " * " + c + ";")
return tmp
# 2.0 * math.cos((a + 0.0) / (b + 0.0) * math.pi)
def C2(a, b):
return "c_c2_" + str(a) + "_" + str(b)
# 1.0 / C2(a, b)
def iC2(a, b):
return "c_ic2_" + str(a) + "_" + str(b)
#######################################################################
# Utilities
#######################################################################
# Generate identity matrix. Usually this matrix is passed to
# DCT algorithm to generate "basis" vectors of the transform.
def makeVars():
return [makeVar(i) for i in range(N)]
# Split list of variables info halves.
def split(x):
m = len(x)
m2 = m // 2
return (x[0 : m2], x[m2 : m])
# Make a list of variables in a reverse order.
def reverse(varz):
m = len(varz)
result = [0] * m
for i in range(m):
result[i] = varz[m - 1 - i]
return result
# Apply permutation
def permute(x, p):
return [x[p[i]] for i in range(len(p))]
def transposePermutation(p):
n = len(p)
result = [0] * n
for i in range(n):
result[p[i]] = i
return result
# See paper. Split even-odd elements.
def P(n):
if n == 1:
return [0]
n2 = n // 2
return [2 * i for i in range(n2)] + [2 * i + 1 for i in range(n2)]
# See paper. Interleave first and second half.
def Pt(n):
return transposePermutation(P(n))
#######################################################################
# Scheme
#######################################################################
def B2(x):
n = len(x)
n2 = n // 2
if n == 1:
raise "ooops"
(top, bottom) = split(x)
bottom = reverse(bottom)
t = [add(top[i], bottom[i]) for i in range(n2)]
b = [sub(top[i], bottom[i]) for i in range(n2)]
return t + b
def iB2(x):
n = len(x)
n2 = n // 2
if n == 1:
raise "ooops"
(top, bottom) = split(x)
t = [add(top[i], bottom[i]) for i in range(n2)]
b = [sub(top[i], bottom[i]) for i in range(n2)]
return t + reverse(b)
def B4(x, rn):
n = len(x)
n2 = n // 2
if n == 1:
raise "ooops"
(top, bottom) = split(x)
rbottom = reverse(bottom)
t = [sub(top[i], rbottom[i]) for i in range(n2)]
b = [mul(bottom[i], C2(rn, 2 * N)) for i in range(n2)]
top = [add(t[i], b[i]) for i in range(n2)]
bottom = [sub(t[i], b[i]) for i in range(n2)]
return top + bottom
def iB4(x, rn):
n = len(x)
n2 = n // 2
if n == 1:
raise "ooops"
(top, bottom) = split(x)
t = [add(top[i], bottom[i]) for i in range(n2)]
b = [sub(top[i], bottom[i]) for i in range(n2)]
bottom = [mul(b[i], iC2(rn, 2 * N)) for i in range(n2)]
rbottom = reverse(bottom)
top = [add(t[i], rbottom[i]) for i in range(n2)]
return top + bottom
def P4(n):
if n == 1:
return [0]
if n == 2:
return [0, 1]
n2 = n // 2
result = [0] * n
tc = 0
bc = 0
i = 0
result[i] = tc; tc = tc + 1; i = i + 1
turn = True
while i < n - 1:
if turn:
result[i] = n2 + bc; bc = bc + 1; i = i + 1
result[i] = n2 + bc; bc = bc + 1; i = i + 1
else:
result[i] = tc; tc = tc + 1; i = i + 1
result[i] = tc; tc = tc + 1; i = i + 1
turn = not turn
result[i] = tc; tc = tc + 1; i = i + 1
return result
def iP4(n):
return transposePermutation(P4(n))
def d2n(x):
n = len(x)
if n == 1:
return x
y = B2(x)
(top, bottom) = split(y)
return permute(d2n(top) + d4n(bottom, N // 2), Pt(n))
def id2n(x):
n = len(x)
if n == 1:
return x
(top, bottom) = split(permute(x, P(n)))
return iB2(id2n(top) + id4n(bottom, N // 2))
def d4n(x, rn):
n = len(x)
if n == 1:
return x
y = B4(x, rn)
(top, bottom) = split(y)
rn2 = rn // 2
return permute(d4n(top, rn2) + d4n(bottom, N - rn2), P4(n))
def id4n(x, rn):
n = len(x)
if n == 1:
return x
(top, bottom) = split(permute(x, iP4(n)))
rn2 = rn // 2
y = id4n(top, rn2) + id4n(bottom, N -rn2)
return iB4(y, rn)
#######################################################################
# Main.
#######################################################################
def help():
print("Usage: %s [N [T]]" % sys.argv[0])
print(" N should be the power of 2, default is 8")
print(" T is one of {2, 3}, default is 2")
sys.exit()
def parseInt(s):
try:
return int(s)
except ValueError:
help()
if __name__ == "__main__":
if len(sys.argv) < 1 or len(sys.argv) > 3: help()
if len(sys.argv) >= 2:
N = parseInt(sys.argv[1])
if (N & (N - 1)) != 0: help()
type = 0
if len(sys.argv) >= 3:
typeOption = sys.argv[2]
if len(typeOption) != 1: help()
type = "23".index(typeOption)
if type == -1: help()
if type == 0:
vars = d2n(makeVars())
else: # type == 1
vars = id2n(makeVars())
print("Output vector: " + str(vars))
```

View file

@ -1,6 +0,0 @@
#### Table M.7 – "Ducky" marker template
```
0xEC, 0x00, 0x11, 0x44, 0x75, 0x63, 0x6B, 0x79, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00
```

View file

@ -1,54 +0,0 @@
#### Table M.15 – freq_context
`scheme == 0`:
```
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
```
`scheme == 1`:
```
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0
```
`scheme == 2`:
```
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1
```
`scheme == 3`:
```
0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2
```
`scheme == 4`:
```
0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,
9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13,
13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15
```
`scheme == 5`:
```
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16,
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 24, 24,
25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29,
29, 29, 30, 30, 30, 30, 31, 31, 31, 31
```
`scheme == 6`:
```
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
54, 55, 56, 57, 58, 59, 60, 61, 62, 63
```

File diff suppressed because one or more lines are too long

View file

@ -1,9 +0,0 @@
#### Table M.1 – is_zero_base table
```
228, 216, 216, 195, 192, 189, 182, 184, 179, 176, 171, 168, 166, 159,
156, 151, 151, 150, 150, 146, 144, 138, 138, 137, 135, 131, 127, 126,
124, 123, 124, 123, 122, 121, 118, 117, 114, 115, 116, 116, 115, 115,
114, 111, 111, 111, 112, 111, 110, 110, 110, 111, 111, 114, 110, 111,
112, 113, 116, 120, 126, 131, 147, 160
```

View file

@ -1,36 +0,0 @@
/*
settings.json:
"markdown-pdf.styles": ["markdown-pdf.css",],
"markdown-pdf.format": "Letter",
"markdown-pdf.margin.top": "1in",
"markdown-pdf.margin.bottom": "1in",
"markdown-pdf.margin.left": "1in",
"markdown-pdf.margin.right": "1in",
"markdown-pdf.stylesRelativePathFile" : true,
"markdown-pdf.displayHeaderFooter": false,
*/
body {
font-family: "Times";
font-size: 10pt;
padding: 0;
}
h4 {
font-family: "Times New Roman";
font-size: 10pt;
font-weight: bold;
}
code {
font-family: Consolas, "Source Code Pro";
font-size: 10pt;
}
pre.hljs code > div {
padding: 0px;
}
:not(pre):not(.hljs) > code {
color: #4d4d4c;
}

View file

@ -1,9 +0,0 @@
#### Table M.17 – nonzero_buckets
```
0, 1, 2, 3, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10
```

View file

@ -1,60 +0,0 @@
#### Table M.16 – num_nonzero_context
`scheme == 0`:
```
0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
```
`scheme == 1`:
```
0, 2, 2, 4, 4, 4, 6, 6, 6, 6, 8, 8, 8, 8, 8, 8, 10, 10,
10, 10, 10, 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14
```
`scheme == 2`:
```
0, 4, 4, 8, 8, 8, 12, 12, 12, 12, 16, 16, 16, 16, 16, 16, 20, 20,
20, 20, 20, 20, 20, 20, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28
```
`scheme == 3`:
```
0, 8, 8, 16, 16, 16, 24, 24, 24, 24, 32, 32, 32, 32, 32, 32, 40, 40,
40, 40, 40, 40, 40, 40, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55, 55, 55
```
`scheme == 4`:
```
0, 16, 16, 32, 32, 32, 48, 48, 48, 48, 64, 64, 64, 64,
64, 64, 80, 80, 80, 80, 80, 80, 80, 80, 95, 95, 95, 95,
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 109, 109,
109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109,
109, 109, 109, 109, 109, 109, 109, 109
```
`scheme == 5`:
```
0, 32, 32, 64, 64, 64, 96, 96, 96, 96, 127, 127, 127, 127,
127, 127, 157, 157, 157, 157, 157, 157, 157, 157, 185, 185, 185, 185,
185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 211, 211,
211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211,
211, 211, 211, 211, 211, 211, 211, 211
```
`scheme == 6`:
```
0, 64, 64, 127, 127, 127, 188, 188, 188, 188, 246, 246, 246, 246,
246, 246, 300, 300, 300, 300, 300, 300, 300, 300, 348, 348, 348, 348,
348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 388, 388,
388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388,
388, 388, 388, 388, 388, 388, 388, 388
```

View file

@ -1,258 +0,0 @@
#### Table M.2 – num_nonzeros_base table
```
251, 252, 117, 249, 161, 136, 83, 238, 184, 126, 137, 129, 140, 119,
70, 213, 160, 175, 174, 130, 166, 134, 122, 125, 131, 144, 136, 133,
139, 123, 79, 216, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
254, 252, 174, 232, 189, 155, 122, 177, 204, 173, 146, 149, 141, 133,
103, 109, 167, 187, 168, 142, 154, 147, 125, 139, 144, 138, 138, 153,
141, 133, 90, 121, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
251, 240, 197, 176, 184, 177, 114, 89, 194, 165, 153, 161, 158, 136,
92, 95, 123, 171, 160, 140, 148, 136, 129, 139, 145, 136, 143, 134,
138, 124, 92, 154, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
247, 220, 201, 110, 194, 176, 147, 59, 175, 171, 156, 157, 152, 146,
115, 114, 88, 151, 164, 141, 153, 135, 141, 131, 146, 139, 140, 145,
138, 137, 112, 184, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
238, 179, 203, 63, 194, 173, 149, 71, 139, 169, 154, 159, 150, 146,
117, 143, 78, 122, 152, 137, 149, 138, 138, 133, 134, 142, 142, 142,
148, 128, 118, 199, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
227, 127, 200, 44, 192, 170, 148, 100, 102, 161, 156, 153, 148, 149,
124, 160, 88, 101, 134, 132, 149, 145, 134, 134, 136, 141, 138, 142,
144, 137, 116, 208, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
214, 86, 195, 44, 187, 163, 148, 126, 81, 147, 156, 152, 150, 144,
121, 172, 96, 95, 117, 122, 145, 152, 136, 133, 135, 135, 131, 142,
141, 135, 114, 217, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
198, 56, 191, 54, 171, 162, 147, 144, 74, 128, 152, 149, 150, 142,
119, 177, 101, 100, 106, 111, 135, 154, 136, 137, 136, 132, 133, 142,
144, 130, 117, 222, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
176, 40, 189, 73, 147, 159, 148, 152, 79, 106, 147, 149, 151, 139,
123, 188, 108, 110, 106, 97, 125, 151, 137, 138, 135, 135, 134, 136,
140, 131, 116, 221, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
148, 33, 185, 88, 117, 158, 145, 163, 95, 91, 137, 146, 150, 140,
120, 197, 115, 116, 114, 92, 114, 144, 130, 133, 132, 133, 129, 140,
138, 130, 111, 224, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
117, 31, 180, 104, 93, 150, 143, 166, 99, 85, 124, 139, 148, 142,
118, 201, 105, 120, 120, 90, 107, 135, 127, 130, 131, 131, 132, 140,
142, 133, 114, 229, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
87, 35, 170, 110, 78, 141, 144, 176, 106, 90, 112, 132, 143, 138,
119, 204, 111, 121, 125, 90, 105, 131, 124, 122, 129, 128, 129, 137,
138, 133, 114, 227, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
63, 42, 159, 123, 73, 127, 142, 191, 105, 91, 105, 123, 139, 137,
120, 209, 117, 110, 122, 98, 110, 125, 115, 123, 122, 126, 128, 134,
141, 129, 113, 229, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
45, 53, 146, 135, 71, 114, 138, 193, 100, 98, 98, 113, 133, 135,
118, 222, 113, 111, 139, 103, 107, 126, 111, 119, 121, 122, 127, 135,
141, 128, 114, 242, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
33, 60, 132, 138, 75, 100, 134, 203, 112, 99, 98, 105, 126, 131,
115, 229, 107, 93, 121, 106, 108, 122, 106, 109, 114, 116, 127, 133,
143, 128, 110, 242, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
24, 70, 118, 134, 76, 87, 130, 201, 110, 96, 99, 97, 119, 130,
111, 229, 97, 104, 125, 102, 112, 125, 101, 109, 113, 114, 125, 129,
142, 127, 112, 241, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
17, 65, 100, 121, 80, 75, 124, 174, 117, 100, 94, 93, 114, 128,
110, 216, 103, 94, 113, 122, 118, 126, 113, 108, 105, 108, 122, 128,
141, 125, 113, 238, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
12, 70, 82, 132, 78, 65, 118, 155, 136, 103, 97, 89, 106, 124,
111, 215, 115, 123, 129, 99, 104, 127, 110, 108, 101, 109, 118, 126,
136, 123, 110, 233, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
8, 66, 61, 117, 91, 59, 108, 195, 101, 112, 99, 99, 99, 116,
106, 230, 127, 99, 144, 101, 118, 137, 117, 111, 106, 104, 116, 121,
134, 122, 110, 223, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
6, 78, 42, 146, 101, 54, 94, 201, 116, 102, 110, 94, 92, 108,
103, 214, 108, 111, 127, 102, 121, 132, 120, 121, 95, 98, 110, 121,
129, 117, 107, 235, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
5, 93, 29, 145, 102, 52, 77, 216, 108, 115, 108, 102, 89, 97,
94, 229, 89, 103, 139, 120, 103, 151, 102, 100, 97, 96, 99, 111,
125, 116, 104, 242, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
4, 105, 21, 145, 100, 54, 64, 217, 100, 122, 128, 87, 88, 91,
87, 230, 112, 80, 148, 95, 146, 123, 96, 140, 90, 91, 98, 106,
122, 111, 100, 249, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
4, 130, 14, 142, 104, 56, 51, 208, 116, 135, 100, 89, 82, 84,
75, 239, 85, 85, 122, 125, 94, 144, 151, 136, 92, 97, 104, 109,
113, 110, 91, 246, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
3, 126, 9, 172, 105, 57, 39, 219, 95, 120, 118, 96, 93, 75,
66, 241, 102, 134, 96, 156, 146, 162, 130, 112, 82, 89, 97, 101,
116, 103, 82, 254, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
3, 149, 7, 182, 122, 54, 29, 224, 103, 100, 113, 96, 90, 74,
55, 250, 127, 94, 118, 93, 135, 160, 113, 130, 95, 117, 106, 96,
111, 97, 77, 242, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
3, 150, 4, 170, 138, 59, 20, 229, 91, 150, 107, 98, 92, 68,
48, 245, 113, 64, 114, 111, 134, 127, 102, 104, 85, 118, 103, 107,
102, 91, 72, 245, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
3, 171, 3, 165, 137, 62, 14, 211, 96, 127, 132, 121, 95, 62,
37, 248, 102, 57, 144, 85, 127, 191, 102, 97, 127, 104, 91, 102,
107, 81, 64, 254, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
2, 166, 2, 196, 122, 65, 10, 243, 102, 93, 117, 92, 96, 63,
29, 251, 169, 159, 149, 96, 91, 139, 157, 40, 100, 89, 120, 92,
109, 79, 58, 247, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
2, 176, 2, 189, 118, 48, 7, 219, 68, 43, 109, 96, 129, 75,
19, 254, 2, 3, 185, 6, 102, 127, 127, 127, 1, 131, 83, 99,
107, 80, 45, 254, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
1, 205, 2, 208, 64, 89, 4, 223, 29, 169, 29, 123, 118, 76,
11, 240, 202, 243, 65, 6, 12, 243, 96, 55, 102, 102, 114, 102,
107, 74, 31, 247, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
1, 216, 1, 214, 127, 94, 2, 234, 145, 3, 127, 106, 155, 80,
4, 247, 4, 65, 86, 127, 127, 127, 127, 102, 127, 143, 143, 108,
113, 80, 16, 216, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```
```
2, 199, 1, 222, 93, 94, 1, 232, 2, 65, 74, 139, 201, 48,
2, 254, 169, 127, 52, 243, 251, 249, 102, 86, 202, 153, 65, 65,
146, 69, 8, 238, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128
```

View file

@ -1,19 +0,0 @@
#### Table M.13 – template quant tables
`is_luma == true`:
```
16, 11, 10, 16, 24, 40, 51, 61, 12, 12, 14, 19, 26, 58, 60,
55, 14, 13, 16, 24, 40, 57, 69, 56, 14, 17, 22, 29, 51, 87,
80, 62, 18, 22, 37, 56, 68, 109, 103, 77, 24, 35, 55, 64, 81,
104, 113, 92, 49, 64, 78, 87, 103, 121, 120, 101, 72, 92, 95, 98,
112, 100, 103, 99
```
`is_luma == false`:
```
17, 18, 24, 47, 99, 99, 99, 99, 18, 21, 26, 66, 99, 99, 99, 99, 24, 26,
56, 99, 99, 99, 99, 99, 47, 66, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99
```

View file

@ -1,22 +0,0 @@
#### Table M.9 – stock counts arrays
`is_ac == 0`, `stock_index == 0`:
```
0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0
```
`is_ac == 0`, `stock_index == 1`:
```
0, 0, 1, 5, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0
```
`is_ac == 1`, `stock_index == 0`:
```
0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 126
```
`is_ac == 1`, `stock_index == 1`:
```
0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 120
```

View file

@ -1,130 +0,0 @@
#### Table M.12 – stock quant tables
`is_luma == true`, `stock_index == 0`:
```
3, 2, 2, 3, 5, 8, 10, 12, 2, 2, 3, 4, 5, 12, 12, 11, 3, 3,
3, 5, 8, 11, 14, 11, 3, 3, 4, 6, 10, 17, 16, 12, 4, 4, 7, 11,
14, 22, 21, 15, 5, 7, 11, 13, 16, 21, 23, 18, 10, 13, 16, 17, 21, 24,
24, 20, 14, 18, 19, 20, 22, 20, 21, 20
```
`is_luma == true`, `stock_index == 1`:
```
8, 6, 5, 8, 12, 20, 26, 31, 6, 6, 7, 10, 13, 29, 30, 28, 7, 7,
8, 12, 20, 29, 35, 28, 7, 9, 11, 15, 26, 44, 40, 31, 9, 11, 19, 28,
34, 55, 52, 39, 12, 18, 28, 32, 41, 52, 57, 46, 25, 32, 39, 44, 52, 61,
60, 51, 36, 46, 48, 49, 56, 50, 52, 50
```
`is_luma == true`, `stock_index == 2`:
```
6, 4, 4, 6, 10, 16, 20, 24, 5, 5, 6, 8, 10, 23, 24, 22, 6, 5,
6, 10, 16, 23, 28, 22, 6, 7, 9, 12, 20, 35, 32, 25, 7, 9, 15, 22,
27, 44, 41, 31, 10, 14, 22, 26, 32, 42, 45, 37, 20, 26, 31, 35, 41, 48,
48, 40, 29, 37, 38, 39, 45, 40, 41, 40
```
`is_luma == true`, `stock_index == 3`:
```
5, 3, 3, 5, 7, 12, 15, 18, 4, 4, 4, 6, 8, 17, 18, 17, 4, 4,
5, 7, 12, 17, 21, 17, 4, 5, 7, 9, 15, 26, 24, 19, 5, 7, 11, 17,
20, 33, 31, 23, 7, 11, 17, 19, 24, 31, 34, 28, 15, 19, 23, 26, 31, 36,
36, 30, 22, 28, 29, 29, 34, 30, 31, 30
```
`is_luma == true`, `stock_index == 4`:
```
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1
```
`is_luma == true`, `stock_index == 5`:
```
2, 1, 1, 2, 2, 4, 5, 6, 1, 1, 1, 2, 3, 6, 6, 6, 1, 1,
2, 2, 4, 6, 7, 6, 1, 2, 2, 3, 5, 9, 8, 6, 2, 2, 4, 6,
7, 11, 10, 8, 2, 4, 6, 6, 8, 10, 11, 9, 5, 6, 8, 9, 10, 12,
12, 10, 7, 9, 10, 10, 11, 10, 10, 10
```
`is_luma == true`, `stock_index == 6`:
```
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1,
1, 2, 2, 3, 1, 1, 1, 1, 2, 2, 3, 3, 1, 1, 1, 2, 2, 3,
3, 3, 1, 1, 2, 2, 3, 3, 3, 3
```
`is_luma == true`, `stock_index == 7`:
```
10, 7, 6, 10, 14, 24, 31, 37, 7, 7, 8, 11, 16, 35, 36, 33, 8, 8,
10, 14, 24, 34, 41, 34, 8, 10, 13, 17, 31, 52, 48, 37, 11, 13, 22, 34,
41, 65, 62, 46, 14, 21, 33, 38, 49, 62, 68, 55, 29, 38, 47, 52, 62, 73,
72, 61, 43, 55, 57, 59, 67, 60, 62, 59
```
`is_luma == false`, `stock_index == 0`:
```
9, 9, 9, 12, 11, 12, 24, 13, 13, 24, 50, 33, 28, 33, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50, 50, 50
```
`is_luma == false`, `stock_index == 1`:
```
3, 4, 5, 9, 20, 20, 20, 20, 4, 4, 5, 13, 20, 20, 20, 20, 5, 5,
11, 20, 20, 20, 20, 20, 9, 13, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20
```
`is_luma == false`, `stock_index == 2`:
```
9, 9, 12, 24, 50, 50, 50, 50, 9, 11, 13, 33, 50, 50, 50, 50, 12, 13,
28, 50, 50, 50, 50, 50, 24, 33, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50, 50, 50
```
`is_luma == false`, `stock_index == 3`:
```
5, 5, 7, 14, 30, 30, 30, 30, 5, 6, 8, 20, 30, 30, 30, 30, 7, 8,
17, 30, 30, 30, 30, 30, 14, 20, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30
```
`is_luma == false`, `stock_index == 4`:
```
7, 7, 10, 19, 40, 40, 40, 40, 7, 8, 10, 26, 40, 40, 40, 40, 10, 10,
22, 40, 40, 40, 40, 40, 19, 26, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40
```
`is_luma == false`, `stock_index == 5`:
```
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1
```
`is_luma == false`, `stock_index == 6`:
```
2, 2, 2, 5, 10, 10, 10, 10, 2, 2, 3, 7, 10, 10, 10, 10, 2, 3,
6, 10, 10, 10, 10, 10, 5, 7, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10
```
`is_luma == false`, `stock_index == 7`:
```
10, 11, 14, 28, 59, 59, 59, 59, 11, 13, 16, 40, 59, 59, 59, 59, 14, 16,
34, 59, 59, 59, 59, 59, 28, 40, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
59, 59, 59, 59, 59, 59, 59, 59, 59, 59
```

View file

@ -1,44 +0,0 @@
#### Table M.10 – stock values arrays
`is_ac == 0`, `stock_index == 0`:
```
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 256
```
`is_ac == 0`, `stock_index == 1`:
```
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 256
```
`is_ac == 1`, `stock_index == 0`:
```
1, 2, 3, 0, 4, 17, 5, 18, 33, 49, 65, 6, 19, 81,
97, 7, 34, 113, 20, 50, 129, 145, 161, 8, 35, 66, 177, 193,
21, 82, 209, 240, 36, 51, 98, 114, 130, 9, 10, 22, 23, 24,
25, 26, 37, 38, 39, 40, 41, 42, 52, 53, 54, 55, 56, 57,
58, 67, 68, 69, 70, 71, 72, 73, 74, 83, 84, 85, 86, 87,
88, 89, 90, 99, 100, 101, 102, 103, 104, 105, 106, 115, 116, 117,
118, 119, 120, 121, 122, 131, 132, 133, 134, 135, 136, 137, 138, 146,
147, 148, 149, 150, 151, 152, 153, 154, 162, 163, 164, 165, 166, 167,
168, 169, 170, 178, 179, 180, 181, 182, 183, 184, 185, 186, 194, 195,
196, 197, 198, 199, 200, 201, 202, 210, 211, 212, 213, 214, 215, 216,
217, 218, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 241, 242,
243, 244, 245, 246, 247, 248, 249, 250, 256
```
`is_ac == 1`, `stock_index == 1`:
```
0, 1, 2, 3, 17, 4, 5, 33, 49, 6, 18, 65, 81, 7,
97, 113, 19, 34, 50, 129, 8, 20, 66, 145, 161, 177, 193, 9,
35, 51, 82, 240, 21, 98, 114, 209, 10, 22, 36, 52, 225, 37,
241, 23, 24, 25, 26, 38, 39, 40, 41, 42, 53, 54, 55, 56,
57, 58, 67, 68, 69, 70, 71, 72, 73, 74, 83, 84, 85, 86,
87, 88, 89, 90, 99, 100, 101, 102, 103, 104, 105, 106, 115, 116,
117, 118, 119, 120, 121, 122, 130, 131, 132, 133, 134, 135, 136, 137,
138, 146, 147, 148, 149, 150, 151, 152, 153, 154, 162, 163, 164, 165,
166, 167, 168, 169, 170, 178, 179, 180, 181, 182, 183, 184, 185, 186,
194, 195, 196, 197, 198, 199, 200, 201, 202, 210, 211, 212, 213, 214,
215, 216, 217, 218, 226, 227, 228, 229, 230, 231, 232, 233, 234, 242,
243, 244, 245, 246, 247, 248, 249, 250, 256
```

View file

@ -1,30 +0,0 @@
#### Table M.11 – predefined symbol order
`is_ac == 0`:
```
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
```
`is_ac == 1`:
```
1, 0, 2, 3, 17, 4, 5, 33, 18, 49, 65, 6, 81, 19,
97, 7, 34, 113, 50, 129, 20, 145, 161, 8, 35, 66, 177, 193,
21, 82, 209, 240, 36, 51, 98, 114, 9, 130, 10, 22, 52, 225,
23, 37, 241, 24, 25, 26, 38, 39, 40, 41, 42, 53, 54, 55,
56, 57, 58, 67, 68, 69, 70, 71, 72, 73, 74, 83, 84, 85,
86, 87, 88, 89, 90, 99, 100, 101, 102, 103, 104, 105, 106, 115,
116, 117, 118, 119, 120, 121, 122, 131, 132, 133, 134, 135, 136, 137,
138, 146, 147, 148, 149, 150, 151, 152, 153, 154, 162, 163, 164, 165,
166, 167, 168, 169, 170, 178, 179, 180, 181, 182, 183, 184, 185, 186,
194, 195, 196, 197, 198, 199, 200, 201, 202, 210, 211, 212, 213, 214,
215, 216, 217, 218, 226, 227, 228, 229, 230, 231, 232, 233, 234, 242,
243, 244, 245, 246, 247, 248, 249, 250, 16, 32, 48, 64, 80, 96,
112, 128, 144, 160, 176, 192, 208, 11, 12, 13, 14, 15, 27, 28,
29, 30, 31, 43, 44, 45, 46, 47, 59, 60, 61, 62, 63, 75,
76, 77, 78, 79, 91, 92, 93, 94, 95, 107, 108, 109, 110, 111,
123, 124, 125, 126, 127, 139, 140, 141, 142, 143, 155, 156, 157, 158,
159, 171, 172, 173, 174, 175, 187, 188, 189, 190, 191, 203, 204, 205,
206, 207, 219, 220, 221, 222, 223, 224, 235, 236, 237, 238, 239, 251,
252, 253, 254, 255
```

View file

@ -195,7 +195,7 @@ engineers on the required backports.
A security bug is a bug that can potentially be exploited to let an attacker A security bug is a bug that can potentially be exploited to let an attacker
gain unauthorized access or privileges. For example, gaining code execution in gain unauthorized access or privileges. For example, gaining code execution in
libjxl decoder by decoding a malicious .jxl file is a security but hitting a libjxl decoder by decoding a malicious .jxl file is a security but hitting a
`JXL_ASSERT()` is not necessarily one. `JXL_DASSERT` is not necessarily one.
The supported use cases to consider in the context of security bugs that require The supported use cases to consider in the context of security bugs that require
a vulnerability disclosure are "release" builds. The disclosure is intended for a vulnerability disclosure are "release" builds. The disclosure is intended for
@ -215,22 +215,9 @@ released software will not have the developer code. This developer code is in
the same libjxl repository for convenience. the same libjxl repository for convenience.
When considering the impact of a bug, "release" mode should be assumed. In When considering the impact of a bug, "release" mode should be assumed. In
release mode `JXL_ASSERT()` and `JXL_CHECK()` are enabled, but `JXL_DASSERT()` non-release mode `JXL_DASSERT` is enabled. This means that if a
are not. This means that if a `JXL_DASSERT()` protects an out-of-bounds (OOB) `JXL_DASSERT` protects an out-of-bounds (OOB) write, then the impact of a bug
write, then the impact of a bug hitting the `JXL_DASSERT()` is at least an hitting the `JXL_DASSERT` is at least an OOB write.
OOB write. On the other hand, if a bug ends up hitting a `JXL_CHECK()` instead
of continuing, the only impact is the process abort instead of whatever else is
possible after the `JXL_CHECK()`.
Asserts in `libjxl` *tools* cause the tool process to abort, but don't affect
the caller. Either crashing or returning an error (non-zero exit code) would
have the same effect, so `JXL_ASSERT()` failures in the tools have no security
or functional impact.
Asserts in `libjxl` libraries, meant to be linked into other processes, cause
the caller process to abort, potentially causing a Denial of Service, however,
Denial of Service issues are *not* considered security bugs by this policy.
These are still issues and should be fixed, but they are not security issues.
Out-of-bounds (OOB) reads in process memory are considered security Out-of-bounds (OOB) reads in process memory are considered security
vulnerabilities. OOB reads may allow an attacker to read other buffers from the vulnerabilities. OOB reads may allow an attacker to read other buffers from the

View file

@ -124,7 +124,7 @@ To diagnose the cause of encoder/decoder failures (which often only result in a
generic "decode failed" message), build using the following command: generic "decode failed" message), build using the following command:
```bash ```bash
CMAKE_FLAGS="-DJXL_CRASH_ON_ERROR" ./ci.sh opt CMAKE_FLAGS="-DJXL_CRASH_ON_ERROR" ./ci.sh debug
``` ```
In such builds, the first JXL_FAILURE will print a message identifying where the In such builds, the first JXL_FAILURE will print a message identifying where the
@ -150,7 +150,7 @@ multiple image lines.
**DCT size selection**: `ac_strategy.cc` **DCT size selection**: `ac_strategy.cc`
**[Gaborish]**: `gaborish.h`. **[Gaborish]**: `enc_gaborish.h`.
**[Edge preserving filter]**: `epf.h` **[Edge preserving filter]**: `epf.h`

View file

@ -1,21 +0,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.
# Build an Ubuntu-based docker image with the installed software needed to
# develop and test JPEG XL.
FROM ubuntu:bionic
# Set a prompt for when using it locally.
ENV PS1="\[\033[01;33m\]\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ "
COPY scripts/99_norecommends /etc/apt/apt.conf.d/99_norecommends
COPY scripts /jpegxl_scripts
ARG DEBIAN_FRONTEND=noninteractive
RUN /jpegxl_scripts/jpegxl_builder.sh && \
rm -rf /jpegxl_scripts

View file

@ -1,37 +0,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.
# Build an Ubuntu-based docker image for aarch64 with the installed software
# needed to run JPEG XL. This is only useful when running on actual aarch64
# hardware.
FROM arm64v8/ubuntu:bionic
COPY scripts/99_norecommends /etc/apt/apt.conf.d/99_norecommends
# Set a prompt for when using it locally.
ENV PS1="\[\033[01;33m\]\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ "
ARG DEBIAN_FRONTEND=noninteractive
RUN set -ex; \
apt-get update -y; \
apt-get install -y \
bsdmainutils \
cmake \
curl \
ca-certificates \
extra-cmake-modules \
git \
imagemagick \
libjpeg8 \
libgif7 \
libgoogle-perftools4 \
libopenexr22 \
libpng16-16 \
libqt5x11extras5 \
libsdl2-2.0-0 \
parallel; \
rm -rf /var/lib/apt/lists/*;

View file

@ -1,7 +0,0 @@
### Docker container infrastructure for JPEG XL
This directory contains the requirements to build a docker image for the
JPEG XL project builder.
Docker images need to be created and upload manually. See ./build.sh for
details.

View file

@ -1,83 +0,0 @@
#!/usr/bin/env bash
# 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.
set -eu
MYDIR=$(dirname $(realpath "$0"))
declare -a TARGETS
load_targets() {
# Built-in OSX "find" does not support "-m".
FIND=$(which "gfind" || which "find")
for f in $(${FIND} -maxdepth 1 -name 'Dockerfile.*' | sort); do
local target="${f#*Dockerfile.}"
TARGETS+=("${target}")
done
}
usage() {
cat >&2 <<EOF
Use: $1 [targets]
Available targets:
* all
EOF
for target in "${TARGETS[@]}"; do
echo " * ${target}" >&2
done
}
build_target() {
local target="$1"
local dockerfile="${MYDIR}/Dockerfile.${target}"
# JPEG XL builder images are stored in the gcr.io/jpegxl project.
local tag="gcr.io/jpegxl/${target}"
echo "Building ${target}"
if ! sudo docker build --no-cache -t "${tag}" -f "${dockerfile}" "${MYDIR}" \
>"${target}.log" 2>&1; then
echo "${target} failed. See ${target}.log" >&2
else
echo "Done, to upload image run:" >&2
echo " sudo docker push ${tag}"
if [[ "${JPEGXL_PUSH:-}" == "1" ]]; then
echo "sudo docker push ${tag}" >&2
sudo docker push "${tag}"
# The RepoDigest is only created after it is pushed.
local fulltag=$(sudo docker inspect --format="{{.RepoDigests}}" "${tag}")
fulltag="${fulltag#[}"
fulltag="${fulltag%]}"
echo "Updating .gitlab-ci.yml to ${fulltag}" >&2
sed -E "s;${tag}@sha256:[0-9a-f]+;${fulltag};" \
-i "${MYDIR}/../.gitlab-ci.yml"
fi
fi
}
main() {
cd "${MYDIR}"
local target="${1:-}"
load_targets
if [[ -z "${target}" ]]; then
usage $0
exit 1
fi
if [[ "${target}" == "all" ]]; then
for target in "${TARGETS[@]}"; do
build_target "${target}"
done
else
for target in "$@"; do
build_target "${target}"
done
fi
}
main "$@"

View file

@ -1 +0,0 @@
APT::Install-Recommends "false";

View file

@ -1,28 +0,0 @@
Description: fix lack of alignment in relocations (crashes on mingw)
See https://sourceware.org/git/?p=binutils-gdb.git;a=patch;h=73af69e74974eaa155eec89867e3ccc77ab39f6d
From: Marc <marc@groundctl.com>
Date: Fri, 9 Nov 2018 11:13:50 +0000
Subject: [PATCH] Allow for compilers that do not produce aligned .rdat
sections in PE format files.
--- a/upstream/ld/scripttempl/pe.sc 2020-05-12 18:45:12.000000000 +0200
+++ b/upstream/ld/scripttempl/pe.sc 2020-05-12 18:47:12.000000000 +0200
@@ -143,6 +143,7 @@
.rdata ${RELOCATING+BLOCK(__section_alignment__)} :
{
${R_RDATA}
+ . = ALIGN(4);
${RELOCATING+__rt_psrelocs_start = .;}
${RELOCATING+KEEP(*(.rdata_runtime_pseudo_reloc))}
${RELOCATING+__rt_psrelocs_end = .;}
--- a/upstream/ld/scripttempl/pep.sc 2020-05-12 18:45:19.000000000 +0200
+++ b/upstream/ld/scripttempl/pep.sc 2020-05-12 18:47:18.000000000 +0200
@@ -143,6 +143,7 @@
.rdata ${RELOCATING+BLOCK(__section_alignment__)} :
{
${R_RDATA}
+ . = ALIGN(4);
${RELOCATING+__rt_psrelocs_start = .;}
${RELOCATING+KEEP(*(.rdata_runtime_pseudo_reloc))}
${RELOCATING+__rt_psrelocs_end = .;}

View file

@ -1,37 +0,0 @@
#!/usr/bin/env bash
# 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.
EMSDK_URL="https://github.com/emscripten-core/emsdk/archive/main.tar.gz"
EMSDK_DIR="/opt/emsdk"
EMSDK_RELEASE="2.0.23"
set -eu -x
# Temporary files cleanup hooks.
CLEANUP_FILES=()
cleanup() {
if [[ ${#CLEANUP_FILES[@]} -ne 0 ]]; then
rm -fr "${CLEANUP_FILES[@]}"
fi
}
trap "{ set +x; } 2>/dev/null; cleanup" INT TERM EXIT
main() {
local workdir=$(mktemp -d --suffix=emsdk)
CLEANUP_FILES+=("${workdir}")
local emsdktar="${workdir}/emsdk.tar.gz"
curl --output "${emsdktar}" "${EMSDK_URL}" --location
mkdir -p "${EMSDK_DIR}"
tar -zxf "${emsdktar}" -C "${EMSDK_DIR}" --strip-components=1
cd "${EMSDK_DIR}"
./emsdk install --shallow "${EMSDK_RELEASE}"
./emsdk activate --embedded "${EMSDK_RELEASE}"
}
main "$@"

View file

@ -1,518 +0,0 @@
#!/usr/bin/env bash
# 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.
# Main entry point for all the Dockerfile for jpegxl-builder. This centralized
# file helps sharing code and configuration between Dockerfiles.
set -eux
MYDIR=$(dirname $(realpath "$0"))
# libjpeg-turbo.
JPEG_TURBO_RELEASE="2.0.4"
JPEG_TURBO_URL="https://github.com/libjpeg-turbo/libjpeg-turbo/archive/${JPEG_TURBO_RELEASE}.tar.gz"
JPEG_TURBO_SHA256="7777c3c19762940cff42b3ba4d7cd5c52d1671b39a79532050c85efb99079064"
# zlib (dependency of libpng)
ZLIB_RELEASE="1.2.11"
ZLIB_URL="https://www.zlib.net/zlib-${ZLIB_RELEASE}.tar.gz"
ZLIB_SHA256="c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1"
# The name in the .pc and the .dll generated don't match in zlib for Windows
# because they use different .dll names in Windows. We avoid that by defining
# UNIX=1. We also install all the .dll files to ${prefix}/lib instead of the
# default ${prefix}/bin.
ZLIB_FLAGS='-DUNIX=1 -DINSTALL_PKGCONFIG_DIR=/${CMAKE_INSTALL_PREFIX}/lib/pkgconfig -DINSTALL_BIN_DIR=/${CMAKE_INSTALL_PREFIX}/lib'
# libpng
LIBPNG_RELEASE="1.6.37"
LIBPNG_URL="https://github.com/glennrp/libpng/archive/v${LIBPNG_RELEASE}.tar.gz"
LIBPNG_SHA256="ca74a0dace179a8422187671aee97dd3892b53e168627145271cad5b5ac81307"
# giflib
GIFLIB_RELEASE="5.2.1"
GIFLIB_URL="https://netcologne.dl.sourceforge.net/project/giflib/giflib-${GIFLIB_RELEASE}.tar.gz"
GIFLIB_SHA256="31da5562f44c5f15d63340a09a4fd62b48c45620cd302f77a6d9acf0077879bd"
# A patch needed to compile GIFLIB in mingw.
GIFLIB_PATCH_URL="https://github.com/msys2/MINGW-packages/raw/3afde38fcee7b3ba2cafd97d76cca8f06934504f/mingw-w64-giflib/001-mingw-build.patch"
GIFLIB_PATCH_SHA256="2b2262ddea87fc07be82e10aeb39eb699239f883c899aa18a16e4d4e40af8ec8"
# webp
WEBP_RELEASE="1.0.2"
WEBP_URL="https://codeload.github.com/webmproject/libwebp/tar.gz/v${WEBP_RELEASE}"
WEBP_SHA256="347cf85ddc3497832b5fa9eee62164a37b249c83adae0ba583093e039bf4881f"
# Google benchmark
BENCHMARK_RELEASE="1.5.2"
BENCHMARK_URL="https://github.com/google/benchmark/archive/v${BENCHMARK_RELEASE}.tar.gz"
BENCHMARK_SHA256="dccbdab796baa1043f04982147e67bb6e118fe610da2c65f88912d73987e700c"
BENCHMARK_FLAGS="-DGOOGLETEST_PATH=${MYDIR}/../../third_party/googletest"
# attribute(format(__MINGW_PRINTF_FORMAT, ...)) doesn't work in our
# environment, so we disable the warning.
BENCHMARK_FLAGS="-DCMAKE_BUILD_TYPE=Release -DBENCHMARK_ENABLE_TESTING=OFF \
-DCMAKE_CXX_FLAGS=-Wno-ignored-attributes \
-DCMAKE_POSITION_INDEPENDENT_CODE=ON"
# V8
V8_VERSION="9.3.22"
# Temporary files cleanup hooks.
CLEANUP_FILES=()
cleanup() {
if [[ ${#CLEANUP_FILES[@]} -ne 0 ]]; then
rm -fr "${CLEANUP_FILES[@]}"
fi
}
trap "{ set +x; } 2>/dev/null; cleanup" INT TERM EXIT
# List of Ubuntu arch names supported by the builder (such as "i386").
LIST_ARCHS=(
amd64
i386
arm64
armhf
)
# List of target triplets supported by the builder.
LIST_TARGETS=(
x86_64-linux-gnu
i686-linux-gnu
arm-linux-gnueabihf
aarch64-linux-gnu
)
LIST_MINGW_TARGETS=(
i686-w64-mingw32
x86_64-w64-mingw32
)
LIST_WASM_TARGETS=(
wasm32
)
# Setup the apt repositories and supported architectures.
setup_apt() {
apt-get update -y
apt-get install -y curl gnupg ca-certificates
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 1E9377A2BA9EF27F
# node sources.
cat >/etc/apt/sources.list.d/nodesource.list <<EOF
deb https://deb.nodesource.com/node_14.x bionic main
deb-src https://deb.nodesource.com/node_14.x bionic main
EOF
curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add -
local port_list=()
local main_list=()
local ubarch
for ubarch in "${LIST_ARCHS[@]}"; do
if [[ "${ubarch}" != "amd64" && "${ubarch}" != "i386" ]]; then
# other archs are not part of the main mirrors, but available in
# ports.ubuntu.com.
port_list+=("${ubarch}")
else
main_list+=("${ubarch}")
fi
# Add the arch to the system.
if [[ "${ubarch}" != "amd64" ]]; then
dpkg --add-architecture "${ubarch}"
fi
done
# Update the sources.list with the split of supported architectures.
local bkplist="/etc/apt/sources.list.bkp"
[[ -e "${bkplist}" ]] || \
mv /etc/apt/sources.list "${bkplist}"
local newlist="/etc/apt/sources.list.tmp"
rm -f "${newlist}"
port_list=$(echo "${port_list[@]}" | tr ' ' ,)
if [[ -n "${port_list}" ]]; then
local port_url="http://ports.ubuntu.com/ubuntu-ports/"
grep -v -E '^#' "${bkplist}" |
sed -E "s;^deb (http[^ ]+) (.*)\$;deb [arch=${port_list}] ${port_url} \\2;" \
>>"${newlist}"
fi
main_list=$(echo "${main_list[@]}" | tr ' ' ,)
grep -v -E '^#' "${bkplist}" |
sed -E "s;^deb (http[^ ]+) (.*)\$;deb [arch=${main_list}] \\1 \\2\ndeb-src [arch=${main_list}] \\1 \\2;" \
>>"${newlist}"
mv "${newlist}" /etc/apt/sources.list
}
install_pkgs() {
packages=(
# Native compilers (minimum for SIMD is clang-7)
clang-7 clang-format-7 clang-tidy-7
# TODO: Consider adding clang-8 to every builder:
# clang-8 clang-format-8 clang-tidy-8
# For cross-compiling to Windows with mingw.
mingw-w64
wine64
wine-binfmt
# Native tools.
bsdmainutils
cmake
extra-cmake-modules
git
llvm
nasm
ninja-build
parallel
pkg-config
# For compiling / testing JNI wrapper. JDK8 is almost 2x smaller than JDK11
# openjdk-8-jdk-headless would be 50MB smaller, unfortunately, CMake
# does mistakenly thinks it does not contain JNI feature.
openjdk-8-jdk
# These are used by the ./ci.sh lint in the native builder.
clang-format-7
clang-format-8
# For coverage builds
gcovr
# For compiling giflib documentation.
xmlto
# Common libraries.
libstdc++-8-dev
# We don't use tcmalloc on archs other than amd64. This installs
# libgoogle-perftools4:amd64.
google-perftools
# NodeJS for running WASM tests
nodejs
# To generate API documentation.
doxygen
# Freezes version that builds (passes tests). Newer version
# (2.30-21ubuntu1~18.04.4) claims to fix "On Intel Skylake
# (-march=native) generated avx512 instruction can be wrong",
# but newly added tests does not pass. Perhaps the problem is
# that mingw package is not updated.
binutils-source=2.30-15ubuntu1
)
# Install packages that are arch-dependent.
local ubarch
for ubarch in "${LIST_ARCHS[@]}"; do
packages+=(
# Library dependencies. These normally depend on the target architecture
# we are compiling for and can't usually be installed for multiple
# architectures at the same time.
libgif7:"${ubarch}"
libjpeg-dev:"${ubarch}"
libpng-dev:"${ubarch}"
libqt5x11extras5-dev:"${ubarch}"
libstdc++-8-dev:"${ubarch}"
qtbase5-dev:"${ubarch}"
# For OpenEXR:
libilmbase12:"${ubarch}"
libopenexr22:"${ubarch}"
# TCMalloc dependency
libunwind-dev:"${ubarch}"
# Cross-compiling tools per arch.
libc6-dev-"${ubarch}"-cross
libstdc++-8-dev-"${ubarch}"-cross
)
done
local target
for target in "${LIST_TARGETS[@]}"; do
# Per target cross-compiling tools.
if [[ "${target}" != "x86_64-linux-gnu" ]]; then
packages+=(
binutils-"${target}"
gcc-"${target}"
)
fi
done
# Install all the manual packages via "apt install" for the main arch. These
# will be installed for other archs via manual download and unpack.
apt install -y "${packages[@]}" "${UNPACK_PKGS[@]}"
}
# binutils <2.32 need a patch.
install_binutils() {
local workdir=$(mktemp -d --suffix=_install)
CLEANUP_FILES+=("${workdir}")
pushd "${workdir}"
apt source binutils-mingw-w64
apt -y build-dep binutils-mingw-w64
cd binutils-mingw-w64-8ubuntu1
cp "${MYDIR}/binutils_align_fix.patch" debian/patches
echo binutils_align_fix.patch >> debian/patches/series
dpkg-buildpackage -b
cd ..
dpkg -i *deb
popd
}
# Install a library from the source code for multiple targets.
# Usage: install_from_source <tar_url> <sha256> <target> [<target...>]
install_from_source() {
local package="$1"
shift
local url
eval "url=\${${package}_URL}"
local sha256
eval "sha256=\${${package}_SHA256}"
# Optional package flags
local pkgflags
eval "pkgflags=\${${package}_FLAGS:-}"
local workdir=$(mktemp -d --suffix=_install)
CLEANUP_FILES+=("${workdir}")
local tarfile="${workdir}"/$(basename "${url}")
curl -L --output "${tarfile}" "${url}"
if ! echo "${sha256} ${tarfile}" | sha256sum -c --status -; then
echo "SHA256 mismatch for ${url}: expected ${sha256} but found:"
sha256sum "${tarfile}"
exit 1
fi
local target
for target in "$@"; do
echo "Installing ${package} for target ${target} from ${url}"
local srcdir="${workdir}/source-${target}"
mkdir -p "${srcdir}"
tar -zxf "${tarfile}" -C "${srcdir}" --strip-components=1
local prefix="/usr"
if [[ "${target}" != "x86_64-linux-gnu" ]]; then
prefix="/usr/${target}"
fi
# Apply patches to buildfiles.
if [[ "${package}" == "GIFLIB" && "${target}" == *mingw32 ]]; then
# GIFLIB Makefile has several problems so we need to fix them here. We are
# using a patch from MSYS2 that already fixes the compilation for mingw.
local make_patch="${srcdir}/libgif.patch"
curl -L "${GIFLIB_PATCH_URL}" -o "${make_patch}"
echo "${GIFLIB_PATCH_SHA256} ${make_patch}" | sha256sum -c --status -
patch "${srcdir}/Makefile" < "${make_patch}"
elif [[ "${package}" == "LIBPNG" && "${target}" == wasm* ]]; then
# Cut the dependency to libm; there is pull request to fix it, so this
# might not be needed in the future.
sed -i 's/APPLE/EMSCRIPTEN/g' "${srcdir}/CMakeLists.txt"
fi
local cmake_args=()
local export_args=("CC=clang-7" "CXX=clang++-7")
local cmake="cmake"
local make="make"
local system_name="Linux"
if [[ "${target}" == *mingw32 ]]; then
system_name="Windows"
# When compiling with clang, CMake doesn't detect that we are using mingw.
cmake_args+=(
-DMINGW=1
# Googletest needs this when cross-compiling to windows
-DCMAKE_CROSSCOMPILING=1
-DHAVE_STD_REGEX=0
-DHAVE_POSIX_REGEX=0
-DHAVE_GNU_POSIX_REGEX=0
)
local windres=$(which ${target}-windres || true)
if [[ -n "${windres}" ]]; then
cmake_args+=(-DCMAKE_RC_COMPILER="${windres}")
fi
fi
if [[ "${target}" == wasm* ]]; then
system_name="WASM"
cmake="emcmake cmake"
make="emmake make"
export_args=()
cmake_args+=(
-DCMAKE_FIND_ROOT_PATH="${prefix}"
-DCMAKE_PREFIX_PATH="${prefix}"
)
# Static and shared library link to the same file -> race condition.
nproc=1
else
nproc=`nproc --all`
fi
cmake_args+=(-DCMAKE_SYSTEM_NAME="${system_name}")
if [[ "${target}" != "x86_64-linux-gnu" ]]; then
# Cross-compiling.
cmake_args+=(
-DCMAKE_C_COMPILER_TARGET="${target}"
-DCMAKE_CXX_COMPILER_TARGET="${target}"
-DCMAKE_SYSTEM_PROCESSOR="${target%%-*}"
)
fi
if [[ -e "${srcdir}/CMakeLists.txt" ]]; then
# Most packages use cmake for building which is easier to configure for
# cross-compiling.
if [[ "${package}" == "JPEG_TURBO" && "${target}" == wasm* ]]; then
# JT erroneously detects WASM CPU as i386 and tries to use asm.
# Wasm/Emscripten support for dynamic linking is incomplete; disable
# to avoid CMake warning.
cmake_args+=(-DWITH_SIMD=0 -DENABLE_SHARED=OFF)
fi
(
cd "${srcdir}"
export ${export_args[@]}
${cmake} \
-DCMAKE_INSTALL_PREFIX="${prefix}" \
"${cmake_args[@]}" ${pkgflags}
${make} -j${nproc}
${make} install
)
elif [[ "${package}" == "GIFLIB" ]]; then
# GIFLIB doesn't yet have a cmake build system. There is a pull
# request in giflib for adding CMakeLists.txt so this might not be
# needed in the future.
(
cd "${srcdir}"
local giflib_make_flags=(
CFLAGS="-O2 --target=${target} -std=gnu99"
PREFIX="${prefix}"
)
if [[ "${target}" != wasm* ]]; then
giflib_make_flags+=(CC=clang-7)
fi
# giflib make dependencies are not properly set up so parallel building
# doesn't work for everything.
${make} -j${nproc} libgif.a "${giflib_make_flags[@]}"
${make} -j${nproc} all "${giflib_make_flags[@]}"
${make} install "${giflib_make_flags[@]}"
)
else
echo "Don't know how to install ${package}"
exit 1
fi
# CMake mistakenly uses ".so" libraries and EMCC fails to link properly.
if [[ "${target}" == wasm* ]]; then
rm -f "${prefix}/lib"/*.so*
fi
done
}
# Packages that are manually unpacked for each architecture.
UNPACK_PKGS=(
libgif-dev
libclang-common-7-dev
# For OpenEXR:
libilmbase-dev
libopenexr-dev
# TCMalloc
libgoogle-perftools-dev
libtcmalloc-minimal4
libgoogle-perftools4
)
# Main script entry point.
main() {
cd "${MYDIR}"
# Configure the repositories with the sources for multi-arch cross
# compilation.
setup_apt
apt-get update -y
apt-get dist-upgrade -y
install_pkgs
install_binutils
apt clean
# Remove prebuilt Java classes cache.
rm /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/classes.jsa
# Manually extract packages for the target arch that can't install it directly
# at the same time as the native ones.
local ubarch
for ubarch in "${LIST_ARCHS[@]}"; do
if [[ "${ubarch}" != "amd64" ]]; then
local pkg
for pkg in "${UNPACK_PKGS[@]}"; do
apt download "${pkg}":"${ubarch}"
dpkg -x "${pkg}"_*_"${ubarch}".deb /
done
fi
done
# TODO: Add clang from the llvm repos. This is problematic since we are
# installing libclang-common-7-dev:"${ubarch}" from the ubuntu ports repos
# which is not available in the llvm repos so it might have a different
# version than the ubuntu ones.
# Remove the win32 libgcc version. The gcc-mingw-w64-x86-64 (and i686)
# packages install two libgcc versions:
# /usr/lib/gcc/x86_64-w64-mingw32/7.3-posix
# /usr/lib/gcc/x86_64-w64-mingw32/7.3-win32
# (exact libgcc version number depends on the package version).
#
# Clang will pick the best libgcc, sorting by version, but it doesn't
# seem to be a way to specify one or the other one, except by passing
# -nostdlib and setting all the include paths from the command line.
# To check which one is being used you can run:
# clang++-7 --target=x86_64-w64-mingw32 -v -print-libgcc-file-name
# We need to use the "posix" versions for thread support, so here we
# just remove the other one.
local target
for target in "${LIST_MINGW_TARGETS[@]}"; do
update-alternatives --set "${target}-gcc" $(which "${target}-gcc-posix")
local gcc_win32_path=$("${target}-cpp-win32" -print-libgcc-file-name)
rm -rf $(dirname "${gcc_win32_path}")
done
# TODO: Add msan for the target when cross-compiling. This only installs it
# for amd64.
./msan_install.sh
# Build and install qemu user-linux targets.
./qemu_install.sh
# Install emscripten SDK.
./emsdk_install.sh
# Setup environment for building WASM libraries from sources.
source /opt/emsdk/emsdk_env.sh
# Install some dependency libraries manually for the different targets.
install_from_source JPEG_TURBO "${LIST_MINGW_TARGETS[@]}" "${LIST_WASM_TARGETS[@]}"
install_from_source ZLIB "${LIST_MINGW_TARGETS[@]}" "${LIST_WASM_TARGETS[@]}"
install_from_source LIBPNG "${LIST_MINGW_TARGETS[@]}" "${LIST_WASM_TARGETS[@]}"
install_from_source GIFLIB "${LIST_MINGW_TARGETS[@]}" "${LIST_WASM_TARGETS[@]}"
# webp in Ubuntu is relatively old so we install it from source for everybody.
install_from_source WEBP "${LIST_TARGETS[@]}" "${LIST_MINGW_TARGETS[@]}"
install_from_source BENCHMARK "${LIST_TARGETS[@]}" "${LIST_MINGW_TARGETS[@]}"
# Install v8. v8 has better WASM SIMD support than NodeJS 14 (LTS).
# First we need the installer to install v8.
npm install jsvu -g
# install specific version;
HOME=/opt jsvu --os=linux64 "v8@${V8_VERSION}"
ln -s "/opt/.jsvu/v8-${V8_VERSION}" "/opt/.jsvu/v8"
# Cleanup.
find /var/lib/apt/lists/ -mindepth 1 -delete
}
main "$@"

View file

@ -1,131 +0,0 @@
#!/usr/bin/env bash
# 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.
set -eu
MYDIR=$(dirname $(realpath "$0"))
# Convenience flag to pass both CMAKE_C_FLAGS and CMAKE_CXX_FLAGS
CMAKE_FLAGS=${CMAKE_FLAGS:-}
CMAKE_C_FLAGS=${CMAKE_C_FLAGS:-${CMAKE_FLAGS}}
CMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS:-${CMAKE_FLAGS}}
CMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS:-}
CLANG_VERSION="${CLANG_VERSION:-}"
# Detect the clang version suffix and store it in CLANG_VERSION. For example,
# "6.0" for clang 6 or "7" for clang 7.
detect_clang_version() {
if [[ -n "${CLANG_VERSION}" ]]; then
return 0
fi
local clang_version=$("${CC:-clang}" --version | head -n1)
local llvm_tag
case "${clang_version}" in
"clang version 6."*)
CLANG_VERSION="6.0"
;;
"clang version 7."*)
CLANG_VERSION="7"
;;
"clang version 8."*)
CLANG_VERSION="8"
;;
"clang version 9."*)
CLANG_VERSION="9"
;;
*)
echo "Unknown clang version: ${clang_version}" >&2
return 1
esac
}
# Temporary files cleanup hooks.
CLEANUP_FILES=()
cleanup() {
if [[ ${#CLEANUP_FILES[@]} -ne 0 ]]; then
rm -fr "${CLEANUP_FILES[@]}"
fi
}
trap "{ set +x; } 2>/dev/null; cleanup" INT TERM EXIT
# Install libc++ libraries compiled with msan in the msan_prefix for the current
# compiler version.
cmd_msan_install() {
local tmpdir=$(mktemp -d)
CLEANUP_FILES+=("${tmpdir}")
# Detect the llvm to install:
export CC="${CC:-clang}"
export CXX="${CXX:-clang++}"
detect_clang_version
local llvm_tag
case "${CLANG_VERSION}" in
"6.0")
llvm_tag="llvmorg-6.0.1"
;;
"7")
llvm_tag="llvmorg-7.0.1"
;;
"8")
llvm_tag="llvmorg-8.0.0"
;;
*)
echo "Unknown clang version: ${clang_version}" >&2
return 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"
tar -C "${tmpdir}" -zxf "${llvm_targz}"
local llvm_root="${tmpdir}/llvm-project-${llvm_tag}"
local msan_prefix="${HOME}/.msan/${CLANG_VERSION}"
rm -rf "${msan_prefix}"
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_INSTALL_PREFIX="${msan_prefix}" \
${CMAKE_EXTRAS[${project}]}
cmake --build "${proj_build}"
ninja -C "${proj_build}" install
done
}
main() {
set -x
for version in 6.0 7 8; do
if ! which "clang-${version}" >/dev/null; then
echo "Skipping msan install for clang version ${version}"
continue
fi
(
trap "{ set +x; } 2>/dev/null; cleanup" INT TERM EXIT
export CLANG_VERSION=${version}
export CC=clang-${version}
export CXX=clang++-${version}
cmd_msan_install
) &
done
wait
}
main "$@"

View file

@ -1,83 +0,0 @@
#!/usr/bin/env bash
# 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.
QEMU_RELEASE="4.1.0"
QEMU_URL="https://download.qemu.org/qemu-${QEMU_RELEASE}.tar.xz"
QEMU_ARCHS=(
aarch64
arm
i386
# TODO: Consider adding these:
# aarch64_be
# mips64el
# mips64
# mips
# ppc64
# ppc
)
# Ubuntu packages not installed that are needed to build qemu.
QEMU_BUILD_DEPS=(
libglib2.0-dev
libpixman-1-dev
flex
bison
)
set -eu -x
# Temporary files cleanup hooks.
CLEANUP_FILES=()
cleanup() {
if [[ ${#CLEANUP_FILES[@]} -ne 0 ]]; then
rm -fr "${CLEANUP_FILES[@]}"
fi
}
trap "{ set +x; } 2>/dev/null; cleanup" INT TERM EXIT
main() {
local workdir=$(mktemp -d --suffix=qemu)
CLEANUP_FILES+=("${workdir}")
apt install -y "${QEMU_BUILD_DEPS[@]}"
local qemutar="${workdir}/qemu.tar.gz"
curl --output "${qemutar}" "${QEMU_URL}"
tar -Jxf "${qemutar}" -C "${workdir}"
local srcdir="${workdir}/qemu-${QEMU_RELEASE}"
local builddir="${workdir}/build"
local prefixdir="${workdir}/prefix"
mkdir -p "${builddir}"
# List of targets to build.
local targets=""
local make_targets=()
local target
for target in "${QEMU_ARCHS[@]}"; do
targets="${targets} ${target}-linux-user"
# Build just the linux-user targets.
make_targets+=("${target}-linux-user/all")
done
cd "${builddir}"
"${srcdir}/configure" \
--prefix="${prefixdir}" \
--static --disable-system --enable-linux-user \
--target-list="${targets}"
make -j $(nproc --all || echo 1) "${make_targets[@]}"
# Manually install these into the non-standard location. This script runs as
# root anyway.
for target in "${QEMU_ARCHS[@]}"; do
cp "${target}-linux-user/qemu-${target}" "/usr/bin/qemu-${target}-static"
done
apt autoremove -y --purge "${QEMU_BUILD_DEPS[@]}"
}
main "$@"

View file

@ -11,46 +11,18 @@ project(SAMPLE_LIBJXL LANGUAGES C CXX)
# Use pkg-config to find libjxl. # Use pkg-config to find libjxl.
find_package(PkgConfig) find_package(PkgConfig)
pkg_check_modules(Jxl REQUIRED IMPORTED_TARGET libjxl) pkg_check_modules(Jxl REQUIRED IMPORTED_TARGET libjxl libjxl_cms libjxl_threads)
pkg_check_modules(JxlThreads REQUIRED IMPORTED_TARGET libjxl_threads)
# Build the example encoder/decoder binaries using the default shared libraries # Build the example encoder/decoder binaries using the default shared libraries
# installed. # 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) add_executable(decode_oneshot decode_oneshot.cc)
target_link_libraries(decode_oneshot PkgConfig::Jxl PkgConfig::JxlThreads) target_link_libraries(decode_oneshot PkgConfig::Jxl)
add_executable(decode_progressive decode_progressive.cc) add_executable(decode_progressive decode_progressive.cc)
target_link_libraries(decode_progressive PkgConfig::Jxl PkgConfig::JxlThreads) target_link_libraries(decode_progressive PkgConfig::Jxl)
add_executable(encode_oneshot encode_oneshot.cc) add_executable(encode_oneshot encode_oneshot.cc)
target_link_libraries(encode_oneshot PkgConfig::Jxl PkgConfig::JxlThreads) target_link_libraries(encode_oneshot PkgConfig::Jxl)
# Building a static binary with the static libjxl dependencies. How to load
# static library configs from pkg-config and how to build static binaries
# depends on the platform, and building static binaries in general has problems.
# If you don't need static binaries you can remove this section.
add_library(StaticJxl INTERFACE IMPORTED GLOBAL)
set_target_properties(StaticJxl PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${Jxl_STATIC_INCLUDE_DIR}"
INTERFACE_COMPILE_OPTIONS "${Jxl_STATIC_CFLAGS_OTHER}"
INTERFACE_LINK_LIBRARIES "${Jxl_STATIC_LDFLAGS}"
)
add_library(StaticJxlThreads INTERFACE IMPORTED GLOBAL)
set_target_properties(StaticJxlThreads PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${JxlThreads_STATIC_INCLUDE_DIR}"
INTERFACE_COMPILE_OPTIONS "${JxlThreads_STATIC_CFLAGS_OTHER}"
# libgcc uses weak symbols for pthread which means that -lpthread is not
# linked when compiling a static binary. This is a platform-specific fix for
# that.
INTERFACE_LINK_LIBRARIES
"${JxlThreads_STATIC_LDFLAGS} -Wl,--whole-archive -lpthread -Wl,--no-whole-archive"
)
add_executable(decode_oneshot_static decode_oneshot.cc)
target_link_libraries(decode_oneshot_static
-static StaticJxl StaticJxlThreads)
add_executable(encode_oneshot_static encode_oneshot.cc)
target_link_libraries(encode_oneshot_static
-static StaticJxl StaticJxlThreads)

View file

@ -7,6 +7,8 @@
// available at once). The example outputs the pixels and color information to a // available at once). The example outputs the pixels and color information to a
// floating point image and an ICC profile on disk. // floating point image and an ICC profile on disk.
#include <jxl/decode.h>
#include <jxl/decode_cxx.h>
#include <limits.h> #include <limits.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
@ -14,16 +16,14 @@
#include <vector> #include <vector>
#include "jxl/decode.h"
#include "jxl/decode_cxx.h"
bool DecodeJpegXlExif(const uint8_t* jxl, size_t size, bool DecodeJpegXlExif(const uint8_t* jxl, size_t size,
std::vector<uint8_t>* exif) { std::vector<uint8_t>* exif) {
auto dec = JxlDecoderMake(nullptr); auto dec = JxlDecoderMake(nullptr);
// We're only interested in the Exif boxes in this example, so don't // We're only interested in the Exif boxes in this example, so don't
// subscribe to events related to pixel data. // 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"); fprintf(stderr, "JxlDecoderSubscribeEvents failed\n");
return false; return false;
} }
@ -57,8 +57,9 @@ bool DecodeJpegXlExif(const uint8_t* jxl, size_t size,
return true; return true;
} }
JxlBoxType type; JxlBoxType type;
if (JXL_DEC_SUCCESS != status = JxlDecoderGetBoxType(dec.get(), type,
JxlDecoderGetBoxType(dec.get(), type, support_decompression)) { TO_JXL_BOOL(support_decompression));
if (JXL_DEC_SUCCESS != status) {
fprintf(stderr, "Error, failed to get box type\n"); fprintf(stderr, "Error, failed to get box type\n");
return false; return false;
} }
@ -72,7 +73,7 @@ bool DecodeJpegXlExif(const uint8_t* jxl, size_t size,
exif->resize(exif->size() + kChunkSize); exif->resize(exif->size() + kChunkSize);
JxlDecoderSetBoxBuffer(dec.get(), exif->data() + output_pos, JxlDecoderSetBoxBuffer(dec.get(), exif->data() + output_pos,
exif->size() - output_pos); exif->size() - output_pos);
} else if (status == JXL_DEC_SUCCESS) { } else if (status == JXL_DEC_BOX_COMPLETE) {
if (!exif->empty()) { if (!exif->empty()) {
size_t remaining = JxlDecoderReleaseBoxBuffer(dec.get()); size_t remaining = JxlDecoderReleaseBoxBuffer(dec.get());
exif->resize(exif->size() - remaining); exif->resize(exif->size() - remaining);
@ -97,7 +98,7 @@ bool LoadFile(const char* filename, std::vector<uint8_t>* out) {
return false; return false;
} }
long size = ftell(file); long size = ftell(file); // NOLINT
// Avoid invalid file or directory. // Avoid invalid file or directory.
if (size >= LONG_MAX || size < 0) { if (size >= LONG_MAX || size < 0) {
fclose(file); fclose(file);

View file

@ -7,7 +7,12 @@
// available at once). The example outputs the pixels and color information to a // available at once). The example outputs the pixels and color information to a
// floating point image and an ICC profile on disk. // floating point image and an ICC profile on disk.
#include <inttypes.h> #include <jxl/codestream_header.h>
#include <jxl/decode.h>
#include <jxl/decode_cxx.h>
#include <jxl/resizable_parallel_runner.h>
#include <jxl/resizable_parallel_runner_cxx.h>
#include <jxl/types.h>
#include <limits.h> #include <limits.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
@ -15,11 +20,6 @@
#include <vector> #include <vector>
#include "jxl/decode.h"
#include "jxl/decode_cxx.h"
#include "jxl/resizable_parallel_runner.h"
#include "jxl/resizable_parallel_runner_cxx.h"
/** Decodes JPEG XL image to floating point pixels and ICC Profile. Pixel are /** Decodes JPEG XL image to floating point pixels and ICC Profile. Pixel are
* stored as floating point, as interleaved RGBA (4 floating point values per * stored as floating point, as interleaved RGBA (4 floating point values per
* pixel), line per line from top to bottom. Pixel values have nominal range * pixel), line per line from top to bottom. Pixel values have nominal range
@ -77,15 +77,14 @@ bool DecodeJpegXlOneShot(const uint8_t* jxl, size_t size,
// Get the ICC color profile of the pixel data // Get the ICC color profile of the pixel data
size_t icc_size; size_t icc_size;
if (JXL_DEC_SUCCESS != if (JXL_DEC_SUCCESS !=
JxlDecoderGetICCProfileSize( JxlDecoderGetICCProfileSize(dec.get(), JXL_COLOR_PROFILE_TARGET_DATA,
dec.get(), &format, JXL_COLOR_PROFILE_TARGET_DATA, &icc_size)) { &icc_size)) {
fprintf(stderr, "JxlDecoderGetICCProfileSize failed\n"); fprintf(stderr, "JxlDecoderGetICCProfileSize failed\n");
return false; return false;
} }
icc_profile->resize(icc_size); icc_profile->resize(icc_size);
if (JXL_DEC_SUCCESS != JxlDecoderGetColorAsICCProfile( if (JXL_DEC_SUCCESS != JxlDecoderGetColorAsICCProfile(
dec.get(), &format, dec.get(), JXL_COLOR_PROFILE_TARGET_DATA,
JXL_COLOR_PROFILE_TARGET_DATA,
icc_profile->data(), icc_profile->size())) { icc_profile->data(), icc_profile->size())) {
fprintf(stderr, "JxlDecoderGetColorAsICCProfile failed\n"); fprintf(stderr, "JxlDecoderGetColorAsICCProfile failed\n");
return false; return false;
@ -98,13 +97,13 @@ bool DecodeJpegXlOneShot(const uint8_t* jxl, size_t size,
return false; return false;
} }
if (buffer_size != *xsize * *ysize * 16) { if (buffer_size != *xsize * *ysize * 16) {
fprintf(stderr, "Invalid out buffer size %" PRIu64 " %" PRIu64 "\n", fprintf(stderr, "Invalid out buffer size %d %d\n",
static_cast<uint64_t>(buffer_size), static_cast<int>(buffer_size),
static_cast<uint64_t>(*xsize * *ysize * 16)); static_cast<int>(*xsize * *ysize * 16));
return false; return false;
} }
pixels->resize(*xsize * *ysize * 4); pixels->resize(*xsize * *ysize * 4);
void* pixels_buffer = (void*)pixels->data(); void* pixels_buffer = static_cast<void*>(pixels->data());
size_t pixels_buffer_size = pixels->size() * sizeof(float); size_t pixels_buffer_size = pixels->size() * sizeof(float);
if (JXL_DEC_SUCCESS != JxlDecoderSetImageOutBuffer(dec.get(), &format, if (JXL_DEC_SUCCESS != JxlDecoderSetImageOutBuffer(dec.get(), &format,
pixels_buffer, pixels_buffer,
@ -143,8 +142,8 @@ bool WritePFM(const char* filename, const float* pixels, size_t xsize,
uint8_t little_endian[4]; uint8_t little_endian[4];
memcpy(little_endian, &endian_test, 4); memcpy(little_endian, &endian_test, 4);
fprintf(file, "PF\n%d %d\n%s\n", (int)xsize, (int)ysize, fprintf(file, "PF\n%d %d\n%s\n", static_cast<int>(xsize),
little_endian[0] ? "-1.0" : "1.0"); static_cast<int>(ysize), little_endian[0] ? "-1.0" : "1.0");
for (int y = ysize - 1; y >= 0; y--) { for (int y = ysize - 1; y >= 0; y--) {
for (size_t x = 0; x < xsize; x++) { for (size_t x = 0; x < xsize; x++) {
for (size_t c = 0; c < 3; c++) { for (size_t c = 0; c < 3; c++) {
@ -170,7 +169,7 @@ bool LoadFile(const char* filename, std::vector<uint8_t>* out) {
return false; return false;
} }
long size = ftell(file); long size = ftell(file); // NOLINT
// Avoid invalid file or directory. // Avoid invalid file or directory.
if (size >= LONG_MAX || size < 0) { if (size >= LONG_MAX || size < 0) {
fclose(file); fclose(file);
@ -229,7 +228,8 @@ int main(int argc, char* argv[]) {
std::vector<float> pixels; std::vector<float> pixels;
std::vector<uint8_t> icc_profile; std::vector<uint8_t> icc_profile;
size_t xsize = 0, ysize = 0; size_t xsize = 0;
size_t ysize = 0;
if (!DecodeJpegXlOneShot(jxl.data(), jxl.size(), &pixels, &xsize, &ysize, if (!DecodeJpegXlOneShot(jxl.data(), jxl.size(), &pixels, &xsize, &ysize,
&icc_profile)) { &icc_profile)) {
fprintf(stderr, "Error while decoding the jxl file\n"); fprintf(stderr, "Error while decoding the jxl file\n");

View file

@ -6,19 +6,22 @@
// This C++ example decodes a JPEG XL image progressively (input bytes are // This C++ example decodes a JPEG XL image progressively (input bytes are
// passed in chunks). The example outputs the intermediate steps to PAM files. // passed in chunks). The example outputs the intermediate steps to PAM files.
#include <inttypes.h> #ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif
#include <jxl/decode.h>
#include <jxl/decode_cxx.h>
#include <jxl/resizable_parallel_runner.h>
#include <jxl/resizable_parallel_runner_cxx.h>
#include <limits.h> #include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <cinttypes> // PRIu64
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <vector> #include <vector>
#include "jxl/decode.h"
#include "jxl/decode_cxx.h"
#include "jxl/resizable_parallel_runner.h"
#include "jxl/resizable_parallel_runner_cxx.h"
bool WritePAM(const char* filename, const uint8_t* buffer, size_t w, size_t h) { bool WritePAM(const char* filename, const uint8_t* buffer, size_t w, size_t h) {
FILE* fp = fopen(filename, "wb"); FILE* fp = fopen(filename, "wb");
if (!fp) { if (!fp) {
@ -26,11 +29,14 @@ bool WritePAM(const char* filename, const uint8_t* buffer, size_t w, size_t h) {
return false; return false;
} }
fprintf(fp, fprintf(fp,
"P7\nWIDTH %" PRIu64 "\nHEIGHT %" PRIu64 "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 4\nMAXVAL 255\nTUPLTYPE "
"\nDEPTH 4\nMAXVAL 255\nTUPLTYPE "
"RGB_ALPHA\nENDHDR\n", "RGB_ALPHA\nENDHDR\n",
static_cast<uint64_t>(w), static_cast<uint64_t>(h)); static_cast<int>(w), static_cast<int>(h));
fwrite(buffer, 1, w * h * 4, fp); size_t num_bytes = w * h * 4;
if (fwrite(buffer, 1, num_bytes, fp) != num_bytes) {
fclose(fp);
return false;
};
if (fclose(fp) != 0) { if (fclose(fp) != 0) {
return false; return false;
} }
@ -44,7 +50,8 @@ bool DecodeJpegXlProgressive(const uint8_t* jxl, size_t size,
const char* filename, size_t chunksize) { const char* filename, size_t chunksize) {
std::vector<uint8_t> pixels; std::vector<uint8_t> pixels;
std::vector<uint8_t> icc_profile; std::vector<uint8_t> icc_profile;
size_t xsize = 0, ysize = 0; size_t xsize = 0;
size_t ysize = 0;
// Multi-threaded parallel runner. // Multi-threaded parallel runner.
auto runner = JxlResizableParallelRunnerMake(nullptr); auto runner = JxlResizableParallelRunnerMake(nullptr);
@ -121,16 +128,14 @@ bool DecodeJpegXlProgressive(const uint8_t* jxl, size_t size,
// Get the ICC color profile of the pixel data // Get the ICC color profile of the pixel data
size_t icc_size; size_t icc_size;
if (JXL_DEC_SUCCESS != if (JXL_DEC_SUCCESS !=
JxlDecoderGetICCProfileSize(dec.get(), &format, JxlDecoderGetICCProfileSize(
JXL_COLOR_PROFILE_TARGET_ORIGINAL, dec.get(), JXL_COLOR_PROFILE_TARGET_ORIGINAL, &icc_size)) {
&icc_size)) {
fprintf(stderr, "JxlDecoderGetICCProfileSize failed\n"); fprintf(stderr, "JxlDecoderGetICCProfileSize failed\n");
return false; return false;
} }
icc_profile.resize(icc_size); icc_profile.resize(icc_size);
if (JXL_DEC_SUCCESS != JxlDecoderGetColorAsICCProfile( if (JXL_DEC_SUCCESS != JxlDecoderGetColorAsICCProfile(
dec.get(), &format, dec.get(), JXL_COLOR_PROFILE_TARGET_ORIGINAL,
JXL_COLOR_PROFILE_TARGET_ORIGINAL,
icc_profile.data(), icc_profile.size())) { icc_profile.data(), icc_profile.size())) {
fprintf(stderr, "JxlDecoderGetColorAsICCProfile failed\n"); fprintf(stderr, "JxlDecoderGetColorAsICCProfile failed\n");
return false; return false;
@ -149,11 +154,9 @@ bool DecodeJpegXlProgressive(const uint8_t* jxl, size_t size,
return false; return false;
} }
pixels.resize(xsize * ysize * 4); pixels.resize(xsize * ysize * 4);
void* pixels_buffer = (void*)pixels.data();
size_t pixels_buffer_size = pixels.size() * sizeof(float);
if (JXL_DEC_SUCCESS != JxlDecoderSetImageOutBuffer(dec.get(), &format, if (JXL_DEC_SUCCESS != JxlDecoderSetImageOutBuffer(dec.get(), &format,
pixels_buffer, pixels.data(),
pixels_buffer_size)) { pixels.size())) {
fprintf(stderr, "JxlDecoderSetImageOutBuffer failed\n"); fprintf(stderr, "JxlDecoderSetImageOutBuffer failed\n");
return false; return false;
} }
@ -175,7 +178,7 @@ bool LoadFile(const char* filename, std::vector<uint8_t>* out) {
return false; return false;
} }
long size = ftell(file); long size = ftell(file); // NOLINT
// Avoid invalid file or directory. // Avoid invalid file or directory.
if (size >= LONG_MAX || size < 0) { if (size >= LONG_MAX || size < 0) {
fclose(file); fclose(file);
@ -221,7 +224,7 @@ int main(int argc, char* argv[]) {
} }
size_t chunksize = jxl.size(); size_t chunksize = jxl.size();
if (argc > 3) { if (argc > 3) {
long cs = atol(argv[3]); long cs = atol(argv[3]); // NOLINT
if (cs < 100) { if (cs < 100) {
fprintf(stderr, "Chunk size is too low, try at least 100 bytes\n"); fprintf(stderr, "Chunk size is too low, try at least 100 bytes\n");
return 1; return 1;

View file

@ -6,18 +6,22 @@
// This example encodes a file containing a floating point image to another // This example encodes a file containing a floating point image to another
// file containing JPEG XL image with a single frame. // file containing JPEG XL image with a single frame.
#include <jxl/codestream_header.h>
#include <jxl/color_encoding.h>
#include <jxl/encode.h>
#include <jxl/encode_cxx.h>
#include <jxl/thread_parallel_runner.h>
#include <jxl/thread_parallel_runner_cxx.h>
#include <jxl/types.h>
#include <limits.h> #include <limits.h>
#include <string.h> #include <string.h>
#include <cstdint>
#include <cstdio>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <vector> #include <vector>
#include "jxl/encode.h"
#include "jxl/encode_cxx.h"
#include "jxl/thread_parallel_runner.h"
#include "jxl/thread_parallel_runner_cxx.h"
/** /**
* Reads from .pfm file (Portable FloatMap) * Reads from .pfm file (Portable FloatMap)
* *
@ -35,15 +39,16 @@ bool ReadPFM(const char* filename, std::vector<float>* pixels, uint32_t* xsize,
return false; return false;
} }
uint32_t endian_test = 1; uint32_t endian_test = 1;
uint8_t little_endian[4]; uint8_t little_endian_check[4];
memcpy(little_endian, &endian_test, 4); memcpy(little_endian_check, &endian_test, 4);
bool little_endian = (little_endian_check[0] == 1);
if (fseek(file, 0, SEEK_END) != 0) { if (fseek(file, 0, SEEK_END) != 0) {
fclose(file); fclose(file);
return false; return false;
} }
long size = ftell(file); long size = ftell(file); // NOLINT
// Avoid invalid file or directory. // Avoid invalid file or directory.
if (size >= LONG_MAX || size < 0) { if (size >= LONG_MAX || size < 0) {
fclose(file); fclose(file);
@ -59,7 +64,8 @@ bool ReadPFM(const char* filename, std::vector<float>* pixels, uint32_t* xsize,
data.resize(size); data.resize(size);
size_t readsize = fread(data.data(), 1, size, file); size_t readsize = fread(data.data(), 1, size, file);
if ((long)readsize != size) { if (static_cast<long>(readsize) != size) { // NOLINT
fclose(file);
return false; return false;
} }
if (fclose(file) != 0) { if (fclose(file) != 0) {
@ -111,12 +117,13 @@ bool ReadPFM(const char* filename, std::vector<float>* pixels, uint32_t* xsize,
fprintf(stderr, fprintf(stderr,
"%s doesn't seem to be a Portable FloatMap file (pixel data bytes " "%s doesn't seem to be a Portable FloatMap file (pixel data bytes "
"are %d, but expected %d * %d * 3 * 4 + %d (%d).\n", "are %d, but expected %d * %d * 3 * 4 + %d (%d).\n",
filename, (int)data.size(), (int)*ysize, (int)*xsize, (int)offset, filename, static_cast<int>(data.size()), static_cast<int>(*ysize),
(int)(*ysize * *xsize * 3 * 4 + offset)); static_cast<int>(*xsize), static_cast<int>(offset),
static_cast<int>(*ysize * *xsize * 3 * 4 + offset));
return false; return false;
} }
if (!!little_endian[0] != input_little_endian) { if (little_endian != input_little_endian) {
fprintf(stderr, fprintf(stderr,
"%s has a different endianness than we do, conversion is not " "%s has a different endianness than we do, conversion is not "
"supported.\n", "supported.\n",
@ -127,7 +134,7 @@ bool ReadPFM(const char* filename, std::vector<float>* pixels, uint32_t* xsize,
pixels->resize(*ysize * *xsize * 3); pixels->resize(*ysize * *xsize * 3);
for (int y = *ysize - 1; y >= 0; y--) { for (int y = *ysize - 1; y >= 0; y--) {
for (int x = 0; x < (int)*xsize; x++) { for (int x = 0; x < static_cast<int>(*xsize); x++) {
for (int c = 0; c < 3; c++) { for (int c = 0; c < 3; c++) {
memcpy(pixels->data() + (y * *xsize + x) * 3 + c, data.data() + offset, memcpy(pixels->data() + (y * *xsize + x) * 3 + c, data.data() + offset,
sizeof(float)); sizeof(float));
@ -175,8 +182,8 @@ bool EncodeJxlOneshot(const std::vector<float>& pixels, const uint32_t xsize,
} }
JxlColorEncoding color_encoding = {}; JxlColorEncoding color_encoding = {};
JxlColorEncodingSetToSRGB(&color_encoding, JXL_BOOL is_gray = TO_JXL_BOOL(pixel_format.num_channels < 3);
/*is_gray=*/pixel_format.num_channels < 3); JxlColorEncodingSetToSRGB(&color_encoding, is_gray);
if (JXL_ENC_SUCCESS != if (JXL_ENC_SUCCESS !=
JxlEncoderSetColorEncoding(enc.get(), &color_encoding)) { JxlEncoderSetColorEncoding(enc.get(), &color_encoding)) {
fprintf(stderr, "JxlEncoderSetColorEncoding failed\n"); fprintf(stderr, "JxlEncoderSetColorEncoding failed\n");
@ -188,7 +195,7 @@ bool EncodeJxlOneshot(const std::vector<float>& pixels, const uint32_t xsize,
if (JXL_ENC_SUCCESS != if (JXL_ENC_SUCCESS !=
JxlEncoderAddImageFrame(frame_settings, &pixel_format, JxlEncoderAddImageFrame(frame_settings, &pixel_format,
(void*)pixels.data(), static_cast<const void*>(pixels.data()),
sizeof(float) * pixels.size())) { sizeof(float) * pixels.size())) {
fprintf(stderr, "JxlEncoderAddImageFrame failed\n"); fprintf(stderr, "JxlEncoderAddImageFrame failed\n");
return false; return false;
@ -229,6 +236,7 @@ bool WriteFile(const std::vector<uint8_t>& bytes, const char* filename) {
if (fwrite(bytes.data(), sizeof(uint8_t), bytes.size(), file) != if (fwrite(bytes.data(), sizeof(uint8_t), bytes.size(), file) !=
bytes.size()) { bytes.size()) {
fprintf(stderr, "Could not write bytes to %s\n", filename); fprintf(stderr, "Could not write bytes to %s\n", filename);
fclose(file);
return false; return false;
} }
if (fclose(file) != 0) { if (fclose(file) != 0) {

View file

@ -3,6 +3,8 @@
# Use of this source code is governed by a BSD-style # Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file. # 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) add_executable(decode_oneshot ${CMAKE_CURRENT_LIST_DIR}/decode_oneshot.cc)
target_link_libraries(decode_oneshot jxl_dec jxl_threads) target_link_libraries(decode_oneshot jxl_dec jxl_threads)
add_executable(decode_progressive ${CMAKE_CURRENT_LIST_DIR}/decode_progressive.cc) add_executable(decode_progressive ${CMAKE_CURRENT_LIST_DIR}/decode_progressive.cc)

File diff suppressed because it is too large Load diff

View file

@ -1,14 +0,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.
#ifndef FAST_LOSSLESS_H
#define FAST_LOSSLESS_H
#include <stdlib.h>
size_t FastLosslessEncode(const unsigned char* rgba, size_t width,
size_t row_stride, size_t height, size_t nb_chans,
size_t bitdepth, int effort, unsigned char** output);
#endif

61
media/libjxl/src/flake.lock generated Normal file
View file

@ -0,0 +1,61 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1701680307,
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1702312524,
"narHash": "sha256-gkZJRDBUCpTPBvQk25G0B7vfbpEYM5s5OZqghkjZsnE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "a9bf124c46ef298113270b1f84a164865987a91c",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

View file

@ -0,0 +1,38 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem
(system:
let
pkgs = import nixpkgs {
inherit system;
};
in
with pkgs;
{
devShells.default = mkShell {
buildInputs = [
clang
cmake
pkg-config
gtest
doxygen
graphviz
python3
libclang.python
libpng
giflib
lcms2
brotli
];
shellHook = ''
export CC=clang
export CXX=clang++
'';
};
}
);
}

314
media/libjxl/src/lib/BUILD Normal file
View file

@ -0,0 +1,314 @@
# 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.
load("@bazel_skylib//rules:copy_file.bzl", "copy_file")
load("@bazel_skylib//rules:expand_template.bzl", "expand_template")
# Load sources/headers/tests lists.
load(
"jxl_lists.bzl",
"libjxl_base_sources",
"libjxl_cms_sources",
"libjxl_codec_apng_sources",
"libjxl_codec_exr_sources",
"libjxl_codec_gif_sources",
"libjxl_codec_jpegli_sources",
"libjxl_codec_jpg_sources",
"libjxl_codec_jxl_sources",
"libjxl_codec_npy_sources",
"libjxl_codec_pgx_sources",
"libjxl_codec_pnm_sources",
"libjxl_dec_box_sources",
"libjxl_dec_jpeg_sources",
"libjxl_dec_sources",
"libjxl_enc_sources",
"libjxl_extras_for_tools_sources",
"libjxl_extras_sources",
# "libjxl_gbench_sources",
# "libjxl_jpegli_lib_version",
"libjxl_jpegli_libjpeg_helper_files",
"libjxl_jpegli_sources",
"libjxl_jpegli_testlib_files",
"libjxl_jpegli_tests",
"libjxl_major_version",
"libjxl_minor_version",
"libjxl_patch_version",
"libjxl_public_headers",
"libjxl_testlib_files",
"libjxl_tests",
"libjxl_threads_public_headers",
"libjxl_threads_sources",
)
load(
"jxl_vars.bzl",
"libjxl_deps_brotli",
"libjxl_deps_exr",
"libjxl_deps_gif",
"libjxl_deps_gtest",
"libjxl_deps_hwy",
"libjxl_deps_hwy_nanobenchmark",
"libjxl_deps_hwy_test_util",
"libjxl_deps_jpeg",
"libjxl_deps_png",
"libjxl_deps_runfiles",
"libjxl_deps_skcms",
# "libjxl_deps_testdata",
# "libjxl_deps_webp",
"libjxl_root_package",
"libjxl_test_shards",
"libjxl_test_timeouts",
)
DEFAULT_VISIBILITY = ["//:__subpackages__"]
DEFAULT_COMPATIBILITY = []
INCLUDES_DIR = "include"
package(
default_visibility = DEFAULT_VISIBILITY,
)
licenses(["notice"])
exports_files(["LICENSE"])
EXPORT_TEMPLATE = """
#ifndef @_EXPORT_H
#define @_EXPORT_H
#define @_EXPORT
#define @_NO_EXPORT
#ifndef @_DEPRECATED
# define @_DEPRECATED __attribute__ ((__deprecated__))
#endif
#endif
"""
JXL_EXPORT_H = INCLUDES_DIR + "/jxl/jxl_export.h"
genrule(
name = "create_jxl_export",
outs = [JXL_EXPORT_H],
cmd = "echo '" + EXPORT_TEMPLATE.replace("@", "JXL") + "' > $@",
compatible_with = DEFAULT_COMPATIBILITY,
)
JXL_CMS_EXPORT_H = INCLUDES_DIR + "/jxl/jxl_cms_export.h"
genrule(
name = "create_jxl_cms_export",
outs = [JXL_CMS_EXPORT_H],
cmd = "echo '" + EXPORT_TEMPLATE.replace("@", "JXL_CMS") + "' > $@",
compatible_with = DEFAULT_COMPATIBILITY,
)
JXL_THREADS_EXPORT_H = INCLUDES_DIR + "/jxl/jxl_threads_export.h"
genrule(
name = "create_jxl_threads_export",
outs = [JXL_THREADS_EXPORT_H],
cmd = "echo '" + EXPORT_TEMPLATE.replace("@", "JXL_THREADS") + "' > $@",
compatible_with = DEFAULT_COMPATIBILITY,
)
JXL_VERSION_H = INCLUDES_DIR + "/jxl/version.h"
expand_template(
name = "expand_jxl_version",
out = JXL_VERSION_H,
compatible_with = DEFAULT_COMPATIBILITY,
substitutions = {
"@JPEGXL_MAJOR_VERSION@": str(libjxl_major_version),
"@JPEGXL_MINOR_VERSION@": str(libjxl_minor_version),
"@JPEGXL_PATCH_VERSION@": str(libjxl_patch_version),
},
template = "jxl/version.h.in",
)
cc_library(
name = "jxl_version",
hdrs = [JXL_VERSION_H],
compatible_with = DEFAULT_COMPATIBILITY,
strip_include_prefix = INCLUDES_DIR,
)
JPEGLI_JCONFIG_H = INCLUDES_DIR + "/jpegli/jconfig.h"
JPEGLI_JMORECFG_H = INCLUDES_DIR + "/jpegli/jmorecfg.h"
JPEGLI_JPEGLIB_H = INCLUDES_DIR + "/jpegli/jpeglib.h"
copy_file(
name = "expand_jconfig",
src = "@libjpeg_turbo//:jconfig.h",
out = JPEGLI_JCONFIG_H,
compatible_with = DEFAULT_COMPATIBILITY,
)
copy_file(
name = "copy_jmorecfg",
src = "@libjpeg_turbo//:jmorecfg.h",
out = JPEGLI_JMORECFG_H,
compatible_with = DEFAULT_COMPATIBILITY,
)
copy_file(
name = "copy_jpeglib",
src = "@libjpeg_turbo//:jpeglib.h",
out = JPEGLI_JPEGLIB_H,
compatible_with = DEFAULT_COMPATIBILITY,
)
cc_library(
name = "includes",
hdrs = libjxl_public_headers + [
JXL_EXPORT_H,
JXL_CMS_EXPORT_H,
],
compatible_with = DEFAULT_COMPATIBILITY,
strip_include_prefix = INCLUDES_DIR,
deps = [":jxl_version"],
)
cc_library(
name = "libjpeg_includes",
hdrs = [
JPEGLI_JCONFIG_H,
JPEGLI_JMORECFG_H,
JPEGLI_JPEGLIB_H,
],
compatible_with = DEFAULT_COMPATIBILITY,
strip_include_prefix = INCLUDES_DIR + "/jpegli",
)
cc_library(
name = "base",
srcs = [path for path in libjxl_base_sources if path.endswith(".cc")],
hdrs = [path for path in libjxl_base_sources if path.endswith(".h")],
compatible_with = DEFAULT_COMPATIBILITY,
deps = [
":includes",
] + libjxl_deps_hwy,
)
cc_library(
name = "jpegxl",
srcs = libjxl_dec_sources + libjxl_dec_box_sources + libjxl_dec_jpeg_sources + libjxl_enc_sources + libjxl_cms_sources,
compatible_with = DEFAULT_COMPATIBILITY,
defines = [
"JPEGXL_ENABLE_SKCMS=1",
],
deps = [
":base",
":includes",
] + libjxl_deps_brotli + libjxl_deps_hwy + libjxl_deps_skcms,
)
cc_library(
name = "jpegxl_private",
hdrs = [
path
for path in libjxl_dec_sources + libjxl_dec_box_sources + libjxl_dec_jpeg_sources + libjxl_enc_sources + libjxl_cms_sources
if path.endswith(".h") and not path.endswith("-inl.h")
],
compatible_with = DEFAULT_COMPATIBILITY,
deps = [":jpegxl"],
)
cc_library(
name = "jpegxl_threads",
srcs = libjxl_threads_sources,
hdrs = libjxl_threads_public_headers + [JXL_THREADS_EXPORT_H],
compatible_with = DEFAULT_COMPATIBILITY,
strip_include_prefix = INCLUDES_DIR,
deps = [
":base",
":includes",
],
)
CODEC_FILES = libjxl_codec_apng_sources + libjxl_codec_exr_sources + libjxl_codec_gif_sources + libjxl_codec_jpegli_sources + libjxl_codec_jpg_sources + libjxl_codec_jxl_sources + libjxl_codec_npy_sources + libjxl_codec_pgx_sources + libjxl_codec_pnm_sources
CODEC_SRCS = [path for path in CODEC_FILES if path.endswith(".cc")]
CODEC_HDRS = [path for path in CODEC_FILES if path.endswith(".h")]
cc_library(
name = "jpegli",
srcs = libjxl_jpegli_sources,
hdrs = [
"jpegli/common_internal.h", # TODO(eustas): should not be here
],
compatible_with = DEFAULT_COMPATIBILITY,
deps = [
":jpegxl_private",
":libjpeg_includes",
] + libjxl_deps_hwy,
)
# TODO(eustas): build codecs separately?
cc_library(
name = "jpegxl_extras",
srcs = libjxl_extras_sources + libjxl_extras_for_tools_sources + CODEC_SRCS,
hdrs = CODEC_HDRS,
compatible_with = DEFAULT_COMPATIBILITY,
defines = [
"JPEGXL_ENABLE_APNG=1",
"JPEGXL_ENABLE_EXR=1",
"JPEGXL_ENABLE_GIF=1",
"JPEGXL_ENABLE_JPEG=1",
"JPEGXL_ENABLE_JPEGLI=1",
],
deps = [
":jpegli",
":jpegxl_private",
":jpegxl_threads",
":jxl_version",
] + libjxl_deps_exr + libjxl_deps_gif + libjxl_deps_jpeg + libjxl_deps_png,
)
TESTLIB_FILES = libjxl_testlib_files + libjxl_jpegli_testlib_files + libjxl_jpegli_libjpeg_helper_files
cc_library(
name = "test_utils",
testonly = 1,
srcs = [path for path in TESTLIB_FILES if not path.endswith(".h")],
hdrs = [path for path in TESTLIB_FILES if path.endswith(".h")],
compatible_with = DEFAULT_COMPATIBILITY,
defines = [
'JPEGXL_ROOT_PACKAGE=\'"' + libjxl_root_package + '"\'',
],
deps = [
":jpegli",
":jpegxl_extras",
":jpegxl_private",
] + libjxl_deps_runfiles,
)
TESTS = [path.partition(".")[0] for path in libjxl_tests + libjxl_jpegli_tests]
[
cc_test(
name = test,
timeout = libjxl_test_timeouts.get(test, "moderate"),
srcs = [
test + ".cc",
"jpegli/testing.h",
"jxl/testing.h",
],
data = ["//:testdata"],
shard_count = libjxl_test_shards.get(test, 1),
deps = [
":jpegxl_extras",
":jpegxl_private",
":jpegxl_threads",
":test_utils",
] + libjxl_deps_gtest + libjxl_deps_hwy_test_util + libjxl_deps_hwy_nanobenchmark,
)
for test in TESTS
]

View file

@ -4,8 +4,8 @@
# license that can be found in the LICENSE file. # license that can be found in the LICENSE file.
set(JPEGXL_MAJOR_VERSION 0) set(JPEGXL_MAJOR_VERSION 0)
set(JPEGXL_MINOR_VERSION 7) set(JPEGXL_MINOR_VERSION 11)
set(JPEGXL_PATCH_VERSION 0) set(JPEGXL_PATCH_VERSION 1)
set(JPEGXL_LIBRARY_VERSION set(JPEGXL_LIBRARY_VERSION
"${JPEGXL_MAJOR_VERSION}.${JPEGXL_MINOR_VERSION}.${JPEGXL_PATCH_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 # 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 # so that programs that depend on libjxl can update their dependencies. Semantic
# versioning allows 0.y.z to have incompatible changes in minor versions. # versioning allows 0.y.z to have incompatible changes in minor versions.
set(JPEGXL_SO_MINOR_VERSION 7) set(JPEGXL_SO_MINOR_VERSION 11)
if (JPEGXL_MAJOR_VERSION EQUAL 0) if (JPEGXL_MAJOR_VERSION EQUAL 0)
set(JPEGXL_LIBRARY_SOVERSION set(JPEGXL_LIBRARY_SOVERSION
"${JPEGXL_MAJOR_VERSION}.${JPEGXL_SO_MINOR_VERSION}") "${JPEGXL_MAJOR_VERSION}.${JPEGXL_SO_MINOR_VERSION}")
@ -122,45 +122,72 @@ else() # WIN32
) )
endif() # Clang endif() # Clang
endif() # WIN32 endif() # WIN32
# Internal flags for coverage builds:
if(JPEGXL_ENABLE_COVERAGE)
set(JPEGXL_COVERAGE_FLAGS
-g -O0 -fprofile-arcs -ftest-coverage
-DJXL_ENABLE_ASSERT=0 -DJXL_ENABLE_CHECK=0
)
endif() # JPEGXL_ENABLE_COVERAGE
endif() #!MSVC endif() #!MSVC
if (JPEGXL_ENABLE_SKCMS)
list(APPEND JPEGXL_INTERNAL_FLAGS -DJPEGXL_ENABLE_SKCMS=1)
endif ()
# strips the -internal suffix from all the elements in LIST
function(strip_internal OUTPUT_VAR LIB_LIST)
foreach(lib IN LISTS ${LIB_LIST})
string(REGEX REPLACE "-internal$" "" lib "${lib}")
list(APPEND out_list "${lib}")
endforeach()
set(${OUTPUT_VAR} ${out_list} PARENT_SCOPE)
endfunction()
# set variables for jxl_cms.cmake and jxl.cmake
if(IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}")
set(PKGCONFIG_TARGET_INCLUDES "${CMAKE_INSTALL_INCLUDEDIR}")
else()
set(PKGCONFIG_TARGET_INCLUDES "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
endif()
if(IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}")
set(PKGCONFIG_TARGET_LIBS "${CMAKE_INSTALL_LIBDIR}")
else()
set(PKGCONFIG_TARGET_LIBS "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
endif()
include(CheckCXXSymbolExists)
set(PKGCONFIG_CXX_LIB "")
check_cxx_symbol_exists(__GLIBCXX__ iostream LIBSTDCXX)
check_cxx_symbol_exists(_LIBCPP_VERSION iostream LIBCXX)
if(LIBSTDCXX)
set(PKGCONFIG_CXX_LIB "-lstdc++")
elseif(LIBCXX)
set(PKGCONFIG_CXX_LIB "-lc++")
endif()
# The jxl_cms library definition.
include(jxl_cms.cmake)
# The jxl library definition. # The jxl library definition.
include(jxl.cmake) include(jxl.cmake)
# Other libraries outside the core jxl library. # Other libraries outside the core jxl library.
if(JPEGXL_ENABLE_TOOLS) if(JPEGXL_ENABLE_TOOLS OR BUILD_TESTING)
include(jxl_extras.cmake) include(jxl_extras.cmake)
endif() endif()
include(jxl_threads.cmake) include(jxl_threads.cmake)
if (JPEGXL_ENABLE_JPEGLI)
include(jpegli.cmake)
endif()
# Install all the library headers from the source and the generated ones. There # For simplicity all the library headers, both source and generated ones, are
# is no distinction on which libraries use which header since it is expected # gathered in the binary folder. There is no distinction on which libraries use
# that all developer libraries are available together at build time. # which header since it is expected that all developer libraries are available
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/jxl # together at build time.
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/jxl install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/jxl
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
# Profiler for libjxl
include(jxl_profiler.cmake)
if(BUILD_TESTING) if(BUILD_TESTING)
# Unittests
cmake_policy(SET CMP0057 NEW) # https://gitlab.kitware.com/cmake/cmake/issues/18198
include(GoogleTest) include(GoogleTest)
endif()
# Tests for the jxl library. # Tests for the jxl library.
include(jxl_tests.cmake) include(jxl_tests.cmake)
if(BUILD_TESTING)
# Google benchmark for the jxl library # Google benchmark for the jxl library
include(jxl_benchmark.cmake) include(jxl_benchmark.cmake)
endif()
endif() # BUILD_TESTING

View file

@ -0,0 +1,67 @@
// Copyright (c) the JPEG XL Project Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "lib/extras/alpha_blend.h"
#include "lib/extras/packed_image.h"
#include "lib/jxl/base/status.h"
namespace jxl {
namespace extras {
namespace {
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 true;
}
--format.num_channels;
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) {
if (format.num_channels == 2) {
float g = im.GetPixelValue(y, x, 0);
float a = im.GetPixelValue(y, x, 1);
float out = g * a + background[0] * (1 - a);
blended.SetPixelValue(y, x, 0, out);
} else {
float r = im.GetPixelValue(y, x, 0);
float g = im.GetPixelValue(y, x, 1);
float b = im.GetPixelValue(y, x, 2);
float a = im.GetPixelValue(y, x, 3);
float out_r = r * a + background[0] * (1 - a);
float out_g = g * a + background[1] * (1 - a);
float out_b = b * a + background[2] * (1 - a);
blended.SetPixelValue(y, x, 0, out_r);
blended.SetPixelValue(y, x, 1, out_g);
blended.SetPixelValue(y, x, 2, out_b);
}
}
}
frame->color = blended.Copy();
return true;
}
} // namespace
Status AlphaBlend(PackedPixelFile* ppf, const float background[3]) {
if (!ppf || ppf->info.alpha_bits == 0) {
return true;
}
ppf->info.alpha_bits = 0;
JXL_RETURN_IF_ERROR(AlphaBlend(ppf->preview_frame.get(), background));
for (auto& frame : ppf->frames) {
JXL_RETURN_IF_ERROR(AlphaBlend(&frame, background));
}
return true;
}
} // namespace extras
} // namespace jxl

View file

@ -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_EXTRAS_ALPHA_BLEND_H_
#define LIB_EXTRAS_ALPHA_BLEND_H_
#include "lib/extras/packed_image.h"
#include "lib/jxl/base/status.h"
namespace jxl {
namespace extras {
Status AlphaBlend(PackedPixelFile* ppf, const float background[3]);
} // namespace extras
} // namespace jxl
#endif // LIB_EXTRAS_ALPHA_BLEND_H_

View file

@ -5,28 +5,18 @@
#include "lib/extras/codec.h" #include "lib/extras/codec.h"
#include "jxl/decode.h" #include <jxl/decode.h>
#include "jxl/types.h" #include <jxl/types.h>
#include "lib/extras/packed_image.h"
#include "lib/jxl/base/padded_bytes.h"
#include "lib/jxl/base/status.h"
#if JPEGXL_ENABLE_APNG
#include "lib/extras/enc/apng.h"
#endif
#if JPEGXL_ENABLE_JPEG
#include "lib/extras/enc/jpg.h"
#endif
#if JPEGXL_ENABLE_EXR
#include "lib/extras/enc/exr.h"
#endif
#include "lib/extras/dec/decode.h" #include "lib/extras/dec/decode.h"
#include "lib/extras/enc/apng.h"
#include "lib/extras/enc/exr.h"
#include "lib/extras/enc/jpg.h"
#include "lib/extras/enc/pgx.h" #include "lib/extras/enc/pgx.h"
#include "lib/extras/enc/pnm.h" #include "lib/extras/enc/pnm.h"
#include "lib/extras/packed_image.h"
#include "lib/extras/packed_image_convert.h" #include "lib/extras/packed_image_convert.h"
#include "lib/jxl/base/file_io.h" #include "lib/jxl/base/status.h"
#include "lib/jxl/image_bundle.h"
namespace jxl { namespace jxl {
namespace { namespace {
@ -38,78 +28,46 @@ constexpr size_t kMinBytes = 9;
Status SetFromBytes(const Span<const uint8_t> bytes, Status SetFromBytes(const Span<const uint8_t> bytes,
const extras::ColorHints& color_hints, CodecInOut* io, const extras::ColorHints& color_hints, CodecInOut* io,
ThreadPool* pool, extras::Codec* orig_codec) { ThreadPool* pool, const SizeConstraints* constraints,
extras::Codec* orig_codec) {
if (bytes.size() < kMinBytes) return JXL_FAILURE("Too few bytes"); if (bytes.size() < kMinBytes) return JXL_FAILURE("Too few bytes");
extras::PackedPixelFile ppf; extras::PackedPixelFile ppf;
if (extras::DecodeBytes(bytes, color_hints, io->constraints, &ppf, if (extras::DecodeBytes(bytes, color_hints, &ppf, constraints, orig_codec)) {
orig_codec)) {
return ConvertPackedPixelFileToCodecInOut(ppf, pool, io); return ConvertPackedPixelFileToCodecInOut(ppf, pool, io);
} }
return JXL_FAILURE("Codecs failed to decode"); return JXL_FAILURE("Codecs failed to decode");
} }
Status SetFromFile(const std::string& pathname, Status Encode(const extras::PackedPixelFile& ppf, const extras::Codec codec,
const extras::ColorHints& color_hints, CodecInOut* io,
ThreadPool* pool, extras::Codec* orig_codec) {
std::vector<uint8_t> encoded;
JXL_RETURN_IF_ERROR(ReadFile(pathname, &encoded));
JXL_RETURN_IF_ERROR(SetFromBytes(Span<const uint8_t>(encoded), color_hints,
io, pool, orig_codec));
return true;
}
Status Encode(const CodecInOut& io, const extras::Codec codec,
const ColorEncoding& c_desired, size_t bits_per_sample,
std::vector<uint8_t>* bytes, ThreadPool* pool) { std::vector<uint8_t>* bytes, ThreadPool* pool) {
JXL_CHECK(!io.Main().c_current().ICC().empty()); bytes->clear();
JXL_CHECK(!c_desired.ICC().empty());
io.CheckMetadata();
if (io.Main().IsJPEG()) {
JXL_WARNING("Writing JPEG data as pixels");
}
JxlPixelFormat format = {
0, // num_channels is ignored by the converter
bits_per_sample <= 8 ? JXL_TYPE_UINT8 : JXL_TYPE_UINT16, JXL_BIG_ENDIAN,
0};
const bool floating_point = bits_per_sample > 16;
std::unique_ptr<extras::Encoder> encoder; std::unique_ptr<extras::Encoder> encoder;
std::ostringstream os;
switch (codec) { switch (codec) {
case extras::Codec::kPNG: case extras::Codec::kPNG:
#if JPEGXL_ENABLE_APNG
encoder = extras::GetAPNGEncoder(); encoder = extras::GetAPNGEncoder();
if (encoder) {
break; break;
#else } else {
return JXL_FAILURE("JPEG XL was built without (A)PNG support"); return JXL_FAILURE("JPEG XL was built without (A)PNG support");
#endif }
case extras::Codec::kJPG: case extras::Codec::kJPG:
#if JPEGXL_ENABLE_JPEG
format.data_type = JXL_TYPE_UINT8;
encoder = extras::GetJPEGEncoder(); encoder = extras::GetJPEGEncoder();
os << io.jpeg_quality; if (encoder) {
encoder->SetOption("q", os.str());
break; break;
#else } else {
return JXL_FAILURE("JPEG XL was built without JPEG support"); return JXL_FAILURE("JPEG XL was built without JPEG support");
#endif }
case extras::Codec::kPNM: case extras::Codec::kPNM:
if (io.Main().HasAlpha()) { if (ppf.info.alpha_bits > 0) {
encoder = extras::GetPAMEncoder(); encoder = extras::GetPAMEncoder();
} else if (io.Main().IsGray()) { } else if (ppf.info.num_color_channels == 1) {
encoder = extras::GetPGMEncoder(); encoder = extras::GetPGMEncoder();
} else if (!floating_point) { } else if (ppf.info.bits_per_sample <= 16) {
encoder = extras::GetPPMEncoder(); encoder = extras::GetPPMEncoder();
} else { } else {
format.data_type = JXL_TYPE_FLOAT;
format.endianness = JXL_NATIVE_ENDIAN;
encoder = extras::GetPFMEncoder(); encoder = extras::GetPFMEncoder();
} }
if (!c_desired.IsSRGB()) {
JXL_WARNING(
"PNM encoder cannot store custom ICC profile; decoder "
"will need hint key=color_space to get the same values");
}
break; break;
case extras::Codec::kPGX: case extras::Codec::kPGX:
encoder = extras::GetPGXEncoder(); encoder = extras::GetPGXEncoder();
@ -117,13 +75,16 @@ Status Encode(const CodecInOut& io, const extras::Codec codec,
case extras::Codec::kGIF: case extras::Codec::kGIF:
return JXL_FAILURE("Encoding to GIF is not implemented"); return JXL_FAILURE("Encoding to GIF is not implemented");
case extras::Codec::kEXR: case extras::Codec::kEXR:
#if JPEGXL_ENABLE_EXR
format.data_type = JXL_TYPE_FLOAT;
encoder = extras::GetEXREncoder(); encoder = extras::GetEXREncoder();
if (encoder) {
break; break;
#else } else {
return JXL_FAILURE("JPEG XL was built without OpenEXR support"); return JXL_FAILURE("JPEG XL was built without OpenEXR support");
#endif }
case extras::Codec::kJXL:
// TODO(user): implement
return JXL_FAILURE("Codec::kJXL is not supported yet");
case extras::Codec::kUnknown: case extras::Codec::kUnknown:
return JXL_FAILURE("Cannot encode using Codec::kUnknown"); return JXL_FAILURE("Cannot encode using Codec::kUnknown");
} }
@ -131,59 +92,20 @@ Status Encode(const CodecInOut& io, const extras::Codec codec,
if (!encoder) { if (!encoder) {
return JXL_FAILURE("Invalid codec."); return JXL_FAILURE("Invalid codec.");
} }
extras::PackedPixelFile ppf;
JXL_RETURN_IF_ERROR(
ConvertCodecInOutToPackedPixelFile(io, format, c_desired, pool, &ppf));
extras::EncodedImage encoded_image; extras::EncodedImage encoded_image;
JXL_RETURN_IF_ERROR(encoder->Encode(ppf, &encoded_image, pool)); 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]; *bytes = encoded_image.bitstreams[0];
return true; return true;
} }
Status EncodeToFile(const CodecInOut& io, const ColorEncoding& c_desired, Status Encode(const extras::PackedPixelFile& ppf, const std::string& pathname,
size_t bits_per_sample, const std::string& pathname, std::vector<uint8_t>* bytes, ThreadPool* pool) {
ThreadPool* pool) { std::string extension;
const std::string extension = Extension(pathname);
const extras::Codec codec = const extras::Codec codec =
extras::CodecFromExtension(extension, &bits_per_sample); extras::CodecFromPath(pathname, nullptr, &extension);
return Encode(ppf, codec, bytes, pool);
// Warn about incorrect usage of PGM/PGX/PPM - only the latter supports
// color, but CodecFromExtension lumps them all together.
if (codec == extras::Codec::kPNM && extension != ".pfm") {
if (io.Main().HasAlpha() && extension != ".pam") {
JXL_WARNING(
"For images with alpha, the filename should end with .pam.\n");
} else if (!io.Main().IsGray() && extension == ".pgm") {
JXL_WARNING("For color images, the filename should end with .ppm.\n");
} else if (io.Main().IsGray() && extension == ".ppm") {
JXL_WARNING(
"For grayscale images, the filename should not end with .ppm.\n");
}
if (bits_per_sample > 16) {
JXL_WARNING("PPM only supports up to 16 bits per sample");
bits_per_sample = 16;
}
} else if (codec == extras::Codec::kPGX && !io.Main().IsGray()) {
JXL_WARNING("Storing color image to PGX - use .ppm extension instead.\n");
}
if (bits_per_sample > 16 && codec == extras::Codec::kPNG) {
JXL_WARNING("PNG only supports up to 16 bits per sample");
bits_per_sample = 16;
}
std::vector<uint8_t> encoded;
return Encode(io, codec, c_desired, bits_per_sample, &encoded, pool) &&
WriteFile(encoded, pathname);
}
Status EncodeToFile(const CodecInOut& io, const std::string& pathname,
ThreadPool* pool) {
// TODO(lode): need to take the floating_point_sample field into account
return EncodeToFile(io, io.metadata.m.color_encoding,
io.metadata.m.bit_depth.bits_per_sample, pathname, pool);
} }
} // namespace jxl } // namespace jxl

View file

@ -17,7 +17,6 @@
#include "lib/extras/dec/decode.h" #include "lib/extras/dec/decode.h"
#include "lib/jxl/base/compiler_specific.h" #include "lib/jxl/base/compiler_specific.h"
#include "lib/jxl/base/data_parallel.h" #include "lib/jxl/base/data_parallel.h"
#include "lib/jxl/base/padded_bytes.h"
#include "lib/jxl/base/span.h" #include "lib/jxl/base/span.h"
#include "lib/jxl/base/status.h" #include "lib/jxl/base/status.h"
#include "lib/jxl/codec_in_out.h" #include "lib/jxl/codec_in_out.h"
@ -26,39 +25,30 @@
namespace jxl { namespace jxl {
struct SizeConstraints;
// Decodes "bytes" and sets io->metadata.m. // Decodes "bytes" and sets io->metadata.m.
// color_space_hint may specify the color space, otherwise, defaults to sRGB. // color_space_hint may specify the color space, otherwise, defaults to sRGB.
Status SetFromBytes(Span<const uint8_t> bytes, Status SetFromBytes(Span<const uint8_t> bytes,
const extras::ColorHints& color_hints, CodecInOut* io, const extras::ColorHints& color_hints, CodecInOut* io,
ThreadPool* pool = nullptr, ThreadPool* pool = nullptr,
const SizeConstraints* constraints = nullptr,
extras::Codec* orig_codec = nullptr); extras::Codec* orig_codec = nullptr);
// Helper function to use no color_space_hint. // Helper function to use no color_space_hint.
JXL_INLINE Status SetFromBytes(const Span<const uint8_t> bytes, CodecInOut* io, JXL_INLINE Status SetFromBytes(const Span<const uint8_t> bytes, CodecInOut* io,
ThreadPool* pool = nullptr, ThreadPool* pool = nullptr,
const SizeConstraints* constraints = nullptr,
extras::Codec* orig_codec = nullptr) { extras::Codec* orig_codec = nullptr) {
return SetFromBytes(bytes, extras::ColorHints(), io, pool, orig_codec); return SetFromBytes(bytes, extras::ColorHints(), io, pool, constraints,
orig_codec);
} }
// Reads from file and calls SetFromBytes. Status Encode(const extras::PackedPixelFile& ppf, extras::Codec codec,
Status SetFromFile(const std::string& pathname, std::vector<uint8_t>* bytes, ThreadPool* pool);
const extras::ColorHints& color_hints, CodecInOut* io,
ThreadPool* pool = nullptr,
extras::Codec* orig_codec = nullptr);
// Replaces "bytes" with an encoding of pixels transformed from c_current Status Encode(const extras::PackedPixelFile& ppf, const std::string& pathname,
// color space to c_desired.
Status Encode(const CodecInOut& io, extras::Codec codec,
const ColorEncoding& c_desired, size_t bits_per_sample,
std::vector<uint8_t>* bytes, ThreadPool* pool = nullptr); std::vector<uint8_t>* bytes, ThreadPool* pool = nullptr);
// Deduces codec, calls Encode and writes to file.
Status EncodeToFile(const CodecInOut& io, const ColorEncoding& c_desired,
size_t bits_per_sample, const std::string& pathname,
ThreadPool* pool = nullptr);
// Same, but defaults to metadata.original color_encoding and bits_per_sample.
Status EncodeToFile(const CodecInOut& io, const std::string& pathname,
ThreadPool* pool = nullptr);
} // namespace jxl } // namespace jxl
#endif // LIB_EXTRAS_CODEC_H_ #endif // LIB_EXTRAS_CODEC_H_

View file

@ -3,42 +3,52 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
#include "lib/extras/codec.h" #include <jxl/codestream_header.h>
#include <jxl/color_encoding.h>
#include <stddef.h> #include <jxl/encode.h>
#include <stdio.h> #include <jxl/types.h>
#include <algorithm> #include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <memory>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "lib/extras/dec/pgx.h" #include "lib/extras/common.h"
#include "lib/extras/dec/pnm.h" #include "lib/extras/dec/color_hints.h"
#include "lib/extras/dec/decode.h"
#include "lib/extras/enc/encode.h" #include "lib/extras/enc/encode.h"
#include "lib/extras/packed_image_convert.h" #include "lib/extras/packed_image.h"
#include "lib/jxl/base/printf_macros.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/random.h"
#include "lib/jxl/base/thread_pool_internal.h" #include "lib/jxl/base/span.h"
#include "lib/jxl/color_management.h" #include "lib/jxl/base/status.h"
#include "lib/jxl/enc_color_management.h" #include "lib/jxl/color_encoding_internal.h"
#include "lib/jxl/image.h"
#include "lib/jxl/image_bundle.h"
#include "lib/jxl/image_test_utils.h"
#include "lib/jxl/test_utils.h" #include "lib/jxl/test_utils.h"
#include "lib/jxl/testdata.h" #include "lib/jxl/testing.h"
namespace jxl { namespace jxl {
using ::jxl::test::ThreadPoolForTests;
namespace extras { namespace extras {
Status PnmParseSigned(Bytes str, double* v);
Status PnmParseUnsigned(Bytes str, size_t* v);
namespace { namespace {
using ::testing::AllOf; Span<const uint8_t> MakeSpan(const char* str) {
using ::testing::Contains; return Bytes(reinterpret_cast<const uint8_t*>(str), strlen(str));
using ::testing::Field; }
using ::testing::IsEmpty;
using ::testing::NotNull;
using ::testing::SizeIs;
std::string ExtensionFromCodec(Codec codec, const bool is_gray, std::string ExtensionFromCodec(Codec codec, const bool is_gray,
const bool has_alpha, const bool has_alpha,
@ -51,18 +61,14 @@ std::string ExtensionFromCodec(Codec codec, const bool is_gray,
case Codec::kPNG: case Codec::kPNG:
return ".png"; return ".png";
case Codec::kPNM: case Codec::kPNM:
if (bits_per_sample == 32) return ".pfm";
if (has_alpha) return ".pam"; if (has_alpha) return ".pam";
if (is_gray) return ".pgm"; return is_gray ? ".pgm" : ".ppm";
return (bits_per_sample == 32) ? ".pfm" : ".ppm";
case Codec::kGIF:
return ".gif";
case Codec::kEXR: case Codec::kEXR:
return ".exr"; return ".exr";
case Codec::kUnknown: default:
return std::string(); return std::string();
} }
JXL_UNREACHABLE;
return std::string();
} }
void VerifySameImage(const PackedImage& im0, size_t bits_per_sample0, void VerifySameImage(const PackedImage& im0, size_t bits_per_sample0,
@ -76,8 +82,8 @@ void VerifySameImage(const PackedImage& im0, size_t bits_per_sample0,
}; };
double factor0 = get_factor(im0.format, bits_per_sample0); double factor0 = get_factor(im0.format, bits_per_sample0);
double factor1 = get_factor(im1.format, bits_per_sample1); double factor1 = get_factor(im1.format, bits_per_sample1);
auto pixels0 = static_cast<const uint8_t*>(im0.pixels()); const auto* pixels0 = static_cast<const uint8_t*>(im0.pixels());
auto pixels1 = static_cast<const uint8_t*>(im1.pixels()); const auto* pixels1 = static_cast<const uint8_t*>(im1.pixels());
auto rgba0 = auto rgba0 =
test::ConvertToRGBA32(pixels0, im0.xsize, im0.ysize, im0.format, factor0); test::ConvertToRGBA32(pixels0, im0.xsize, im0.ysize, im0.format, factor0);
auto rgba1 = auto rgba1 =
@ -110,17 +116,16 @@ JxlColorEncoding CreateTestColorEncoding(bool is_gray) {
// Roundtrip through internal color encoding to fill in primaries and white // Roundtrip through internal color encoding to fill in primaries and white
// point CIE xy coordinates. // point CIE xy coordinates.
ColorEncoding c_internal; ColorEncoding c_internal;
JXL_CHECK(ConvertExternalToInternalColorEncoding(c, &c_internal)); EXPECT_TRUE(c_internal.FromExternal(c));
ConvertInternalToExternalColorEncoding(c_internal, &c); c = c_internal.ToExternal();
return c; return c;
} }
std::vector<uint8_t> GenerateICC(JxlColorEncoding color_encoding) { std::vector<uint8_t> GenerateICC(JxlColorEncoding color_encoding) {
ColorEncoding c; ColorEncoding c;
JXL_CHECK(ConvertExternalToInternalColorEncoding(color_encoding, &c)); EXPECT_TRUE(c.FromExternal(color_encoding));
JXL_CHECK(c.CreateICC()); EXPECT_TRUE(!c.ICC().empty());
PaddedBytes icc = c.ICC(); return c.ICC();
return std::vector<uint8_t>(icc.begin(), icc.end());
} }
void StoreRandomValue(uint8_t* out, Rng* rng, JxlPixelFormat format, void StoreRandomValue(uint8_t* out, Rng* rng, JxlPixelFormat format,
@ -173,10 +178,11 @@ struct TestImageParams {
bool is_gray; bool is_gray;
bool add_alpha; bool add_alpha;
bool big_endian; bool big_endian;
bool add_extra_channels;
bool ShouldTestRoundtrip() const { bool ShouldTestRoundtrip() const {
if (codec == Codec::kPNG) { if (codec == Codec::kPNG) {
return true; return bits_per_sample <= 16;
} else if (codec == Codec::kPNM) { } else if (codec == Codec::kPNM) {
// TODO(szabadka) Make PNM encoder endianness-aware. // TODO(szabadka) Make PNM encoder endianness-aware.
return ((bits_per_sample <= 16 && big_endian) || return ((bits_per_sample <= 16 && big_endian) ||
@ -213,7 +219,7 @@ struct TestImageParams {
std::string DebugString() const { std::string DebugString() const {
std::ostringstream os; std::ostringstream os;
os << "bps:" << bits_per_sample << " gr:" << is_gray << " al:" << add_alpha os << "bps:" << bits_per_sample << " gr:" << is_gray << " al:" << add_alpha
<< " be: " << big_endian; << " be: " << big_endian << " ec: " << add_extra_channels;
return os.str(); return os.str();
} }
}; };
@ -225,14 +231,31 @@ void CreateTestImage(const TestImageParams& params, PackedPixelFile* ppf) {
ppf->info.exponent_bits_per_sample = params.bits_per_sample == 32 ? 8 : 0; ppf->info.exponent_bits_per_sample = params.bits_per_sample == 32 ? 8 : 0;
ppf->info.num_color_channels = params.is_gray ? 1 : 3; ppf->info.num_color_channels = params.is_gray ? 1 : 3;
ppf->info.alpha_bits = params.add_alpha ? params.bits_per_sample : 0; ppf->info.alpha_bits = params.add_alpha ? params.bits_per_sample : 0;
ppf->info.alpha_premultiplied = (params.codec == Codec::kEXR); ppf->info.alpha_premultiplied = TO_JXL_BOOL(params.codec == Codec::kEXR);
JxlColorEncoding color_encoding = CreateTestColorEncoding(params.is_gray); JxlColorEncoding color_encoding = CreateTestColorEncoding(params.is_gray);
ppf->icc = GenerateICC(color_encoding); ppf->icc = GenerateICC(color_encoding);
ppf->color_encoding = 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); 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;
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;
pec.ec_info.bits_per_sample = params.bits_per_sample;
pec.ec_info.type = static_cast<JxlExtraChannelType>(i);
ppf->extra_channels_info.emplace_back(std::move(pec));
}
}
ppf->frames.emplace_back(std::move(frame)); ppf->frames.emplace_back(std::move(frame));
} }
@ -249,33 +272,67 @@ void TestRoundTrip(const TestImageParams& params, ThreadPool* pool) {
EncodedImage encoded; EncodedImage encoded;
auto encoder = Encoder::FromExtension(extension); auto encoder = Encoder::FromExtension(extension);
ASSERT_TRUE(encoder.get()); if (!encoder) {
fprintf(stderr, "Skipping test because of missing codec support.\n");
return;
}
ASSERT_TRUE(encoder->Encode(ppf_in, &encoded, pool)); ASSERT_TRUE(encoder->Encode(ppf_in, &encoded, pool));
ASSERT_EQ(encoded.bitstreams.size(), 1); ASSERT_EQ(encoded.bitstreams.size(), 1);
PackedPixelFile ppf_out; PackedPixelFile ppf_out;
ASSERT_TRUE(DecodeBytes(Span<const uint8_t>(encoded.bitstreams[0]), ColorHints color_hints;
ColorHints(), SizeConstraints(), &ppf_out)); if (params.codec == Codec::kPNM || params.codec == Codec::kPGX) {
color_hints.Add("color_space",
if (params.codec != Codec::kPNM && params.codec != Codec::kPGX && params.is_gray ? "Gra_D65_Rel_SRG" : "RGB_D65_SRG_Rel_SRG");
}
ASSERT_TRUE(DecodeBytes(Bytes(encoded.bitstreams[0]), color_hints, &ppf_out));
if (params.codec == Codec::kPNG && ppf_out.icc.empty()) {
// Decoding a PNG may drop the ICC profile if there's a valid cICP chunk.
// Rendering intent is not preserved in this case.
EXPECT_EQ(ppf_in.color_encoding.color_space,
ppf_out.color_encoding.color_space);
EXPECT_EQ(ppf_in.color_encoding.white_point,
ppf_out.color_encoding.white_point);
if (ppf_in.color_encoding.color_space != JXL_COLOR_SPACE_GRAY) {
EXPECT_EQ(ppf_in.color_encoding.primaries,
ppf_out.color_encoding.primaries);
}
EXPECT_EQ(ppf_in.color_encoding.transfer_function,
ppf_out.color_encoding.transfer_function);
EXPECT_EQ(ppf_out.color_encoding.rendering_intent,
JXL_RENDERING_INTENT_RELATIVE);
} else if (params.codec != Codec::kPNM && params.codec != Codec::kPGX &&
params.codec != Codec::kEXR) { params.codec != Codec::kEXR) {
EXPECT_EQ(ppf_in.icc, ppf_out.icc); EXPECT_EQ(ppf_in.icc, ppf_out.icc);
} }
ASSERT_EQ(ppf_out.frames.size(), 1); ASSERT_EQ(ppf_out.frames.size(), 1);
VerifySameImage(ppf_in.frames[0].color, ppf_in.info.bits_per_sample, const auto& frame_in = ppf_in.frames[0];
ppf_out.frames[0].color, ppf_out.info.bits_per_sample, const auto& frame_out = ppf_out.frames[0];
VerifySameImage(frame_in.color, ppf_in.info.bits_per_sample, frame_out.color,
ppf_out.info.bits_per_sample,
/*lossless=*/params.codec != Codec::kJPG); /*lossless=*/params.codec != Codec::kJPG);
ASSERT_EQ(frame_in.extra_channels.size(), frame_out.extra_channels.size());
ASSERT_EQ(ppf_out.extra_channels_info.size(),
frame_out.extra_channels.size());
for (size_t i = 0; i < frame_in.extra_channels.size(); ++i) {
VerifySameImage(frame_in.extra_channels[i], ppf_in.info.bits_per_sample,
frame_out.extra_channels[i], ppf_out.info.bits_per_sample,
/*lossless=*/true);
EXPECT_EQ(ppf_out.extra_channels_info[i].ec_info.type,
ppf_in.extra_channels_info[i].ec_info.type);
}
} }
TEST(CodecTest, TestRoundTrip) { TEST(CodecTest, TestRoundTrip) {
ThreadPoolInternal pool(12); ThreadPoolForTests pool(12);
TestImageParams params; TestImageParams params;
params.xsize = 7; params.xsize = 7;
params.ysize = 4; params.ysize = 4;
for (Codec codec : AvailableCodecs()) { for (Codec codec :
{Codec::kPNG, Codec::kPNM, Codec::kPGX, Codec::kEXR, Codec::kJPG}) {
for (int bits_per_sample : {4, 8, 10, 12, 16, 32}) { for (int bits_per_sample : {4, 8, 10, 12, 16, 32}) {
for (bool is_gray : {false, true}) { for (bool is_gray : {false, true}) {
for (bool add_alpha : {false, true}) { for (bool add_alpha : {false, true}) {
@ -285,7 +342,12 @@ TEST(CodecTest, TestRoundTrip) {
params.is_gray = is_gray; params.is_gray = is_gray;
params.add_alpha = add_alpha; params.add_alpha = add_alpha;
params.big_endian = big_endian; params.big_endian = big_endian;
TestRoundTrip(params, &pool); params.add_extra_channels = false;
TestRoundTrip(params, pool.get());
if (codec == Codec::kPNM && add_alpha) {
params.add_extra_channels = true;
TestRoundTrip(params, pool.get());
}
} }
} }
} }
@ -293,194 +355,74 @@ TEST(CodecTest, TestRoundTrip) {
} }
} }
CodecInOut DecodeRoundtrip(const std::string& pathname, ThreadPool* pool, TEST(CodecTest, LosslessPNMRoundtrip) {
const ColorHints& color_hints = ColorHints()) { ThreadPoolForTests pool(12);
CodecInOut io;
const PaddedBytes orig = ReadTestData(pathname);
JXL_CHECK(
SetFromBytes(Span<const uint8_t>(orig), color_hints, &io, pool, nullptr));
const ImageBundle& ib1 = io.Main();
// Encode/Decode again to make sure Encode carries through all metadata. static const char* kChannels[] = {"", "g", "ga", "rgb", "rgba"};
std::vector<uint8_t> encoded; static const char* kExtension[] = {"", ".pgm", ".pam", ".ppm", ".pam"};
JXL_CHECK(Encode(io, Codec::kPNG, io.metadata.m.color_encoding, for (size_t bit_depth = 1; bit_depth <= 16; ++bit_depth) {
io.metadata.m.bit_depth.bits_per_sample, &encoded, pool)); for (size_t channels = 1; channels <= 4; ++channels) {
if (bit_depth == 1 && (channels == 2 || channels == 4)) continue;
std::string extension(kExtension[channels]);
std::string filename = "jxl/flower/flower_small." +
std::string(kChannels[channels]) + ".depth" +
std::to_string(bit_depth) + extension;
const std::vector<uint8_t> orig = jxl::test::ReadTestData(filename);
CodecInOut io2; PackedPixelFile ppf;
JXL_CHECK(SetFromBytes(Span<const uint8_t>(encoded), color_hints, &io2, pool, ColorHints color_hints;
nullptr)); color_hints.Add("color_space",
const ImageBundle& ib2 = io2.Main(); channels < 3 ? "Gra_D65_Rel_SRG" : "RGB_D65_SRG_Rel_SRG");
EXPECT_EQ(Description(ib1.metadata()->color_encoding), ASSERT_TRUE(
Description(ib2.metadata()->color_encoding)); DecodeBytes(Bytes(orig.data(), orig.size()), color_hints, &ppf));
EXPECT_EQ(Description(ib1.c_current()), Description(ib2.c_current()));
size_t bits_per_sample = io2.metadata.m.bit_depth.bits_per_sample; EncodedImage encoded;
auto encoder = Encoder::FromExtension(extension);
// "Same" pixels? ASSERT_TRUE(encoder.get());
double max_l1 = bits_per_sample <= 12 ? 1.3 : 2E-3; ASSERT_TRUE(encoder->Encode(ppf, &encoded, pool.get()));
double max_rel = bits_per_sample <= 12 ? 6E-3 : 1E-4; ASSERT_EQ(encoded.bitstreams.size(), 1);
if (ib1.metadata()->color_encoding.IsGray()) { ASSERT_EQ(orig.size(), encoded.bitstreams[0].size());
max_rel *= 2.0; EXPECT_EQ(0,
} else if (ib1.metadata()->color_encoding.primaries != Primaries::kSRGB) { memcmp(orig.data(), encoded.bitstreams[0].data(), orig.size()));
// Need more tolerance for large gamuts (anything but sRGB)
max_l1 *= 1.5;
max_rel *= 3.0;
} }
VerifyRelativeError(ib1.color(), ib2.color(), max_l1, max_rel);
// Simulate the encoder removing profile and decoder restoring it.
if (!ib2.metadata()->color_encoding.WantICC()) {
io2.metadata.m.color_encoding.InternalRemoveICC();
EXPECT_TRUE(io2.metadata.m.color_encoding.CreateICC());
}
return io2;
}
#if 0
TEST(CodecTest, TestMetadataSRGB) {
ThreadPoolInternal pool(12);
const char* paths[] = {"external/raw.pixls/DJI-FC6310-16bit_srgb8_v4_krita.png",
"external/raw.pixls/Google-Pixel2XL-16bit_srgb8_v4_krita.png",
"external/raw.pixls/HUAWEI-EVA-L09-16bit_srgb8_dt.png",
"external/raw.pixls/Nikon-D300-12bit_srgb8_dt.png",
"external/raw.pixls/Sony-DSC-RX1RM2-14bit_srgb8_v4_krita.png"};
for (const char* relative_pathname : paths) {
const CodecInOut io =
DecodeRoundtrip(relative_pathname, Codec::kPNG, &pool);
EXPECT_EQ(8, io.metadata.m.bit_depth.bits_per_sample);
EXPECT_FALSE(io.metadata.m.bit_depth.floating_point_sample);
EXPECT_EQ(0, io.metadata.m.bit_depth.exponent_bits_per_sample);
EXPECT_EQ(64, io.xsize());
EXPECT_EQ(64, io.ysize());
EXPECT_FALSE(io.metadata.m.HasAlpha());
const ColorEncoding& c_original = io.metadata.m.color_encoding;
EXPECT_FALSE(c_original.ICC().empty());
EXPECT_EQ(ColorSpace::kRGB, c_original.GetColorSpace());
EXPECT_EQ(WhitePoint::kD65, c_original.white_point);
EXPECT_EQ(Primaries::kSRGB, c_original.primaries);
EXPECT_TRUE(c_original.tf.IsSRGB());
} }
} }
TEST(CodecTest, TestMetadataLinear) { TEST(CodecTest, TestPNM) {
ThreadPoolInternal pool(12); 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));
const char* paths[3] = { ASSERT_FALSE(PnmParseSigned(MakeSpan(""), &d));
"external/raw.pixls/Google-Pixel2XL-16bit_acescg_g1_v4_krita.png", ASSERT_FALSE(PnmParseSigned(MakeSpan("+"), &d));
"external/raw.pixls/HUAWEI-EVA-L09-16bit_709_g1_dt.png", ASSERT_FALSE(PnmParseSigned(MakeSpan("-"), &d));
"external/raw.pixls/Nikon-D300-12bit_2020_g1_dt.png", ASSERT_FALSE(PnmParseSigned(MakeSpan("A"), &d));
};
const WhitePoint white_points[3] = {WhitePoint::kCustom, WhitePoint::kD65,
WhitePoint::kD65};
const Primaries primaries[3] = {Primaries::kCustom, Primaries::kSRGB,
Primaries::k2100};
for (size_t i = 0; i < 3; ++i) {
const CodecInOut io = DecodeRoundtrip(paths[i], Codec::kPNG, &pool);
EXPECT_EQ(16, io.metadata.m.bit_depth.bits_per_sample);
EXPECT_FALSE(io.metadata.m.bit_depth.floating_point_sample);
EXPECT_EQ(0, io.metadata.m.bit_depth.exponent_bits_per_sample);
EXPECT_EQ(64, io.xsize());
EXPECT_EQ(64, io.ysize());
EXPECT_FALSE(io.metadata.m.HasAlpha());
const ColorEncoding& c_original = io.metadata.m.color_encoding;
EXPECT_FALSE(c_original.ICC().empty());
EXPECT_EQ(ColorSpace::kRGB, c_original.GetColorSpace());
EXPECT_EQ(white_points[i], c_original.white_point);
EXPECT_EQ(primaries[i], c_original.primaries);
EXPECT_TRUE(c_original.tf.IsLinear());
}
}
TEST(CodecTest, TestMetadataICC) {
ThreadPoolInternal pool(12);
const char* paths[] = {
"external/raw.pixls/DJI-FC6310-16bit_709_v4_krita.png",
"external/raw.pixls/Sony-DSC-RX1RM2-14bit_709_v4_krita.png",
};
for (const char* relative_pathname : paths) {
const CodecInOut io =
DecodeRoundtrip(relative_pathname, Codec::kPNG, &pool);
EXPECT_GE(16, io.metadata.m.bit_depth.bits_per_sample);
EXPECT_LE(14, io.metadata.m.bit_depth.bits_per_sample);
EXPECT_EQ(64, io.xsize());
EXPECT_EQ(64, io.ysize());
EXPECT_FALSE(io.metadata.m.HasAlpha());
const ColorEncoding& c_original = io.metadata.m.color_encoding;
EXPECT_FALSE(c_original.ICC().empty());
EXPECT_EQ(RenderingIntent::kPerceptual, c_original.rendering_intent);
EXPECT_EQ(ColorSpace::kRGB, c_original.GetColorSpace());
EXPECT_EQ(WhitePoint::kD65, c_original.white_point);
EXPECT_EQ(Primaries::kSRGB, c_original.primaries);
EXPECT_EQ(TransferFunction::k709, c_original.tf.GetTransferFunction());
}
}
TEST(CodecTest, Testexternal/pngsuite) {
ThreadPoolInternal pool(12);
// Ensure we can load PNG with text, japanese UTF-8, compressed text.
(void)DecodeRoundtrip("external/pngsuite/ct1n0g04.png", Codec::kPNG, &pool);
(void)DecodeRoundtrip("external/pngsuite/ctjn0g04.png", Codec::kPNG, &pool);
(void)DecodeRoundtrip("external/pngsuite/ctzn0g04.png", Codec::kPNG, &pool);
// Extract gAMA
const CodecInOut b1 =
DecodeRoundtrip("external/pngsuite/g10n3p04.png", Codec::kPNG, &pool);
EXPECT_TRUE(b1.metadata.color_encoding.tf.IsLinear());
// Extract cHRM
const CodecInOut b_p =
DecodeRoundtrip("external/pngsuite/ccwn2c08.png", Codec::kPNG, &pool);
EXPECT_EQ(Primaries::kSRGB, b_p.metadata.color_encoding.primaries);
EXPECT_EQ(WhitePoint::kD65, b_p.metadata.color_encoding.white_point);
// Extract EXIF from (new-style) dedicated chunk
const CodecInOut b_exif =
DecodeRoundtrip("external/pngsuite/exif2c08.png", Codec::kPNG, &pool);
EXPECT_EQ(978, b_exif.blobs.exif.size());
}
#endif #endif
ASSERT_TRUE(PnmParseUnsigned(MakeSpan("1"), &u));
ASSERT_TRUE(u == 1);
void VerifyWideGamutMetadata(const std::string& relative_pathname, ASSERT_TRUE(PnmParseUnsigned(MakeSpan("32"), &u));
const Primaries primaries, ThreadPool* pool) { ASSERT_TRUE(u == 32);
const CodecInOut io = DecodeRoundtrip(relative_pathname, pool);
EXPECT_EQ(8u, io.metadata.m.bit_depth.bits_per_sample); ASSERT_TRUE(PnmParseSigned(MakeSpan("1"), &d));
EXPECT_FALSE(io.metadata.m.bit_depth.floating_point_sample); ASSERT_TRUE(d == 1.0);
EXPECT_EQ(0u, io.metadata.m.bit_depth.exponent_bits_per_sample); ASSERT_TRUE(PnmParseSigned(MakeSpan("+2"), &d));
ASSERT_TRUE(d == 2.0);
const ColorEncoding& c_original = io.metadata.m.color_encoding; ASSERT_TRUE(PnmParseSigned(MakeSpan("-3"), &d));
EXPECT_FALSE(c_original.ICC().empty()); ASSERT_TRUE(std::abs(d - -3.0) < 1E-15);
EXPECT_EQ(RenderingIntent::kAbsolute, c_original.rendering_intent); ASSERT_TRUE(PnmParseSigned(MakeSpan("3.141592"), &d));
EXPECT_EQ(ColorSpace::kRGB, c_original.GetColorSpace()); ASSERT_TRUE(std::abs(d - 3.141592) < 1E-15);
EXPECT_EQ(WhitePoint::kD65, c_original.white_point); ASSERT_TRUE(PnmParseSigned(MakeSpan("-3.141592"), &d));
EXPECT_EQ(primaries, c_original.primaries); ASSERT_TRUE(std::abs(d - -3.141592) < 1E-15);
} }
TEST(CodecTest, TestWideGamut) {
ThreadPoolInternal pool(12);
// VerifyWideGamutMetadata("external/wide-gamut-tests/P3-sRGB-color-bars.png",
// Primaries::kP3, &pool);
VerifyWideGamutMetadata("external/wide-gamut-tests/P3-sRGB-color-ring.png",
Primaries::kP3, &pool);
// VerifyWideGamutMetadata("external/wide-gamut-tests/R2020-sRGB-color-bars.png",
// Primaries::k2100, &pool);
// VerifyWideGamutMetadata("external/wide-gamut-tests/R2020-sRGB-color-ring.png",
// Primaries::k2100, &pool);
}
TEST(CodecTest, TestPNM) { TestCodecPNM(); }
TEST(CodecTest, FormatNegotiation) { TEST(CodecTest, FormatNegotiation) {
const std::vector<JxlPixelFormat> accepted_formats = { const std::vector<JxlPixelFormat> accepted_formats = {
{/*num_channels=*/4, {/*num_channels=*/4,
@ -520,29 +462,32 @@ TEST(CodecTest, EncodeToPNG) {
ThreadPool* const pool = nullptr; ThreadPool* const pool = nullptr;
std::unique_ptr<Encoder> png_encoder = Encoder::FromExtension(".png"); std::unique_ptr<Encoder> png_encoder = Encoder::FromExtension(".png");
ASSERT_THAT(png_encoder, NotNull()); if (!png_encoder) {
fprintf(stderr, "Skipping test because of missing codec support.\n");
return;
}
const PaddedBytes original_png = const std::vector<uint8_t> original_png = jxl::test::ReadTestData(
ReadTestData("external/wesaturate/500px/tmshre_riaphotographs_srgb8.png"); "external/wesaturate/500px/tmshre_riaphotographs_srgb8.png");
PackedPixelFile ppf; PackedPixelFile ppf;
ASSERT_TRUE(extras::DecodeBytes(Span<const uint8_t>(original_png), ASSERT_TRUE(extras::DecodeBytes(Bytes(original_png), ColorHints(), &ppf));
ColorHints(), SizeConstraints(), &ppf));
const JxlPixelFormat& format = ppf.frames.front().color.format; const JxlPixelFormat& format = ppf.frames.front().color.format;
ASSERT_THAT( const auto& format_matcher = [&format](const JxlPixelFormat& candidate) {
png_encoder->AcceptedFormats(), return (candidate.num_channels == format.num_channels) &&
Contains(AllOf(Field(&JxlPixelFormat::num_channels, format.num_channels), (candidate.data_type == format.data_type) &&
Field(&JxlPixelFormat::data_type, format.data_type), (candidate.endianness == format.endianness);
Field(&JxlPixelFormat::endianness, format.endianness)))); };
const auto formats = png_encoder->AcceptedFormats();
ASSERT_TRUE(std::any_of(formats.begin(), formats.end(), format_matcher));
EncodedImage encoded_png; EncodedImage encoded_png;
ASSERT_TRUE(png_encoder->Encode(ppf, &encoded_png, pool)); ASSERT_TRUE(png_encoder->Encode(ppf, &encoded_png, pool));
EXPECT_THAT(encoded_png.icc, IsEmpty()); EXPECT_TRUE(encoded_png.icc.empty());
ASSERT_THAT(encoded_png.bitstreams, SizeIs(1)); ASSERT_EQ(encoded_png.bitstreams.size(), 1);
PackedPixelFile decoded_ppf; PackedPixelFile decoded_ppf;
ASSERT_TRUE( ASSERT_TRUE(extras::DecodeBytes(Bytes(encoded_png.bitstreams.front()),
extras::DecodeBytes(Span<const uint8_t>(encoded_png.bitstreams.front()), ColorHints(), &decoded_ppf));
ColorHints(), SizeConstraints(), &decoded_ppf));
ASSERT_EQ(decoded_ppf.info.bits_per_sample, ppf.info.bits_per_sample); ASSERT_EQ(decoded_ppf.info.bits_per_sample, ppf.info.bits_per_sample);
ASSERT_EQ(decoded_ppf.frames.size(), 1); ASSERT_EQ(decoded_ppf.frames.size(), 1);

View file

@ -0,0 +1,62 @@
// Copyright (c) the JPEG XL Project Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "lib/extras/common.h"
#include <jxl/codestream_header.h>
#include <jxl/types.h>
#include <cstddef>
#include <vector>
#include "lib/extras/packed_image.h"
#include "lib/jxl/base/printf_macros.h"
#include "lib/jxl/base/status.h"
namespace jxl {
namespace extras {
Status SelectFormat(const std::vector<JxlPixelFormat>& accepted_formats,
const JxlBasicInfo& basic_info, JxlPixelFormat* format) {
const size_t original_bit_depth = basic_info.bits_per_sample;
size_t current_bit_depth = 0;
size_t num_alpha_channels = (basic_info.alpha_bits != 0 ? 1 : 0);
size_t num_channels = basic_info.num_color_channels + num_alpha_channels;
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 (
// Candidate bit depth is less than what we have and still enough
(original_bit_depth <= candidate_bit_depth &&
candidate_bit_depth < current_bit_depth) ||
// Or larger than the too-small bit depth we currently have
(current_bit_depth < candidate_bit_depth &&
current_bit_depth < original_bit_depth)) {
*format = candidate;
current_bit_depth = candidate_bit_depth;
}
}
if (current_bit_depth == 0) {
if (num_channels > basic_info.num_color_channels) {
// Try dropping the alpha channel.
--num_channels;
continue;
}
return JXL_FAILURE("no appropriate format found");
}
break;
}
if (current_bit_depth < original_bit_depth) {
JXL_WARNING("encoding %" PRIuS "-bit original to %" PRIuS " bits",
original_bit_depth, current_bit_depth);
}
return true;
}
} // namespace extras
} // namespace jxl

View file

@ -0,0 +1,26 @@
// 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_EXTRAS_COMMON_H_
#define LIB_EXTRAS_COMMON_H_
#include <jxl/codestream_header.h>
#include <jxl/types.h>
#include <vector>
#include "lib/jxl/base/status.h"
namespace jxl {
namespace extras {
// TODO(sboukortt): consider exposing this as part of the C API.
Status SelectFormat(const std::vector<JxlPixelFormat>& accepted_formats,
const JxlBasicInfo& basic_info, JxlPixelFormat* format);
} // namespace extras
} // namespace jxl
#endif // LIB_EXTRAS_COMMON_H_

View file

@ -0,0 +1,53 @@
// Copyright (c) the JPEG XL Project Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include <jxl/compressed_icc.h>
#include "lib/jxl/base/span.h"
#include "lib/jxl/enc_aux_out.h"
#include "lib/jxl/enc_icc_codec.h"
#include "lib/jxl/icc_codec.h"
JXL_BOOL JxlICCProfileEncode(const JxlMemoryManager* memory_manager,
const uint8_t* icc, size_t icc_size,
uint8_t** compressed_icc,
size_t* compressed_icc_size) {
JxlMemoryManager local_memory_manager;
if (!jxl::MemoryManagerInit(&local_memory_manager, memory_manager)) {
return JXL_FALSE;
}
jxl::BitWriter writer(&local_memory_manager);
JXL_RETURN_IF_ERROR(jxl::WriteICC(jxl::Span<const uint8_t>(icc, icc_size),
&writer, jxl::LayerType::Header, nullptr));
writer.ZeroPadToByte();
jxl::Bytes bytes = writer.GetSpan();
*compressed_icc_size = bytes.size();
*compressed_icc = static_cast<uint8_t*>(
jxl::MemoryManagerAlloc(&local_memory_manager, *compressed_icc_size));
memcpy(*compressed_icc, bytes.data(), bytes.size());
return JXL_TRUE;
}
JXL_BOOL JxlICCProfileDecode(const JxlMemoryManager* memory_manager,
const uint8_t* compressed_icc,
size_t compressed_icc_size, uint8_t** icc,
size_t* icc_size) {
JxlMemoryManager local_memory_manager;
if (!jxl::MemoryManagerInit(&local_memory_manager, memory_manager)) {
return JXL_FALSE;
}
jxl::ICCReader icc_reader(&local_memory_manager);
jxl::PaddedBytes decompressed(&local_memory_manager);
jxl::BitReader bit_reader(
jxl::Span<const uint8_t>(compressed_icc, compressed_icc_size));
JXL_RETURN_IF_ERROR(icc_reader.Init(&bit_reader));
JXL_RETURN_IF_ERROR(icc_reader.Process(&bit_reader, &decompressed));
JXL_RETURN_IF_ERROR(bit_reader.Close());
*icc_size = decompressed.size();
*icc = static_cast<uint8_t*>(
jxl::MemoryManagerAlloc(&local_memory_manager, *icc_size));
memcpy(*icc, decompressed.data(), *icc_size);
return JXL_TRUE;
}

View file

@ -0,0 +1,47 @@
// Copyright (c) the JPEG XL Project Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "jxl/compressed_icc.h"
#include <jxl/memory_manager.h>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include "lib/jxl/color_encoding_internal.h"
#include "lib/jxl/test_memory_manager.h"
#include "lib/jxl/test_utils.h"
#include "lib/jxl/testing.h"
namespace jxl {
namespace {
TEST(CompressedIccTest, Roundtrip) {
JxlMemoryManager* memory_manager = jxl::test::MemoryManager();
uint8_t* compressed_icc;
size_t compressed_icc_size;
const IccBytes icc = jxl::test::GetIccTestProfile();
ASSERT_TRUE(JxlICCProfileEncode(memory_manager, icc.data(), icc.size(),
&compressed_icc, &compressed_icc_size));
EXPECT_LT(compressed_icc_size, icc.size());
uint8_t* decompressed_icc;
size_t decompressed_icc_size;
ASSERT_TRUE(JxlICCProfileDecode(memory_manager, compressed_icc,
compressed_icc_size, &decompressed_icc,
&decompressed_icc_size));
ASSERT_EQ(decompressed_icc_size, icc.size());
EXPECT_EQ(0, memcmp(decompressed_icc, icc.data(), decompressed_icc_size));
memory_manager->free(memory_manager->opaque, compressed_icc);
memory_manager->free(memory_manager->opaque, decompressed_icc);
}
} // namespace
} // namespace jxl

File diff suppressed because it is too large Load diff

View file

@ -8,23 +8,25 @@
// Decodes APNG images in memory. // Decodes APNG images in memory.
#include <stdint.h> #include <cstdint>
#include "lib/extras/dec/color_hints.h" #include "lib/extras/dec/color_hints.h"
#include "lib/extras/packed_image.h" #include "lib/extras/packed_image.h"
#include "lib/jxl/base/data_parallel.h"
#include "lib/jxl/base/padded_bytes.h"
#include "lib/jxl/base/span.h" #include "lib/jxl/base/span.h"
#include "lib/jxl/base/status.h" #include "lib/jxl/base/status.h"
#include "lib/jxl/codec_in_out.h"
namespace jxl { namespace jxl {
struct SizeConstraints;
namespace extras { namespace extras {
bool CanDecodeAPNG();
// Decodes `bytes` into `ppf`. // Decodes `bytes` into `ppf`.
Status DecodeImageAPNG(Span<const uint8_t> bytes, const ColorHints& color_hints, Status DecodeImageAPNG(Span<const uint8_t> bytes, const ColorHints& color_hints,
const SizeConstraints& constraints, PackedPixelFile* ppf,
PackedPixelFile* ppf); const SizeConstraints* constraints = nullptr);
} // namespace extras } // namespace extras
} // namespace jxl } // namespace jxl

View file

@ -9,6 +9,8 @@
#include <cmath> #include <cmath>
#include "lib/jxl/base/common.h"
namespace jxl { namespace jxl {
namespace { namespace {
@ -19,49 +21,46 @@ struct EnumName {
T value; T value;
}; };
const EnumName<JxlColorSpace> kJxlColorSpaceNames[] = { constexpr auto kJxlColorSpaceNames =
{"RGB", JXL_COLOR_SPACE_RGB}, to_array<EnumName<JxlColorSpace>>({{"RGB", JXL_COLOR_SPACE_RGB},
{"Gra", JXL_COLOR_SPACE_GRAY}, {"Gra", JXL_COLOR_SPACE_GRAY},
{"XYB", JXL_COLOR_SPACE_XYB}, {"XYB", JXL_COLOR_SPACE_XYB},
{"CS?", JXL_COLOR_SPACE_UNKNOWN}, {"CS?", JXL_COLOR_SPACE_UNKNOWN}});
};
const EnumName<JxlWhitePoint> kJxlWhitePointNames[] = { constexpr auto kJxlWhitePointNames =
{"D65", JXL_WHITE_POINT_D65}, to_array<EnumName<JxlWhitePoint>>({{"D65", JXL_WHITE_POINT_D65},
{"Cst", JXL_WHITE_POINT_CUSTOM}, {"Cst", JXL_WHITE_POINT_CUSTOM},
{"EER", JXL_WHITE_POINT_E}, {"EER", JXL_WHITE_POINT_E},
{"DCI", JXL_WHITE_POINT_DCI}, {"DCI", JXL_WHITE_POINT_DCI}});
};
const EnumName<JxlPrimaries> kJxlPrimariesNames[] = { constexpr auto kJxlPrimariesNames =
{"SRG", JXL_PRIMARIES_SRGB}, to_array<EnumName<JxlPrimaries>>({{"SRG", JXL_PRIMARIES_SRGB},
{"Cst", JXL_PRIMARIES_CUSTOM}, {"Cst", JXL_PRIMARIES_CUSTOM},
{"202", JXL_PRIMARIES_2100}, {"202", JXL_PRIMARIES_2100},
{"DCI", JXL_PRIMARIES_P3}, {"DCI", JXL_PRIMARIES_P3}});
};
const EnumName<JxlTransferFunction> kJxlTransferFunctionNames[] = { constexpr auto kJxlRenderingIntentNames =
{"709", JXL_TRANSFER_FUNCTION_709}, to_array<EnumName<JxlRenderingIntent>>(
{{"Per", JXL_RENDERING_INTENT_PERCEPTUAL},
{"Rel", JXL_RENDERING_INTENT_RELATIVE},
{"Sat", JXL_RENDERING_INTENT_SATURATION},
{"Abs", JXL_RENDERING_INTENT_ABSOLUTE}});
constexpr auto kJxlTransferFunctionNames =
to_array<EnumName<JxlTransferFunction>>(
{{"709", JXL_TRANSFER_FUNCTION_709},
{"TF?", JXL_TRANSFER_FUNCTION_UNKNOWN}, {"TF?", JXL_TRANSFER_FUNCTION_UNKNOWN},
{"Lin", JXL_TRANSFER_FUNCTION_LINEAR}, {"Lin", JXL_TRANSFER_FUNCTION_LINEAR},
{"SRG", JXL_TRANSFER_FUNCTION_SRGB}, {"SRG", JXL_TRANSFER_FUNCTION_SRGB},
{"PeQ", JXL_TRANSFER_FUNCTION_PQ}, {"PeQ", JXL_TRANSFER_FUNCTION_PQ},
{"DCI", JXL_TRANSFER_FUNCTION_DCI}, {"DCI", JXL_TRANSFER_FUNCTION_DCI},
{"HLG", JXL_TRANSFER_FUNCTION_HLG}, {"HLG", JXL_TRANSFER_FUNCTION_HLG},
{"", JXL_TRANSFER_FUNCTION_GAMMA}, {"", JXL_TRANSFER_FUNCTION_GAMMA}});
};
const EnumName<JxlRenderingIntent> kJxlRenderingIntentNames[] = { template <typename T, size_t N>
{"Per", JXL_RENDERING_INTENT_PERCEPTUAL}, Status ParseEnum(const std::string& token,
{"Rel", JXL_RENDERING_INTENT_RELATIVE}, const std::array<EnumName<T>, N>& enum_values, T* value) {
{"Sat", JXL_RENDERING_INTENT_SATURATION}, for (size_t i = 0; i < enum_values.size(); i++) {
{"Abs", JXL_RENDERING_INTENT_ABSOLUTE},
};
template <typename T>
Status ParseEnum(const std::string& token, const EnumName<T>* enum_values,
size_t enum_len, T* value) {
for (size_t i = 0; i < enum_len; i++) {
if (enum_values[i].name == token) { if (enum_values[i].name == token) {
*value = enum_values[i].value; *value = enum_values[i].value;
return true; return true;
@ -69,9 +68,6 @@ Status ParseEnum(const std::string& token, const EnumName<T>* enum_values,
} }
return false; return false;
} }
#define ARRAYSIZE(X) (sizeof(X) / sizeof((X)[0]))
#define PARSE_ENUM(type, token, value) \
ParseEnum<type>(token, k##type##Names, ARRAYSIZE(k##type##Names), value)
class Tokenizer { class Tokenizer {
public: public:
@ -122,7 +118,7 @@ Status ParseColorSpace(Tokenizer* tokenizer, JxlColorEncoding* c) {
std::string str; std::string str;
JXL_RETURN_IF_ERROR(tokenizer->Next(&str)); JXL_RETURN_IF_ERROR(tokenizer->Next(&str));
JxlColorSpace cs; JxlColorSpace cs;
if (PARSE_ENUM(JxlColorSpace, str, &cs)) { if (ParseEnum(str, kJxlColorSpaceNames, &cs)) {
c->color_space = cs; c->color_space = cs;
return true; return true;
} }
@ -139,7 +135,7 @@ Status ParseWhitePoint(Tokenizer* tokenizer, JxlColorEncoding* c) {
std::string str; std::string str;
JXL_RETURN_IF_ERROR(tokenizer->Next(&str)); JXL_RETURN_IF_ERROR(tokenizer->Next(&str));
if (PARSE_ENUM(JxlWhitePoint, str, &c->white_point)) return true; if (ParseEnum(str, kJxlWhitePointNames, &c->white_point)) return true;
Tokenizer xy_tokenizer(&str, ';'); Tokenizer xy_tokenizer(&str, ';');
c->white_point = JXL_WHITE_POINT_CUSTOM; c->white_point = JXL_WHITE_POINT_CUSTOM;
@ -157,7 +153,7 @@ Status ParsePrimaries(Tokenizer* tokenizer, JxlColorEncoding* c) {
std::string str; std::string str;
JXL_RETURN_IF_ERROR(tokenizer->Next(&str)); JXL_RETURN_IF_ERROR(tokenizer->Next(&str));
if (PARSE_ENUM(JxlPrimaries, str, &c->primaries)) return true; if (ParseEnum(str, kJxlPrimariesNames, &c->primaries)) return true;
Tokenizer xy_tokenizer(&str, ';'); Tokenizer xy_tokenizer(&str, ';');
JXL_RETURN_IF_ERROR(ParseDouble(&xy_tokenizer, c->primaries_red_xy + 0)); JXL_RETURN_IF_ERROR(ParseDouble(&xy_tokenizer, c->primaries_red_xy + 0));
@ -168,13 +164,14 @@ Status ParsePrimaries(Tokenizer* tokenizer, JxlColorEncoding* c) {
JXL_RETURN_IF_ERROR(ParseDouble(&xy_tokenizer, c->primaries_blue_xy + 1)); JXL_RETURN_IF_ERROR(ParseDouble(&xy_tokenizer, c->primaries_blue_xy + 1));
c->primaries = JXL_PRIMARIES_CUSTOM; c->primaries = JXL_PRIMARIES_CUSTOM;
return JXL_FAILURE("Invalid primaries %s", str.c_str()); return true;
} }
Status ParseRenderingIntent(Tokenizer* tokenizer, JxlColorEncoding* c) { Status ParseRenderingIntent(Tokenizer* tokenizer, JxlColorEncoding* c) {
std::string str; std::string str;
JXL_RETURN_IF_ERROR(tokenizer->Next(&str)); JXL_RETURN_IF_ERROR(tokenizer->Next(&str));
if (PARSE_ENUM(JxlRenderingIntent, str, &c->rendering_intent)) return true; if (ParseEnum(str, kJxlRenderingIntentNames, &c->rendering_intent))
return true;
return JXL_FAILURE("Invalid RenderingIntent %s\n", str.c_str()); return JXL_FAILURE("Invalid RenderingIntent %s\n", str.c_str());
} }
@ -189,7 +186,7 @@ Status ParseTransferFunction(Tokenizer* tokenizer, JxlColorEncoding* c) {
std::string str; std::string str;
JXL_RETURN_IF_ERROR(tokenizer->Next(&str)); JXL_RETURN_IF_ERROR(tokenizer->Next(&str));
if (PARSE_ENUM(JxlTransferFunction, str, &c->transfer_function)) { if (ParseEnum(str, kJxlTransferFunctionNames, &c->transfer_function)) {
return true; return true;
} }
@ -206,12 +203,38 @@ Status ParseTransferFunction(Tokenizer* tokenizer, JxlColorEncoding* c) {
Status ParseDescription(const std::string& description, JxlColorEncoding* c) { Status ParseDescription(const std::string& description, JxlColorEncoding* c) {
*c = {}; *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, '_'); Tokenizer tokenizer(&description, '_');
JXL_RETURN_IF_ERROR(ParseColorSpace(&tokenizer, c)); JXL_RETURN_IF_ERROR(ParseColorSpace(&tokenizer, c));
JXL_RETURN_IF_ERROR(ParseWhitePoint(&tokenizer, c)); JXL_RETURN_IF_ERROR(ParseWhitePoint(&tokenizer, c));
JXL_RETURN_IF_ERROR(ParsePrimaries(&tokenizer, c)); JXL_RETURN_IF_ERROR(ParsePrimaries(&tokenizer, c));
JXL_RETURN_IF_ERROR(ParseRenderingIntent(&tokenizer, c)); JXL_RETURN_IF_ERROR(ParseRenderingIntent(&tokenizer, c));
JXL_RETURN_IF_ERROR(ParseTransferFunction(&tokenizer, c)); JXL_RETURN_IF_ERROR(ParseTransferFunction(&tokenizer, c));
}
return true; return true;
} }

Some files were not shown because too many files have changed in this diff Show more