├── .clang-format ├── .clang-tidy ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── build_test.yml │ ├── debug_ci.yml │ └── pull_request.yml ├── .gitignore ├── .gitmodules ├── .readthedocs.yaml ├── AUTHORS ├── CHANGELOG.md ├── CMakeLists.txt ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── CONTRIBUTORS ├── LICENSE ├── PATENTS ├── README.Haiku.md ├── README.OSX.md ├── README.md ├── SECURITY.md ├── bash_test.sh ├── ci.sh ├── cmake ├── FindAtomics.cmake └── FindHWY.cmake ├── deps.sh ├── doc ├── api.txt ├── benchmarking.md ├── building_and_testing.md ├── building_wasm.md ├── coding_tools.md ├── color_management.md ├── data_flow.dot ├── data_flow.svg ├── developing_in_debian.md ├── developing_in_docker.md ├── developing_in_github.md ├── developing_in_windows_msys.md ├── developing_in_windows_vcpkg.md ├── developing_with_crossroad.md ├── format_overview.md ├── fuzzing.md ├── jxl.svg ├── man │ ├── cjxl.txt │ └── djxl.txt ├── release.md ├── software_support.md ├── sphinx │ ├── api.rst │ ├── api_butteraugli.rst │ ├── api_common.rst │ ├── api_decoder.rst │ ├── api_encoder.rst │ ├── api_threads.rst │ ├── conf.py │ ├── index.rst │ └── requirements.txt ├── tables │ ├── adobe.md │ ├── all_tables.pdf │ ├── all_tables.sh │ ├── app0.md │ ├── brn_proto.md │ ├── context_modes.md │ ├── dct_gen.md │ ├── ducky.md │ ├── freq_context.md │ ├── icc.md │ ├── is_zero_base.md │ ├── markdown-pdf.css │ ├── nonzero_buckets.md │ ├── num_nonzero_context.md │ ├── num_nonzeros_base.md │ ├── quant.md │ ├── stock_counts.md │ ├── stock_quant.md │ ├── stock_values.md │ └── symbol_order.md ├── vuln_playbook.md └── xl_overview.md ├── docker ├── Dockerfile.jpegxl-builder ├── Dockerfile.jpegxl-builder-run-aarch64 ├── README.md ├── build.sh └── scripts │ ├── 99_norecommends │ ├── binutils_align_fix.patch │ ├── emsdk_install.sh │ ├── jpegxl_builder.sh │ ├── msan_install.sh │ └── qemu_install.sh ├── encoder ├── CMakeLists.txt ├── ac_context.h ├── ac_strategy.h ├── base │ ├── bits.h │ ├── byte_order.h │ ├── cache_aligned.cc │ ├── cache_aligned.h │ ├── compiler_specific.h │ ├── data_parallel.cc │ ├── data_parallel.h │ ├── padded_bytes.cc │ ├── padded_bytes.h │ ├── printf_macros.h │ ├── sanitizer_definitions.h │ ├── span.h │ └── status.h ├── chroma_from_luma.h ├── cjxl_main.cc ├── common.h ├── config.h ├── dc_group_data.h ├── dct_scales.cc ├── dct_scales.h ├── enc_ac_strategy.cc ├── enc_ac_strategy.h ├── enc_adaptive_quantization.cc ├── enc_adaptive_quantization.h ├── enc_bit_writer.cc ├── enc_bit_writer.h ├── enc_chroma_from_luma.cc ├── enc_chroma_from_luma.h ├── enc_cluster.cc ├── enc_cluster.h ├── enc_entropy_code.cc ├── enc_entropy_code.h ├── enc_file.cc ├── enc_file.h ├── enc_frame.cc ├── enc_frame.h ├── enc_group.cc ├── enc_group.h ├── enc_huffman_tree.cc ├── enc_huffman_tree.h ├── enc_transforms-inl.h ├── enc_xyb.cc ├── enc_xyb.h ├── entropy_code.h ├── fast_math-inl.h ├── histogram.h ├── image.cc ├── image.h ├── quant_weights.cc ├── quant_weights.h ├── read_pfm.cc ├── read_pfm.h ├── static_entropy_codes.h └── token.h ├── third_party ├── CMakeLists.txt └── testing.cmake └── tools └── check_author.py /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google 2 | IncludeCategories: 3 | - Regex: '^ 6 | # instead . 7 | # - modernize-return-braced-init-list: this often doesn't improve readability. 8 | # - modernize-use-auto: is too aggressive towards using auto. 9 | # - modernize-use-default-member-init: with a mix of constructors and default 10 | # member initialization this can be confusing if enforced. 11 | # - modernize-use-trailing-return-type: does not improve readability when used 12 | # systematically. 13 | # - modernize-use-using: typedefs are ok. 14 | # 15 | # - readability-else-after-return: It doesn't always improve readability. 16 | # - readability-static-accessed-through-instance 17 | # It is often more useful and readable to access a constant of a passed 18 | # variable (like d.N) instead of using the type of the variable that could be 19 | # long and complex. 20 | # - readability-uppercase-literal-suffix: we write 1.0f, not 1.0F. 21 | 22 | Checks: >- 23 | bugprone-*, 24 | clang-*, 25 | -clang-diagnostic-unused-command-line-argument, 26 | google-*, 27 | modernize-*, 28 | performance-*, 29 | readability-*, 30 | -google-readability-todo, 31 | -modernize-deprecated-headers, 32 | -modernize-return-braced-init-list, 33 | -modernize-use-auto, 34 | -modernize-use-default-member-init, 35 | -modernize-use-trailing-return-type, 36 | -modernize-use-using, 37 | -readability-else-after-return, 38 | -readability-function-cognitive-complexity, 39 | -readability-static-accessed-through-instance, 40 | -readability-uppercase-literal-suffix, 41 | 42 | 43 | WarningsAsErrors: >- 44 | bugprone-argument-comment, 45 | bugprone-macro-parentheses, 46 | bugprone-suspicious-string-compare, 47 | bugprone-use-after-move, 48 | clang-*, 49 | clang-analyzer-*, 50 | -clang-diagnostic-unused-command-line-argument, 51 | google-build-using-namespace, 52 | google-explicit-constructor, 53 | google-readability-braces-around-statements, 54 | google-readability-namespace-comments, 55 | modernize-use-override, 56 | readability-inconsistent-declaration-parameter-name 57 | 58 | # We are only interested in the headers from this projects, excluding 59 | # third_party/ and build/. 60 | HeaderFilterRegex: '^.*/(lib|tools)/.*\.h$' 61 | 62 | CheckOptions: 63 | - key: readability-braces-around-statements.ShortStatementLines 64 | value: '2' 65 | - key: google-readability-braces-around-statements.ShortStatementLines 66 | value: '2' 67 | - key: readability-implicit-bool-conversion.AllowPointerConditions 68 | value: '1' 69 | - key: readability-implicit-bool-conversion.AllowIntegerConditions 70 | value: '1' 71 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 16 | **Expected behavior** 17 | A clear and concise description of what you expected to happen. 18 | 19 | **Screenshots** 20 | If applicable, add screenshots or example input/output images to help explain your problem. 21 | 22 | **Environment** 23 | - OS: [e.g. Windows] 24 | - Compiler version: [e.g. clang 11.0.1] 25 | - CPU type: [e.g. x86_64] 26 | - cjxl/djxl version string: [e.g. cjxl [v0.3.7 | SIMD supported: SSE4,Scalar]] 27 | 28 | **Additional context** 29 | Add any other context about the problem here. 30 | 31 | 38 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/debug_ci.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) the JPEG XL Project Authors. All rights reserved. 2 | # 3 | # Use of this source code is governed by a BSD-style 4 | # license that can be found in the LICENSE file. 5 | 6 | # Workflow for building and then debugging on a specific commit. 7 | 8 | name: Build and Test debugging 9 | on: 10 | push: 11 | branches: 12 | - ci-*-debug 13 | 14 | jobs: 15 | ubuntu_build: 16 | name: Ubuntu Build and SSH 17 | runs-on: [ubuntu-latest] 18 | 19 | steps: 20 | - name: Install build deps 21 | run: | 22 | sudo apt update 23 | sudo apt install -y \ 24 | ccache \ 25 | clang-7 \ 26 | cmake \ 27 | doxygen \ 28 | libbrotli-dev \ 29 | libgdk-pixbuf2.0-dev \ 30 | libgif-dev \ 31 | libgtest-dev \ 32 | libgtk2.0-dev \ 33 | libjpeg-dev \ 34 | libopenexr-dev \ 35 | libpng-dev \ 36 | libwebp-dev \ 37 | ninja-build \ 38 | pkg-config \ 39 | xvfb \ 40 | ${{ matrix.apt_pkgs }} \ 41 | # 42 | echo "CC=clang-7" >> $GITHUB_ENV 43 | echo "CXX=clang++-7" >> $GITHUB_ENV 44 | - name: Checkout the source 45 | uses: actions/checkout@v2 46 | with: 47 | submodules: true 48 | fetch-depth: 2 49 | - name: Build 50 | run: | 51 | ./ci.sh $(echo ${{ github.ref }} | sed 's_refs/heads/ci-\([a-z_]*\)-debug_\1_') \ 52 | -DJPEGXL_FORCE_SYSTEM_BROTLI=ON 53 | env: 54 | SKIP_TEST: 1 55 | - name: Setup tmate session 56 | uses: mxschmitt/action-tmate@v3 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /.github/workflows/pull_request.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) the JPEG XL Project Authors. All rights reserved. 2 | # 3 | # Use of this source code is governed by a BSD-style 4 | # license that can be found in the LICENSE file. 5 | 6 | # Workflow to run pull-requests specific checks. 7 | 8 | name: PR 9 | on: 10 | pull_request: 11 | types: [opened, reopened, synchronize] 12 | 13 | jobs: 14 | # Checks that the AUTHORS files is updated with new contributors. 15 | authors: 16 | runs-on: [ubuntu-latest] 17 | steps: 18 | - name: Checkout the source 19 | uses: actions/checkout@v2 20 | - name: Check AUTHORS file 21 | run: 22 | ./ci.sh authors 23 | 24 | format: 25 | runs-on: [ubuntu-latest] 26 | steps: 27 | - name: Install build deps 28 | run: | 29 | sudo apt update 30 | sudo apt install -y \ 31 | clang-format \ 32 | # 33 | - name: Checkout the source 34 | uses: actions/checkout@v2 35 | - name: clang-format 36 | run: 37 | ./ci.sh lint >&2 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build output directories 2 | /build 3 | /build* 4 | /docker/*.log 5 | 6 | # The downloaded corpora files for benchmark. 7 | /third_party/corpora 8 | 9 | # hdrvdp source code 10 | third_party/hdrvdp-2.2.2 11 | third_party/hdrvdp-2.2.2.zip 12 | third_party/hdrvdp-2.2.2.zip.tmp 13 | 14 | # Output plots 15 | tools/benchmark/metrics/plots 16 | tools/benchmark/metrics/results.csv 17 | tools/conformance/__pycache__ 18 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "third_party/googletest"] 2 | path = third_party/googletest 3 | url = https://github.com/google/googletest 4 | [submodule "third_party/highway"] 5 | path = third_party/highway 6 | url = https://github.com/google/highway 7 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) the JPEG XL Project Authors. 2 | # 3 | # Use of this source code is governed by a BSD-style 4 | # license that can be found in the LICENSE file or at 5 | # https://developers.google.com/open-source/licenses/bsd 6 | # 7 | # readthedocs.io configuration file. See: 8 | # https://docs.readthedocs.io/en/stable/config-file/v2.html 9 | 10 | version: 2 11 | 12 | sphinx: 13 | configuration: doc/sphinx/conf.py 14 | 15 | python: 16 | version: "3.7" 17 | install: 18 | - requirements: doc/sphinx/requirements.txt 19 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # List of the project authors for copyright purposes. When contributing to the 2 | # project add your name or your organization's name to this list. See 3 | # CONTRIBUTING.md for details. 4 | # 5 | # For organizations: 6 | # Organization 7 | # 8 | # For individuals: 9 | # Name 10 | # 11 | # Please keep each list sorted. If you wish to change your email address please 12 | # send a pull request. 13 | 14 | # Organizations: 15 | Cloudinary Ltd. <*@cloudinary.com> 16 | Google LLC <*@google.com> 17 | 18 | # Individuals: 19 | Alex Xu (Hello71) 20 | Alexander Sago 21 | Andrius Lukas Narbutas 22 | Aous Naman 23 | Artem Selishchev 24 | Biswapriyo Nath 25 | CanadianBaconBoi 26 | Daniel Novomeský 27 | David Burnett 28 | Dirk Lemstra 29 | Don Olmstead 30 | Even Rouault 31 | Heiko Becker 32 | Jon Sneyers 33 | Kai Hollberg 34 | Kleis Auke Wolthuizen 35 | L. E. Segovia 36 | Leo Izen 37 | Lovell Fuller 38 | Maarten DB 39 | Marcin Konicki 40 | Martin Strunz 41 | Mathieu Malaterre 42 | Mikk Leini 43 | Misaki Kasumi 44 | Petr Diblík 45 | Pieter Wuille 46 | roland-rollo 47 | Samuel Leong 48 | Sandro 49 | Stephan T. Lavavej 50 | Vincent Torri 51 | xiota 52 | Yonatan Nebenzhal 53 | Ziemowit Zabawa 54 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of 9 | experience, education, socio-economic status, nationality, personal appearance, 10 | race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or reject 41 | comments, commits, code, wiki edits, issues, and other contributions that are 42 | not aligned to this Code of Conduct, or to ban temporarily or permanently any 43 | contributor for other behaviors that they deem inappropriate, threatening, 44 | offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | This Code of Conduct also applies outside the project spaces when the Project 56 | Steward has a reasonable belief that an individual's behavior may have a 57 | negative impact on the project or its community. 58 | 59 | ## Conflict Resolution 60 | 61 | We do not believe that all conflict is bad; healthy debate and disagreement 62 | often yield positive results. However, it is never okay to be disrespectful or 63 | to engage in behavior that violates the project’s code of conduct. 64 | 65 | If you see someone violating the code of conduct, you are encouraged to address 66 | the behavior directly with those involved. Many issues can be resolved quickly 67 | and easily, and this gives people more control over the outcome of their 68 | dispute. If you are unable to resolve the matter for any reason, or if the 69 | behavior is threatening or harassing, report it. We are dedicated to providing 70 | an environment where participants feel welcome and safe. 71 | 72 | Reports should be directed to Jyrki Alakuijala , the 73 | Project Steward(s) for JPEG XL. It is the Project Steward’s duty to 74 | receive and address reported violations of the code of conduct. They will then 75 | work with a committee consisting of representatives from the Open Source 76 | Programs Office and the Google Open Source Strategy team. If for any reason you 77 | are uncomfortable reaching out to the Project Steward, please email 78 | opensource@google.com. 79 | 80 | We will investigate every complaint, but you may not receive a direct response. 81 | We will use our discretion in determining when and how to follow up on reported 82 | incidents, which may range from not taking action to permanent expulsion from 83 | the project and project-sponsored spaces. We will notify the accused of the 84 | report and provide them an opportunity to discuss it before any action is taken. 85 | The identity of the reporter will be omitted from the details of the report 86 | supplied to the accused. In potentially harmful situations, such as ongoing 87 | harassment or threats to anyone's safety, we may take action without notice. 88 | 89 | ## Attribution 90 | 91 | This Code of Conduct is adapted from the Contributor Covenant, version 1.4, 92 | available at 93 | https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 94 | -------------------------------------------------------------------------------- /CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | # This files lists individuals who made significant contributions to the JPEG XL 2 | # code base, such as design, adding features, performing experiments, ... 3 | # Small changes such as a small bugfix or fixing spelling errors are not 4 | # included. If you'd like to be included in this file thanks to a significant 5 | # contribution, feel free to send a pull request changing this file. 6 | Alex Deymo 7 | Alexander Rhatushnyak 8 | Evgenii Kliuchnikov 9 | Iulia-Maria Comșa 10 | Jan Wassenberg 11 | Jon Sneyers 12 | Jyrki Alakuijala 13 | Krzysztof Potempa 14 | Lode Vandevenne 15 | Luca Versari 16 | Martin Bruse 17 | Moritz Firsching 18 | Renata Khasanova 19 | Robert Obryk 20 | Sami Boukortt 21 | Sebastian Gomez-Gonzalez 22 | Thomas Fischbacher 23 | Zoltan Szabadka 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) the JPEG XL Project Authors. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of the copyright holder nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /PATENTS: -------------------------------------------------------------------------------- 1 | Additional IP Rights Grant (Patents) 2 | 3 | "This implementation" means the copyrightable works distributed by 4 | Google as part of the JPEG XL project. 5 | 6 | Google hereby grants to You a perpetual, worldwide, non-exclusive, 7 | no-charge, royalty-free, irrevocable (except as stated in this section) 8 | patent license to make, have made, use, offer to sell, sell, import, 9 | transfer and otherwise run, modify and propagate the contents of this 10 | implementation of JPEG XL, where such license applies only to those patent 11 | claims, both currently owned or controlled by Google and acquired in 12 | the future, licensable by Google that are necessarily infringed by this 13 | implementation of JPEG XL. This grant does not include claims that would be 14 | infringed only as a consequence of further modification of this 15 | implementation. If you or your agent or exclusive licensee institute or 16 | order or agree to the institution of patent litigation against any 17 | entity (including a cross-claim or counterclaim in a lawsuit) alleging 18 | that this implementation of JPEG XL or any code incorporated within this 19 | implementation of JPEG XL constitutes direct or contributory patent 20 | infringement, or inducement of patent infringement, then any patent 21 | rights granted to you under this License for this implementation of JPEG XL 22 | shall terminate as of the date such litigation is filed. 23 | -------------------------------------------------------------------------------- /README.Haiku.md: -------------------------------------------------------------------------------- 1 | ## Disclaimer 2 | 3 | Haiku builds are not officially supported, i.e. the build might not work at all, 4 | some tests may fail and some sub-projects are excluded from build. 5 | 6 | This manual outlines Haiku-specific setup. For general building and testing 7 | instructions see "[README](README.md)" and 8 | "[Building and Testing changes](doc/building_and_testing.md)". 9 | 10 | ## Dependencies 11 | 12 | ```shell 13 | pkgman install llvm9_clang ninja cmake doxygen libjpeg_turbo_devel giflib_devel 14 | ``` 15 | 16 | ## Building 17 | 18 | ```shell 19 | 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 20 | ``` 21 | -------------------------------------------------------------------------------- /README.OSX.md: -------------------------------------------------------------------------------- 1 | ## Disclaimer 2 | 3 | OSX builds have "best effort" support, i.e. build might not work at all, some 4 | tests may fail and some sub-projects are excluded from build. 5 | 6 | This manual outlines OSX specific setup. For general building and testing 7 | instructions see "[README](README.md)" and 8 | "[Building and Testing changes](doc/building_and_testing.md)". 9 | 10 | [Homebrew](https://brew.sh/) is a popular package manager. JPEG XL library and 11 | binaries could be installed using it: 12 | 13 | ```bash 14 | brew install jpeg-xl 15 | ``` 16 | 17 | ## Dependencies 18 | 19 | Make sure that `brew doctor` does not report serious problems and up-to-date 20 | version of XCode is installed. 21 | 22 | Installing (actually, building) `clang` might take a couple hours. 23 | 24 | ```bash 25 | brew install llvm 26 | ``` 27 | 28 | ```bash 29 | brew install coreutils cmake giflib jpeg-turbo libpng ninja zlib 30 | ``` 31 | 32 | Before building the project check that `which clang` is 33 | `/usr/local/opt/llvm/bin/clang`, not the one provided by XCode. If not, update 34 | `PATH` environment variable. 35 | 36 | Also, setting `CMAKE_PREFIX_PATH` might be necessary for correct include paths 37 | resolving, e.g.: 38 | 39 | ```bash 40 | export CMAKE_PREFIX_PATH=`brew --prefix giflib`:`brew --prefix jpeg-turbo`:`brew --prefix libpng`:`brew --prefix zlib` 41 | ``` -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security and Vulnerability Policy for libjxl 2 | 3 | ## TL;DR: 4 | 5 | CPE prefix: `cpe:2.3:a:libjxl_project:libjxl` 6 | 7 | To report a security issue, please email libjxl-security@google.com. 8 | 9 | Include in your email a description of the issue, the steps you took to create 10 | the issue, affected versions, and if known, mitigations for the issue. Our 11 | vulnerability management team will acknowledge receiving your email within 3 12 | working days. 13 | 14 | This project follows a 90 day disclosure timeline. 15 | 16 | For all other bugs, where there are no security implications about disclosing 17 | the unpatched bug, open a [new issue](https://github.com/libjxl/libjxl/issues) 18 | checking first for existing similar issues. If in doubt about the security 19 | impact of a bug you discovered, email first. 20 | 21 | ## Policy overview 22 | 23 | libjxl's Security Policy is based on the [Google Open Source program 24 | guidelines](https://github.com/google/oss-vulnerability-guide) for coordinated 25 | vulnerability disclosure. 26 | 27 | Early versions of `libjxl` had a different security policy that didn't provide 28 | security and vulnerability disclosure support. Versions up to and including 29 | 0.3.7 are not covered and won't receive any security advisory. 30 | 31 | Only released versions, starting from version 0.5, are covered by this policy. 32 | Development branches, arbitrary commits from `main` branch or even releases with 33 | backported features externally patched on top are not covered. Only those 34 | versions with a release tag in `libjxl`'s repository are covered, starting from 35 | version 0.5. 36 | 37 | ## What's a "Security bug" 38 | 39 | A security bug is a bug that can potentially be exploited to let an attacker 40 | gain unauthorized access or privileges such as disclosing information or 41 | arbitrary code execution. Not all fuzzer-found bugs and not all assert() 42 | failures are considered security bugs in libjxl. For a detailed explanation and 43 | examples see our [Security Vulnerabilities Playbook](doc/vuln_playbook.md). 44 | 45 | ## What to expect 46 | 47 | To report a security issue, please email libjxl-security@google.com with all the 48 | details about the bug you encountered. 49 | 50 | * Include a description of the issue, steps to reproduce, etc. Compiler 51 | versions, flags, exact version used and even CPU are often relevant given our 52 | usage of SIMD and run-time dispatch of SIMD instructions. 53 | 54 | * A member of our security team will reply to you within 3 business days. Note 55 | that business days are different in different countries. 56 | 57 | * We will evaluate the issue and we may require more input from your side to 58 | reproduce it. 59 | 60 | * If the issue fits in the description of a security bug, we will issue a 61 | CVE, publish a fix and make a new minor or patch release with it. There is 62 | a maximum of 90 day disclosure timeline, we ask you to not publish the 63 | details before the 90 day deadline or the release date (whichever comes 64 | first). 65 | 66 | * In the case that we publish a CVE we will credit the external researcher who 67 | reported the issue. When reporting security issues please let us know if you 68 | need to include specific information while doing so, like for example a 69 | company affiliation. 70 | 71 | Our security team follows the [Security Vulnerabilities 72 | Playbook](doc/vuln_playbook.md). For more details about the process and policies 73 | please take a look at it. 74 | -------------------------------------------------------------------------------- /cmake/FindAtomics.cmake: -------------------------------------------------------------------------------- 1 | # Copyright (c) the JPEG XL Project Authors. 2 | # 3 | # Use of this source code is governed by a BSD-style 4 | # license that can be found in the LICENSE file or at 5 | # https://developers.google.com/open-source/licenses/bsd 6 | 7 | # Original issue: 8 | # * https://gitlab.kitware.com/cmake/cmake/-/issues/23021#note_1098733 9 | # 10 | # For reference: 11 | # * https://gcc.gnu.org/wiki/Atomic/GCCMM 12 | # 13 | # riscv64 specific: 14 | # * https://lists.debian.org/debian-riscv/2022/01/msg00009.html 15 | # 16 | # ATOMICS_FOUND - system has c++ atomics 17 | # ATOMICS_LIBRARIES - libraries needed to use c++ atomics 18 | 19 | include(CheckCXXSourceCompiles) 20 | 21 | # RISC-V only has 32-bit and 64-bit atomic instructions. GCC is supposed 22 | # to convert smaller atomics to those larger ones via masking and 23 | # shifting like LLVM, but it’s a known bug that it does not. This means 24 | # anything that wants to use atomics on 1-byte or 2-byte types needs 25 | # -latomic, but not 4-byte or 8-byte (though it does no harm). 26 | set(atomic_code 27 | " 28 | #include 29 | #include 30 | std::atomic n8 (0); // riscv64 31 | std::atomic n64 (0); // armel, mipsel, powerpc 32 | int main() { 33 | ++n8; 34 | ++n64; 35 | return 0; 36 | }") 37 | 38 | check_cxx_source_compiles("${atomic_code}" ATOMICS_LOCK_FREE_INSTRUCTIONS) 39 | 40 | if(ATOMICS_LOCK_FREE_INSTRUCTIONS) 41 | set(ATOMICS_FOUND TRUE) 42 | set(ATOMICS_LIBRARIES) 43 | else() 44 | set(CMAKE_REQUIRED_LIBRARIES "-latomic") 45 | check_cxx_source_compiles("${atomic_code}" ATOMICS_IN_LIBRARY) 46 | set(CMAKE_REQUIRED_LIBRARIES) 47 | if(ATOMICS_IN_LIBRARY) 48 | set(ATOMICS_LIBRARY atomic) 49 | include(FindPackageHandleStandardArgs) 50 | find_package_handle_standard_args(Atomics DEFAULT_MSG ATOMICS_LIBRARY) 51 | set(ATOMICS_LIBRARIES ${ATOMICS_LIBRARY}) 52 | unset(ATOMICS_LIBRARY) 53 | else() 54 | if(Atomics_FIND_REQUIRED) 55 | message(FATAL_ERROR "Neither lock free instructions nor -latomic found.") 56 | endif() 57 | endif() 58 | endif() 59 | unset(atomic_code) 60 | -------------------------------------------------------------------------------- /cmake/FindHWY.cmake: -------------------------------------------------------------------------------- 1 | # Copyright (c) the JPEG XL Project Authors. 2 | # 3 | # Use of this source code is governed by a BSD-style 4 | # license that can be found in the LICENSE file or at 5 | # https://developers.google.com/open-source/licenses/bsd 6 | 7 | find_package(PkgConfig QUIET) 8 | if (PkgConfig_FOUND) 9 | pkg_check_modules(PC_HWY QUIET libhwy) 10 | set(HWY_VERSION ${PC_HWY_VERSION}) 11 | endif () 12 | 13 | find_path(HWY_INCLUDE_DIR 14 | NAMES hwy/highway.h 15 | HINTS ${PC_HWY_INCLUDEDIR} ${PC_HWY_INCLUDE_DIRS} 16 | ) 17 | 18 | find_library(HWY_LIBRARY 19 | NAMES ${HWY_NAMES} hwy 20 | HINTS ${PC_HWY_LIBDIR} ${PC_HWY_LIBRARY_DIRS} 21 | ) 22 | 23 | if (HWY_INCLUDE_DIR AND NOT HWY_VERSION) 24 | if (EXISTS "${HWY_INCLUDE_DIR}/hwy/highway.h") 25 | file(READ "${HWY_INCLUDE_DIR}/hwy/highway.h" HWY_VERSION_CONTENT) 26 | 27 | string(REGEX MATCH "#define HWY_MAJOR +([0-9]+)" _dummy "${HWY_VERSION_CONTENT}") 28 | set(HWY_VERSION_MAJOR "${CMAKE_MATCH_1}") 29 | 30 | string(REGEX MATCH "#define +HWY_MINOR +([0-9]+)" _dummy "${HWY_VERSION_CONTENT}") 31 | set(HWY_VERSION_MINOR "${CMAKE_MATCH_1}") 32 | 33 | string(REGEX MATCH "#define +HWY_PATCH +([0-9]+)" _dummy "${HWY_VERSION_CONTENT}") 34 | set(HWY_VERSION_PATCH "${CMAKE_MATCH_1}") 35 | 36 | set(HWY_VERSION "${HWY_VERSION_MAJOR}.${HWY_VERSION_MINOR}.${HWY_VERSION_PATCH}") 37 | endif () 38 | endif () 39 | 40 | include(FindPackageHandleStandardArgs) 41 | find_package_handle_standard_args(HWY 42 | FOUND_VAR HWY_FOUND 43 | REQUIRED_VARS HWY_LIBRARY HWY_INCLUDE_DIR 44 | VERSION_VAR HWY_VERSION 45 | ) 46 | 47 | if (HWY_LIBRARY AND NOT TARGET hwy) 48 | add_library(hwy INTERFACE IMPORTED GLOBAL) 49 | 50 | if(CMAKE_VERSION VERSION_LESS "3.13.5") 51 | set_property(TARGET hwy PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${HWY_INCLUDE_DIR}) 52 | target_link_libraries(hwy INTERFACE ${HWY_LIBRARY}) 53 | set_property(TARGET hwy PROPERTY INTERFACE_COMPILE_OPTIONS ${PC_HWY_CFLAGS_OTHER}) 54 | else() 55 | target_include_directories(hwy INTERFACE ${HWY_INCLUDE_DIR}) 56 | target_link_libraries(hwy INTERFACE ${HWY_LIBRARY}) 57 | target_link_options(hwy INTERFACE ${PC_HWY_LDFLAGS_OTHER}) 58 | target_compile_options(hwy INTERFACE ${PC_HWY_CFLAGS_OTHER}) 59 | endif() 60 | endif() 61 | 62 | mark_as_advanced(HWY_INCLUDE_DIR HWY_LIBRARY) 63 | 64 | if (HWY_FOUND) 65 | set(HWY_LIBRARIES ${HWY_LIBRARY}) 66 | set(HWY_INCLUDE_DIRS ${HWY_INCLUDE_DIR}) 67 | endif () 68 | -------------------------------------------------------------------------------- /deps.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright (c) the JPEG XL Project Authors. 3 | # 4 | # Use of this source code is governed by a BSD-style 5 | # license that can be found in the LICENSE file or at 6 | # https://developers.google.com/open-source/licenses/bsd 7 | 8 | # This file downloads the dependencies needed to build JPEG XL into third_party. 9 | # These dependencies are normally pulled by gtest. 10 | 11 | set -eu 12 | 13 | MYDIR=$(dirname $(realpath "$0")) 14 | 15 | # Git revisions we use for the given submodules. Update these whenever you 16 | # update a git submodule. 17 | THIRD_PARTY_HIGHWAY="7f2e26854086fba4255220fd6c77e9141f1f87cc" 18 | 19 | # Download the target revision from GitHub. 20 | download_github() { 21 | local path="$1" 22 | local project="$2" 23 | 24 | local varname=`echo "$path" | tr '[:lower:]' '[:upper:]'` 25 | varname="${varname/\//_}" 26 | local sha 27 | eval "sha=\${${varname}}" 28 | 29 | local down_dir="${MYDIR}/downloads" 30 | local local_fn="${down_dir}/${sha}.tar.gz" 31 | if [[ -e "${local_fn}" && -d "${MYDIR}/${path}" ]]; then 32 | echo "${path} already up to date." >&2 33 | return 0 34 | fi 35 | 36 | local url 37 | local strip_components=0 38 | if [[ "${project:0:4}" == "http" ]]; then 39 | # "project" is a googlesource.com base url. 40 | url="${project}${sha}.tar.gz" 41 | else 42 | # GitHub files have a top-level directory 43 | strip_components=1 44 | url="https://github.com/${project}/tarball/${sha}" 45 | fi 46 | 47 | echo "Downloading ${path} version ${sha}..." >&2 48 | mkdir -p "${down_dir}" 49 | curl -L --show-error -o "${local_fn}.tmp" "${url}" 50 | mkdir -p "${MYDIR}/${path}" 51 | tar -zxf "${local_fn}.tmp" -C "${MYDIR}/${path}" \ 52 | --strip-components="${strip_components}" 53 | mv "${local_fn}.tmp" "${local_fn}" 54 | } 55 | 56 | 57 | main() { 58 | if git -C "${MYDIR}" rev-parse; then 59 | cat >&2 < 6 | 7 | The individual steps in the graph above are also sometimes simplified compared 8 | to the full libjxl encoder, namely: 9 | 10 | * Color correlation map: use only DCT8 and fast heuristics 11 | 12 | * ACStrategy selection: use only 8x8, 8x16 and 16x8 transforms, use only 13 | aligned blocks 14 | 15 | * DC coding: use fixed tree, gradient predictor, context based on gradient 16 | property 17 | 18 | * AC quantization: no error diffusion 19 | 20 | * AC context modeling: default block entropy context model 21 | 22 | * AC tokenization: use only default coefficient order ("zig-zag") 23 | 24 | * Entropy coding: only one uint coding scheme, no backward references, only ANS 25 | codes (with no histogram shifts) -------------------------------------------------------------------------------- /doc/color_management.md: -------------------------------------------------------------------------------- 1 | # Color Management 2 | 3 | [TOC] 4 | 5 | 9 | 10 | ## Why 11 | 12 | The vast majority of web images are still sRGB. However, wide-gamut material is 13 | increasingly being produced (photography, cinema, 4K). Screens covering most of 14 | the Adobe RGB gamut are readily available and some also cover most of DCI P3 15 | (iPhone, Pixel2) or even BT.2020. 16 | 17 | Currently, after a camera records a very saturated red pixel, most raw 18 | processors would clip it to the rather small sRGB gamut before saving as JPEG. 19 | In keeping with our high-quality goal, we prevent such loss by allowing wider 20 | input color spaces. 21 | 22 | ## Which color space 23 | 24 | Even wide gamuts could be expressed relative to the sRGB primaries, but the 25 | resulting coordinates may be outside the valid 0..1 range. Surprisingly, such 26 | 'unbounded' coordinates can be passed through color transforms provided the 27 | transfer functions are expressed as parametric functions (not lookup tables). 28 | However, most image file formats (including PNG and PNM) lack min/max metadata 29 | and thus do not support unbounded coordinates. 30 | 31 | Instead, we need a larger working gamut to ensure most pixel coordinates are 32 | within bounds and thus not clipped. However, larger gamuts result in lower 33 | precision/resolution when using <= 16 bit encodings (as opposed to 32-bit float 34 | in PFM). BT.2100 or P3 DCI appear to be good compromises. 35 | 36 | ## CMS library 37 | 38 | Transforms with unbounded pixels are desirable because they reduce round-trip 39 | error in tests. This requires parametric curves, which are only supported for 40 | the common sRGB case in ICC v4 profiles. ArgyllCMS does not support v4. The 41 | other popular open-source CMS is LittleCMS. It is also used by color-managed 42 | editors (Krita/darktable), which increases the chances of interoperability. 43 | However, LCMS has race conditions and overflow issues that prevent fuzzing. We 44 | will later switch to the newer skcms. Note that this library does not intend to 45 | support multiProcessElements, so HDR transfer functions cannot be represented 46 | accurately. Thus in the long term, we will probably migrate away from ICC 47 | profiles entirely. 48 | 49 | ## Which viewer 50 | 51 | On Linux, Krita and darktable support loading our PNG output images and their 52 | ICC profile. 53 | 54 | ## How to compress/decompress 55 | 56 | ### Embedded ICC profile 57 | 58 | - Create an 8-bit or 16-bit PNG with an iCCP chunk, e.g. using darktable. 59 | - Pass it to `cjxl`, then `djxl` with no special arguments. The decoded output 60 | will have the same bit depth (can override with `--output_bit_depth`) and 61 | color space. 62 | 63 | ### Images without metadata (e.g. HDR) 64 | 65 | - Create a PGM/PPM/PFM file in a known color space. 66 | - Invoke `cjxl` with `-x color_space=RGB_D65_202_Rel_Lin` (linear 2020). For 67 | details/possible values, see color_encoding.cc `Description`. 68 | - Invoke `djxl` as above with no special arguments. 69 | -------------------------------------------------------------------------------- /doc/data_flow.dot: -------------------------------------------------------------------------------- 1 | digraph { 2 | distance [rank=source,shape=hexagon]; 3 | linear [rank=source,shape=hexagon]; 4 | header [label="Header";shape=parallelogram]; 5 | linear -> size; 6 | size -> header; 7 | distance -> header; 8 | ToXYB [shape=rect]; 9 | linear -> ToXYB; 10 | ToXYB -> opsin; 11 | ComputeAdaptiveQuantField [shape=rect]; 12 | opsin -> ComputeAdaptiveQuantField; 13 | distance -> ComputeAdaptiveQuantField; 14 | ComputeAdaptiveQuantField -> quant_field; 15 | ComputeAdaptiveQuantField -> masking; 16 | ComputeAdaptiveQuantField -> raw_quant_field; 17 | opsin2 [label=opsin]; 18 | GaborishInverse [shape=rect]; 19 | opsin -> GaborishInverse; 20 | GaborishInverse -> opsin2; 21 | ComputeColorCorrelationMap [shape=rect]; 22 | opsin2 -> ComputeColorCorrelationMap; 23 | ComputeColorCorrelationMap -> cmapAC; 24 | ComputeColorCorrelationMap -> cmapDC; 25 | ComputeAcStrategyImage [shape=rect]; 26 | opsin2 -> ComputeAcStrategyImage; 27 | distance -> ComputeAcStrategyImage; 28 | cmapAC -> ComputeAcStrategyImage; 29 | quant_field -> ComputeAcStrategyImage; 30 | masking -> ComputeAcStrategyImage; 31 | ComputeAcStrategyImage -> ac_strategy; 32 | AdjustRawQuantField [shape=rect]; 33 | raw_quant_field -> AdjustRawQuantField; 34 | ac_strategy -> AdjustRawQuantField; 35 | raw_quant_field2 [label=raw_quant_field]; 36 | AdjustRawQuantField -> raw_quant_field2; 37 | dc [label="DC Image"]; 38 | DCT [shape=rect]; 39 | opsin2 -> DCT; 40 | ac_strategy -> DCT; 41 | DCT -> dc; 42 | ac [label="AC Image"]; 43 | DCT -> ac; 44 | ComputeACTokens [shape=rect]; 45 | ac -> ComputeACTokens; 46 | raw_quant_field2 -> ComputeACTokens; 47 | cmapAC -> ComputeACTokens; 48 | ComputeACTokens -> ac_tokens; 49 | ComputeDCTokens [shape=rect]; 50 | dc -> ComputeDCTokens; 51 | cmapDC -> ComputeDCTokens; 52 | ComputeDCTokens -> dc_tokens; 53 | ComputeACMetaTokens [shape=rect]; 54 | cmapAC -> ComputeACMetaTokens; 55 | ac_strategy -> ComputeACMetaTokens; 56 | raw_quant_field2 -> ComputeACMetaTokens; 57 | ComputeACMetaTokens -> ac_meta_tokens; 58 | dcglobal [label="DC Global Section";shape=parallelogram] 59 | WriteDCGlobal [shape=rect]; 60 | cmapDC -> WriteDCGlobal; 61 | dc_tokens -> WriteDCGlobal; 62 | ac_meta_tokens -> WriteDCGlobal; 63 | WriteDCGlobal -> dc_code; 64 | WriteDCGlobal -> dc_context_map; 65 | WriteDCGlobal -> dcglobal; 66 | dcgroups [label="DC Group Sections";shape=parallelogram] 67 | WriteDCGroups [shape=rect]; 68 | dc_tokens -> WriteDCGroups; 69 | ac_meta_tokens -> WriteDCGroups; 70 | dc_code -> WriteDCGroups; 71 | dc_context_map -> WriteDCGroups; 72 | WriteDCGroups -> dcgroups; 73 | WriteACGlobal [shape=rect]; 74 | ac_tokens -> WriteACGlobal; 75 | WriteACGlobal -> ac_code; 76 | WriteACGlobal -> ac_context_map; 77 | acglobal [label="AC Global Section";shape=parallelogram] 78 | WriteACGlobal -> acglobal; 79 | WriteACGroups [shape=rect]; 80 | ac_tokens -> WriteACGroups; 81 | ac_code -> WriteACGroups; 82 | ac_context_map -> WriteACGroups; 83 | acgroups [label="AC Group Sections";shape=parallelogram] 84 | WriteACGroups -> acgroups; 85 | WriteToc [shape=rect]; 86 | dcglobal -> WriteToc; 87 | acglobal -> WriteToc; 88 | dcgroups -> WriteToc; 89 | acgroups -> WriteToc; 90 | toc [label="TOC";shape=parallelogram] 91 | WriteToc -> toc; 92 | jxl [label="JXL Bitstream";shape=parallelogram] 93 | header->jxl; 94 | toc -> jxl; 95 | dcglobal -> jxl; 96 | acglobal -> jxl; 97 | dcgroups -> jxl; 98 | acgroups -> jxl; 99 | } 100 | -------------------------------------------------------------------------------- /doc/developing_in_debian.md: -------------------------------------------------------------------------------- 1 | # Developing in Debian 2 | 3 | These instructions assume an up-to-date Debian/Ubuntu system. 4 | For other platforms, please instead use the following: 5 | 6 | * [Developing in Docker](developing_in_docker.md). 7 | * [Cross Compiling for Windows with Crossroad](developing_with_crossroad.md). 8 | 9 | ## Minimum build dependencies 10 | 11 | Apart from the dependencies in `third_party`, some of the tools use external 12 | dependencies that need to be installed on your system first: 13 | 14 | ```bash 15 | sudo apt install cmake clang doxygen g++ extra-cmake-modules \ 16 | libgif-dev libjpeg-dev ninja-build libgoogle-perftools-dev 17 | ``` 18 | 19 | Make sure your default `clang` compiler is at least version 6 by running 20 | 21 | ```bash 22 | clang --version 23 | ``` 24 | 25 | If it still shows an old version despite having, for example, `clang-7` installed, you need 26 | to update the default `clang` compiler. On Debian-based systems run: 27 | 28 | ```bash 29 | sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-7 100 30 | sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-7 100 31 | ``` 32 | 33 | Optionally, to compile some of the extra tool support and tests you can install 34 | the following packages: 35 | 36 | ```bash 37 | sudo apt install qtbase5-dev libqt5x11extras5-dev libwebp-dev libgimp2.0-dev \ 38 | libopenexr-dev libgtest-dev libgmock-dev libbenchmark-dev libbenchmark-tools 39 | ``` 40 | 41 | For the lint/coverage commands, you will also need additional packages: 42 | 43 | ```bash 44 | sudo apt install clang-format clang-tidy curl parallel gcovr 45 | ``` 46 | 47 | ## Building 48 | 49 | The `libjxl` project uses CMake to build. We provide a script that simplifies the 50 | invocation. To build and test the project, run 51 | 52 | ```bash 53 | ./ci.sh opt 54 | ``` 55 | 56 | This writes binaries to `build/tools` and runs unit tests. More information 57 | on [build modes and testing](building_and_testing.md) is available. 58 | -------------------------------------------------------------------------------- /doc/developing_in_docker.md: -------------------------------------------------------------------------------- 1 | # Developing in Docker 2 | 3 | Docker allows software to be run in a packaged container, isolated from the 4 | host system. This allows code to be run in a standard environment instead 5 | of dealing with different build environments during development. It also 6 | simplifies resolving external dependencies by including them in the automated 7 | setup of the container environment. 8 | 9 | ## Set up the container 10 | 11 | You can read installation instructions and download Docker for your 12 | operating system at [Get Docker](https://docs.docker.com/get-docker/). 13 | 14 | The image used by our builders is an Ubuntu Bionic image with all the 15 | required dependencies and build tools installed. You can pull this image 16 | from `gcr.io/jpegxl/jpegxl-builder` using the following command: 17 | 18 | ```bash 19 | sudo docker pull gcr.io/jpegxl/jpegxl-builder 20 | ``` 21 | 22 | To use the Docker image you can run the following command: 23 | 24 | ```bash 25 | sudo docker run -it --rm \ 26 | --user $(id -u):$(id -g) \ 27 | -v $HOME/jpeg-xl:/jpeg-xl -w /jpeg-xl \ 28 | gcr.io/jpegxl/jpegxl-builder bash 29 | ``` 30 | 31 | This creates and runs a container that will be deleted after you exit the 32 | terminal (`--rm` flag). 33 | 34 | The `-v` flag is to map the directory containing your jpeg-xl checkout in your 35 | host (assumed to be at `$HOME/jpeg-xl`) to a directory inside the container at 36 | /jpeg-xl. Since the container is accessing the host folder directly, 37 | changes made on the host will will be seen immediately in the container, 38 | and vice versa. 39 | 40 | On OSX, the path must be one of those shared and whitelisted with Docker. $HOME 41 | (which is a subdirectory of /Users/) is known to work with the factory-default 42 | settings of Docker. 43 | 44 | On OSX, you may ignore the warning that Docker "cannot find name for group ID". 45 | This warning may also appear on some Linux computers. 46 | 47 | On Windows, you can run the following from the jpeg-xl directory obtained from 48 | Gitlab: 49 | 50 | ```bash 51 | docker run -u root:root -it --rm -v %cd%:/jpeg-xl -w /jpeg-xl \ 52 | gcr.io/jpegxl/jpegxl-builder 53 | ``` 54 | 55 | ## Basic building 56 | 57 | Inside the Docker container, you can compile everything and run unit tests. 58 | We need to specify `clang-7` because the default `clang` compiler is 59 | not installed on the image. 60 | 61 | ```bash 62 | CC=clang-7 CXX=clang++-7 ./ci.sh opt 63 | ``` 64 | 65 | This writes binaries to `/jpeg-xl/build/tools` and runs unit tests. 66 | More information on [build modes and testing](building_and_testing.md) is 67 | available. 68 | 69 | If a `build` directory already exists and was configured for a different 70 | compiler, `cmake` will complain. This can be avoided by renaming or removing 71 | the existing `build` directory or setting the `BUILD_DIR` environment variable. 72 | 73 | ## Cross-compiling environments (optional) 74 | 75 | We have installed the required cross-compiling tools in the main Docker image 76 | `jpegxl-builder`. This allows compiling for other architectures, such as arm. 77 | Tests will be emulated under `qemu`. 78 | 79 | The Docker container has several `qemu-*-static` binaries (such as 80 | `qemu-aarch64-static`) that emulate other architectures on x86_64. These 81 | binaries are automatically used when running foreign architecture programs 82 | in the container only if `binfmt` is installed and configured on the *host* 83 | to use binaries from `/usr/bin` . This is the default location on Ubuntu/Debian. 84 | 85 | You need to install both `binfmt-support` and `qemu-user-static` on the host, 86 | since `binfmt-support` configures only `binfmt` signatures of architectures 87 | that are installed. If these are configured elsewhere on other distributions, 88 | you can symlink them to `/usr/bin/qemu-*-static` inside the Docker container. 89 | 90 | To install binfmt support in your Ubuntu host run *outside* the container: 91 | 92 | ```bash 93 | sudo apt install binfmt-support qemu-user-static 94 | ``` 95 | 96 | Then to cross-compile and run unit tests execute the following commands: 97 | 98 | ```bash 99 | export BUILD_TARGET=aarch64-linux-gnu CC=clang-7 CXX=clang++-7 100 | ./ci.sh release 101 | ``` 102 | 103 | The `BUILD_TARGET=aarch64-linux-gnu` environment variable tells the `ci.sh` 104 | script to cross-compile for that target. This also changes the default 105 | `BUILD_DIR` to `build-aarch64` since you never want to mix them with the `build` 106 | of your host. You can also explicitly set a `BUILD_DIR` environment variable 107 | that will be used instead. The list of supported `BUILD_TARGET` values for this 108 | container is: 109 | 110 | * *the empty string* (for native x86_64 support) 111 | * aarch64-linux-gnu 112 | * arm-linux-gnueabihf 113 | * i686-linux-gnu 114 | * x86_64-w64-mingw32 (for Windows builds) 115 | -------------------------------------------------------------------------------- /doc/developing_in_windows_vcpkg.md: -------------------------------------------------------------------------------- 1 | # Developing on Windows with Visual Studio 2019 2 | 3 | These instructions assume an up-to-date Windows 10 (e.g. build 19041.928) with 4 | **Microsoft Visual Studio 2019** (e.g. Version 16.9.0 Preview 4.0) installed. If 5 | unavailable, please use another build environment: 6 | 7 | * [Docker container](developing_in_docker.md) 8 | * [MSYS2 on Windows](developing_in_windows_msys.md) 9 | * [Crossroad on Linux](developing_with_crossroad.md) (cross compilation for Windows) 10 | 11 | ## Minimum build dependencies 12 | 13 | Apart from the dependencies in third_party, some of the tools use external 14 | dependencies that need to be installed in your system first. 15 | 16 | Please install [vcpkg](https://vcpkg.readthedocs.io/en/latest/examples/installing-and-using-packages/) 17 | (tested with version 2019.07.18), and use it to install the following libraries: 18 | 19 | ``` 20 | vcpkg install gtest:x64-windows 21 | vcpkg install giflib:x64-windows 22 | vcpkg install libjpeg-turbo:x64-windows 23 | vcpkg install libpng:x64-windows 24 | vcpkg install zlib:x64-windows 25 | ``` 26 | 27 | ## Building 28 | 29 | From Visual Studio, open the CMakeLists.txt in the JPEG XL root directory. 30 | Right-click the CMakeLists.txt entry in the Folder View of the Solution 31 | Explorer. In the context menu, select CMake Settings. Click on the green plus 32 | to add an x64-Clang configuration and the red minus to remove any non-Clang 33 | configuration (the MSVC compiler is currently not supported). Click on the blue 34 | hyperlink marked "CMakeSettings.json" and an editor will open. Insert the 35 | following text after replacing $VCPKG with the directory where you installed 36 | vcpkg above. 37 | 38 | ``` 39 | { 40 | "configurations": [ 41 | { 42 | "name": "x64-Clang-Release", 43 | "generator": "Ninja", 44 | "configurationType": "MinSizeRel", 45 | "buildRoot": "${projectDir}\\out\\build\\${name}", 46 | "installRoot": "${projectDir}\\out\\install\\${name}", 47 | "cmakeCommandArgs": "-DCMAKE_TOOLCHAIN_FILE=$VCPKG/scripts/buildsystems/vcpkg.cmake", 48 | "buildCommandArgs": "-v", 49 | "ctestCommandArgs": "", 50 | "inheritEnvironments": [ "clang_cl_x64" ], 51 | "variables": [ 52 | { 53 | "name": "VCPKG_TARGET_TRIPLET", 54 | "value": "x64-windows", 55 | "type": "STRING" 56 | }, 57 | { 58 | "name": "JPEGXL_ENABLE_TCMALLOC", 59 | "value": "False", 60 | "type": "BOOL" 61 | }, 62 | { 63 | "name": "BUILD_GMOCK", 64 | "value": "True", 65 | "type": "BOOL" 66 | }, 67 | { 68 | "name": "gtest_force_shared_crt", 69 | "value": "True", 70 | "type": "BOOL" 71 | }, 72 | { 73 | "name": "JPEGXL_ENABLE_FUZZERS", 74 | "value": "False", 75 | "type": "BOOL" 76 | }, 77 | { 78 | "name": "JPEGXL_ENABLE_VIEWERS", 79 | "value": "False", 80 | "type": "BOOL" 81 | } 82 | ] 83 | } 84 | ] 85 | } 86 | ``` 87 | 88 | The project is now ready for use. To build, simply press F7 (or choose 89 | Build All from the Build menu). This writes binaries to 90 | `out/build/x64-Clang-Release/tools`. The main [README.md](../README.md) explains 91 | how to use the encoder/decoder and benchmark binaries. 92 | -------------------------------------------------------------------------------- /doc/developing_with_crossroad.md: -------------------------------------------------------------------------------- 1 | # Cross Compiling for Windows with Crossroad 2 | 3 | [Crossroad](https://pypi.org/project/crossroad/) is a tool to set up cross-compilation environments on GNU/Linux distributions. These instructions assume a Debian/Ubuntu system. However, they can likely be adapted to other Linux environments. Since Ubuntu can be run on Windows through WSL, these instruction may be useful for developing directly on Windows. 4 | 5 | ## Install Crossroad 6 | 7 | Crossroad requires tools included with `python3-docutils` and `mingw-w64`. They may be installed using: 8 | 9 | ```bash 10 | sudo aptitude install python3-docutils mingw-w64 11 | ``` 12 | 13 | The `zstandard` python package is also required, but is not available in the repositories. It may be installed using `pip`. 14 | 15 | ```bash 16 | pip3 install zstandard 17 | ``` 18 | 19 | After the dependencies are installed, crossroad itself maybe installed with `pip`. 20 | 21 | ```bash 22 | pip3 install crossroad 23 | ``` 24 | 25 | If there are errors while running crossroad, it may need to be downloaded and installed directly using `setup.py`. Instructions are on the crossroad homepage. 26 | 27 | ## Update Debian Alternatives 28 | 29 | Since `libjxl` uses C++ features that require posix threads, the symlinks used by the Debian alternative system need to be updated: 30 | 31 | ```bash 32 | sudo update-alternatives --config x86_64-w64-mingw32-g++ 33 | ``` 34 | 35 | Select the option that indicates `posix` usage. Repeat for `gcc` and `i686`: 36 | 37 | ```bash 38 | sudo update-alternatives --config x86_64-w64-mingw32-gcc 39 | sudo update-alternatives --config i686-w64-mingw32-gcc 40 | sudo update-alternatives --config i686-w64-mingw32-g++ 41 | ``` 42 | 43 | ## Create a New Crossroad Project 44 | 45 | Crossroad supports the following platforms: 46 | 47 | ``` 48 | native Native platform (x86_64 GNU/Linux) 49 | android-x86 Generic Android/Bionic on x86 50 | android-mips64 Generic Android/Bionic on MIPS64 51 | android-x86-64 Generic Android/Bionic on x86-64 52 | w64 Windows 64-bit 53 | w32 Windows 32-bit 54 | android-arm64 Generic Android/Bionic on ARM64 55 | android-mips Generic Android/Bionic on MIPS 56 | android-arm Generic Android/Bionic on ARM 57 | ``` 58 | 59 | To begin cross compiling for Windows, a new project needs to be created: 60 | 61 | ```bash 62 | crossroad w64 [project-name] 63 | ``` 64 | 65 | ## Install Dependencies 66 | 67 | Since the `gimp` development package is required to build the GIMP plugin and also includes most of the packages required by `libjxl`, install it first. 68 | 69 | ```bash 70 | crossroad install gimp 71 | ``` 72 | 73 | `gtest` and `brotli` are also required. 74 | 75 | ```bash 76 | crossroad install gtest brotli 77 | ``` 78 | 79 | If any packages are later found to be missing, you may search for them using: 80 | 81 | ```bash 82 | crossroad search [...] 83 | ``` 84 | 85 | ## Build `libjxl` 86 | 87 | Download the source from the libjxl [releases](https://github.com/libjxl/libjxl/releases) page. Alternatively, you may obtain the latest development version with `git`. Run `./deps.sh` to ensure additional third-party dependencies are downloaded. Unfortunately, the script `./ci.sh` does not work with Crossroad, so `cmake` will need to be called directly. 88 | 89 | Create a build directory within the source directory. If you haven't already, start your crossroad project and run `cmake`: 90 | 91 | ```bash 92 | mkdir build 93 | cd build 94 | crossroad w64 libjxl 95 | crossroad cmake -DCMAKE_BUILD_TYPE=Release \ 96 | -DBUILD_TESTING=OFF -DBUILD_SHARED_LIBS=OFF \ 97 | -DJPEGXL_ENABLE_BENCHMARK=OFF -DJPEGXL_ENABLE_MANPAGES=OFF \ 98 | -DJPEGXL_ENABLE_PLUGINS=ON -DJPEGXL_FORCE_SYSTEM_BROTLI=ON \ 99 | -DJPEGXL_FORCE_SYSTEM_GTEST=ON .. 100 | ``` 101 | 102 | Check the output to see if any dependencies were missed and need to be installed. If all went well, you may now run `cmake` to build `libjxl`: 103 | 104 | ```bash 105 | cmake --build . 106 | ``` 107 | 108 | ## Try out the GIMP Plugin 109 | 110 | The plugin is built statically, so there should be no need to install `dll` files. To try out the plugin: 111 | 112 | 1. [Download](https://www.gimp.org/downloads/) and install the stable version of GIMP (currently 2.10.24). 113 | 114 | 2. Create a new folder: `C:\Program Files\GIMP 2\lib\gimp\2.0\plug-ins\file-jxl` 115 | 116 | 3. Copy `build/plugins/gimp/file-jxl.exe` to the new folder. 117 | -------------------------------------------------------------------------------- /doc/jxl.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/man/cjxl.txt: -------------------------------------------------------------------------------- 1 | cjxl(1) 2 | ======= 3 | :doctype: manpage 4 | 5 | Name 6 | ---- 7 | 8 | cjxl - compress images to JPEG XL 9 | 10 | Synopsis 11 | -------- 12 | 13 | *cjxl* ['options'...] 'input' ['output.jxl'] 14 | 15 | Description 16 | ----------- 17 | 18 | `cjxl` compresses an image or animation to the JPEG XL format. It is intended to 19 | spare users the trouble of determining a set of optimal parameters for each 20 | individual image. Instead, for a given target quality, it should provide 21 | consistent visual results across various kinds of images. The defaults have been 22 | chosen to be sensible, so that the following commands should give satisfactory 23 | results in most cases: 24 | 25 | ---- 26 | cjxl input.png output.jxl 27 | cjxl input.jpg output.jxl 28 | cjxl input.gif output.jxl 29 | ---- 30 | 31 | Options 32 | ------- 33 | 34 | -h:: 35 | --help:: 36 | Displays the options that `cjxl` supports. On its own, it will only show 37 | basic options. It can be combined with `-v` or `-v -v` to show increasingly 38 | advanced options as well. 39 | 40 | -v:: 41 | --verbose:: 42 | Increases verbosity. Can be repeated to increase it further, and also 43 | applies to `--help`. 44 | 45 | -d 'distance':: 46 | --distance='distance':: 47 | The preferred way to specify quality. It is specified in multiples of a 48 | just-noticeable difference. That is, `-d 0` is mathematically lossless, 49 | `-d 1` should be visually lossless, and higher distances yield denser and 50 | denser files with lower and lower fidelity. Lossy sources such as JPEG and 51 | GIF files are compressed losslessly by default, and in the case of JPEG 52 | files specifically, the original JPEG can then be reconstructed bit-for-bit. 53 | For lossless sources, `-d 1` is the default. 54 | 55 | -q 'quality':: 56 | --quality='quality':: 57 | Alternative way to indicate the desired quality. 100 is lossless and lower 58 | values yield smaller files. There is no lower bound to this quality 59 | parameter, but positive values should approximately match the quality 60 | setting of libjpeg. 61 | 62 | -e 'effort':: 63 | --effort='effort':: 64 | Controls the amount of effort that goes into producing an ``optimal'' file 65 | in terms of quality/size. That is to say, all other parameters being equal, 66 | a higher effort should yield a file that is at least as dense and possibly 67 | denser, and with at least as high and possibly higher quality. 68 | + 69 | Recognized effort settings, from fastest to slowest, are: 70 | + 71 | - 1 or ``lightning'' 72 | - 2 or ``thunder'' 73 | - 3 or ``falcon'' 74 | - 4 or ``cheetah'' 75 | - 5 or ``hare'' 76 | - 6 or ``wombat'' 77 | - 7 or ``squirrel'' (default) 78 | - 8 or ``kitten'' 79 | - 9 or ``tortoise'' 80 | 81 | Examples 82 | -------- 83 | 84 | ---- 85 | # Compress a PNG file to a high-quality JPEG XL version. 86 | $ cjxl input.png output.jxl 87 | 88 | # Compress it at a slightly lower quality, appropriate for web use. 89 | $ cjxl -d 2 input.png output.jxl 90 | 91 | # Compress it losslessly. These are equivalent. 92 | $ cjxl -d 0 input.png lossless.jxl 93 | $ cjxl -q 100 input.png lossless.jxl 94 | 95 | # Compress a JPEG file losslessly. 96 | $ cjxl input.jpeg lossless-jpeg.jxl 97 | ---- 98 | 99 | See also 100 | -------- 101 | 102 | *djxl*(1) 103 | -------------------------------------------------------------------------------- /doc/man/djxl.txt: -------------------------------------------------------------------------------- 1 | djxl(1) 2 | ======= 3 | :doctype: manpage 4 | 5 | Name 6 | ---- 7 | 8 | djxl - decompress JPEG XL images 9 | 10 | Synopsis 11 | -------- 12 | 13 | *djxl* ['options'...] 'input.jxl' ['output'] 14 | 15 | Description 16 | ----------- 17 | 18 | `djxl` decompresses a JPEG XL image or animation. The output format is determined 19 | by the extension of the output file, which can be `.png`, `.jpg`, `.ppm`, `.pfm`. 20 | If the JPEG XL input file contains an animation, multiple output files will be 21 | produced, with names of the form "'output'-*framenumber*.ext". 22 | 23 | 24 | Options 25 | ------- 26 | 27 | -h:: 28 | --help:: 29 | Displays the options that `djxl` supports. 30 | 31 | -j:: 32 | --pixels_to_jpeg:: 33 | By default, if the input JPEG XL contains a recompressed JPEG file, 34 | djxl reconstructs the exact original JPEG file if the output file has the 35 | `.jpg` (or `.jpeg`) filename extension. 36 | This flag causes the decoder to instead decode the image to pixels and 37 | encode a new (lossy) JPEG in this case. 38 | 39 | 40 | -q 'quality':: 41 | --jpeg_quality='quality':: 42 | When decoding to `.jpg`, use this output quality. This option implicitly 43 | enables the --pixels_to_jpeg option. 44 | 45 | 46 | Examples 47 | -------- 48 | 49 | ---- 50 | # Decompress a JPEG XL file to PNG 51 | $ djxl input.jxl output.png 52 | 53 | # Reconstruct a losslessly-recompressed JPEG file 54 | $ djxl lossless-jpeg.jxl reconstructed.jpeg 55 | ---- 56 | 57 | 58 | See also 59 | -------- 60 | 61 | *cjxl*(1) 62 | -------------------------------------------------------------------------------- /doc/software_support.md: -------------------------------------------------------------------------------- 1 | # JPEG XL software support 2 | 3 | This document attempts to keep track of software that is using libjxl to support JPEG XL. 4 | This list serves several purposes: 5 | 6 | - thank/acknowledge other projects for integrating jxl support 7 | - point end-users to software that can read/write jxl 8 | - keep track of the adoption status of jxl 9 | - in case of a (security) bug in libjxl, it's easier to see who might be affected and check if they are updated (in case they use static linking) 10 | 11 | Please add missing software to this list. 12 | 13 | ## Browsers 14 | 15 | - Chromium: behind a flag since version 91, [tracking bug](https://bugs.chromium.org/p/chromium/issues/detail?id=1178058) 16 | - Firefox: behind a flag since version 90, [tracking bug](https://bugzilla.mozilla.org/show_bug.cgi?id=1539075) 17 | - Safari: not supported, [tracking bug](https://bugs.webkit.org/show_bug.cgi?id=208235) 18 | - Edge: behind a flag since version 91, start with `.\msedge.exe --enable-features=JXL` 19 | - Opera: behind a flag since version 77. 20 | - For all browsers and to track browsers progress see [Can I Use](https://caniuse.com/jpegxl). 21 | 22 | ## Image libraries 23 | 24 | - [ImageMagick](https://imagemagick.org/): supported since 7.0.10-54 25 | - [libvips](https://libvips.github.io/libvips/): supported since 8.11 26 | - [Imlib2](https://github.com/alistair7/imlib2-jxl) 27 | - [FFmpeg](https://github.com/FFmpeg/FFmpeg/search?q=jpeg-xl&type=commits) 28 | - [GDAL](https://gdal.org/drivers/raster/jpegxl.html): supported since 3.4.0 as a TIFF codec, and 3.6.0 as standalone format 29 | 30 | ## OS-level support / UI frameworks / file browser plugins 31 | 32 | - Qt / KDE: [plugin available](https://github.com/novomesk/qt-jpegxl-image-plugin) 33 | - GDK-pixbuf: plugin available in libjxl repo 34 | - [gThumb](https://ubuntuhandbook.org/index.php/2021/04/gthumb-3-11-3-adds-jpeg-xl-support/) 35 | - [MacOS viewer/QuickLook plugin](https://github.com/yllan/JXLook) 36 | - [Windows Imaging Component](https://github.com/mirillis/jpegxl-wic) 37 | - [Windows thumbnail handler](https://github.com/saschanaz/jxl-winthumb) 38 | - [OpenMandriva Lx (since 4.3 RC)](https://www.openmandriva.org/en/news/article/openmandriva-lx-4-3-rc-available-for-testing) 39 | - [KaOS (since 2021.06)](https://news.itsfoss.com/kaos-2021-06-release/) 40 | - [EFL (since 1.27, no external plugin needed)](https://www.enlightenment.org) 41 | 42 | ## Image editors 43 | 44 | - [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 45 | - [Krita](https://invent.kde.org/graphics/krita/-/commit/13e5d2e5b9f0eac5c8064b7767f0b62264a0797b) 46 | - Photoshop: no plugin available yet, no official support yet 47 | 48 | ## Image viewers 49 | 50 | - [XnView](https://www.xnview.com/en/) 51 | - [ImageGlass](https://imageglass.org/) 52 | - [IrfanView](https://www.irfanview.com/); supported since 4.59 - requires a [plugin](https://www.irfanview.com/plugins.htm) to be downloaded and enabled. 53 | - [Tachiyomi](https://github.com/tachiyomiorg/tachiyomi/releases/tag/v0.12.1) 54 | - Any viewer based on Qt, KDE, GDK-pixbuf, EFL, ImageMagick, libvips or imlib2 (see above) 55 | - Qt viewers: gwenview, digiKam, KolourPaint, KPhotoAlbum, LXImage-Qt, qimgv, qView, nomacs, VookiImageViewer, PhotoQt 56 | - GTK viewers: Eye of Gnome (eog), gThumb, Geeqie 57 | - EFL viewers: entice, ephoto 58 | - [Swayimg](https://github.com/artemsen/swayimg) 59 | 60 | ## Online tools 61 | 62 | - [Squoosh](https://squoosh.app/) 63 | - [Cloudinary](https://cloudinary.com/blog/cloudinary_supports_jpeg_xl) 64 | - [MConverter](https://mconverter.eu/) 65 | - [jpegxl.io](https://jpegxl.io/) 66 | -------------------------------------------------------------------------------- /doc/sphinx/api.rst: -------------------------------------------------------------------------------- 1 | API reference 2 | ============= 3 | 4 | ``libjxl`` exposes a C API for encoding and decoding JPEG XL files with some 5 | C++ header-only helpers for C++ users. 6 | 7 | .. toctree:: 8 | :caption: API REFERENCE 9 | :maxdepth: 2 10 | 11 | api_decoder 12 | api_encoder 13 | api_common 14 | api_butteraugli 15 | api_threads 16 | -------------------------------------------------------------------------------- /doc/sphinx/api_butteraugli.rst: -------------------------------------------------------------------------------- 1 | Butteraugli API - ``jxl/butteraugli.h`` 2 | ======================================= 3 | 4 | .. doxygengroup:: libjxl_butteraugli 5 | :members: 6 | :private-members: 7 | -------------------------------------------------------------------------------- /doc/sphinx/api_common.rst: -------------------------------------------------------------------------------- 1 | Common API concepts 2 | =================== 3 | 4 | .. doxygengroup:: libjxl_common 5 | :members: 6 | :private-members: 7 | -------------------------------------------------------------------------------- /doc/sphinx/api_decoder.rst: -------------------------------------------------------------------------------- 1 | Decoder API - ``jxl/decode.h`` 2 | ============================== 3 | 4 | .. doxygengroup:: libjxl_decoder 5 | :members: 6 | :private-members: 7 | -------------------------------------------------------------------------------- /doc/sphinx/api_encoder.rst: -------------------------------------------------------------------------------- 1 | Encoder API - ``jxl/encode.h`` 2 | ============================== 3 | 4 | .. doxygengroup:: libjxl_encoder 5 | :members: 6 | :private-members: 7 | -------------------------------------------------------------------------------- /doc/sphinx/api_threads.rst: -------------------------------------------------------------------------------- 1 | Multi-threaded Encoder/Decoder 2 | ============================== 3 | 4 | .. doxygengroup:: libjxl_threads 5 | :members: 6 | :private-members: 7 | -------------------------------------------------------------------------------- /doc/sphinx/conf.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) the JPEG XL Project Authors. 2 | # 3 | # Use of this source code is governed by a BSD-style 4 | # license that can be found in the LICENSE file or at 5 | # https://developers.google.com/open-source/licenses/bsd 6 | 7 | # Configuration file for the Sphinx documentation builder. 8 | # 9 | # See https://www.sphinx-doc.org/en/master/usage/configuration.html 10 | 11 | import os 12 | import re 13 | import subprocess 14 | 15 | def GetVersion(): 16 | """Function to get the version of the current code.""" 17 | with open(os.path.join( 18 | os.path.dirname(__file__), '../../lib/CMakeLists.txt'), 'r') as f: 19 | cmakevars = {} 20 | for line in f: 21 | m = re.match(r'set\(JPEGXL_([A-Z]+)_VERSION ([^\)]+)\)', line) 22 | if m: 23 | cmakevars[m.group(1)] = m.group(2) 24 | return '%s.%s.%s' % (cmakevars['MAJOR'], cmakevars['MINOR'], cmakevars['PATCH']) 25 | 26 | def ConfigProject(app, config): 27 | # Configure the doxygen xml directory as the "xml" directory next to the 28 | # sphinx output directory. Doxygen generates by default the xml files in a 29 | # "xml" sub-directory of the OUTPUT_DIRECTORY. 30 | build_dir = os.path.dirname(app.outdir) 31 | xml_dir = os.path.join(build_dir, 'xml') 32 | config.breathe_projects['libjxl'] = xml_dir 33 | 34 | # Read the docs build environment doesn't run our cmake script so instead we 35 | # need to run doxygen manually here. 36 | if os.environ.get('READTHEDOCS', None) != 'True': 37 | return 38 | root_dir = os.path.realpath(os.path.join(app.srcdir, '../../')) 39 | doxyfile = os.path.join(build_dir, 'Doxyfile-rtd.doc') 40 | with open(doxyfile, 'w') as f: 41 | f.write(f""" 42 | FILE_PATTERNS = *.c *.h 43 | GENERATE_HTML = NO 44 | GENERATE_LATEX = NO 45 | GENERATE_XML = YES 46 | INPUT = lib/include doc/api.txt 47 | OUTPUT_DIRECTORY = {build_dir} 48 | PROJECT_NAME = LIBJXL 49 | QUIET = YES 50 | RECURSIVE = YES 51 | STRIP_FROM_PATH = lib/include 52 | WARN_AS_ERROR = YES 53 | """) 54 | subprocess.check_call(['doxygen', doxyfile], cwd=root_dir) 55 | 56 | def setup(app): 57 | # Generate doxygen XML on init when running from Read the docs. 58 | app.connect("config-inited", ConfigProject) 59 | 60 | ### Project information 61 | 62 | project = 'libjxl' 63 | project_copyright = 'JPEG XL Project Authors' 64 | author = 'JPEG XL Project Authors' 65 | version = GetVersion() 66 | 67 | ### General configuration 68 | 69 | extensions = [ 70 | # For integration with doxygen documentation. 71 | 'breathe', 72 | # sphinx readthedocs theme. 73 | 'sphinx_rtd_theme', 74 | # Do we use it? 75 | 'sphinx.ext.graphviz', 76 | ] 77 | 78 | breathe_default_project = 'libjxl' 79 | breathe_projects = {} 80 | 81 | 82 | # All the API is in C, except those files that end with cxx.h. 83 | breathe_domain_by_extension = {'h': 'cpp'} 84 | breathe_domain_by_file_pattern = { 85 | '*cxx.h': 'cpp', 86 | } 87 | breathe_implementation_filename_extensions = ['.cc'] 88 | 89 | # These are defined at build time by cmake. 90 | c_id_attributes = [ 91 | 'JXL_EXPORT', 92 | 'JXL_DEPRECATED', 93 | 'JXL_THREADS_EXPORT', 94 | ] 95 | cpp_id_attributes = c_id_attributes 96 | 97 | 98 | breathe_projects_source = { 99 | 'libjxl' : ('../../', [ 100 | 'doc/api.txt', 101 | 'lib/include/jxl', 102 | ]) 103 | } 104 | 105 | # Recognized suffixes. 106 | source_suffix = ['.rst', '.md'] 107 | 108 | ### Options for HTML output 109 | 110 | # Use the readthedocs.io theme when generating the HTML output. 111 | html_theme = 'sphinx_rtd_theme' 112 | -------------------------------------------------------------------------------- /doc/sphinx/index.rst: -------------------------------------------------------------------------------- 1 | .. libjxl sphinx documentation entrypoint 2 | 3 | JPEG XL image format reference implementation 4 | ============================================= 5 | 6 | .. toctree:: 7 | :maxdepth: 3 8 | :caption: Contents: 9 | 10 | api 11 | 12 | 13 | Indices and tables 14 | ================== 15 | 16 | * :ref:`genindex` 17 | * :ref:`search` 18 | 19 | -------------------------------------------------------------------------------- /doc/sphinx/requirements.txt: -------------------------------------------------------------------------------- 1 | breathe 2 | sphinx 3 | sphinx-rtd-theme 4 | -------------------------------------------------------------------------------- /doc/tables/adobe.md: -------------------------------------------------------------------------------- 1 | #### Table M.8 – "Adobe" marker template 2 | 3 | ``` 4 | 0xEE, 0x00, 0x0E, 0x41, 0x64, 0x6F, 0x62, 0x65, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x01 5 | ``` 6 | 7 | -------------------------------------------------------------------------------- /doc/tables/all_tables.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libjxl/libjxl-tiny/8eae18172059d54f5c734ca814f23b96eebff859/doc/tables/all_tables.pdf -------------------------------------------------------------------------------- /doc/tables/all_tables.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright (c) the JPEG XL Project Authors. 3 | # 4 | # Use of this source code is governed by a BSD-style 5 | # license that can be found in the LICENSE file or at 6 | # https://developers.google.com/open-source/licenses/bsd 7 | 8 | cat dct_gen.md \ 9 | is_zero_base.md num_nonzeros_base.md brn_proto.md app0.md icc.md ducky.md \ 10 | adobe.md stock_counts.md stock_values.md symbol_order.md stock_quant.md \ 11 | quant.md freq_context.md num_nonzero_context.md nonzero_buckets.md \ 12 | context_modes.md > all_tables.md 13 | -------------------------------------------------------------------------------- /doc/tables/app0.md: -------------------------------------------------------------------------------- 1 | #### Table M.4 – APP0 template 2 | 3 | ``` 4 | 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00 5 | ``` 6 | 7 | -------------------------------------------------------------------------------- /doc/tables/brn_proto.md: -------------------------------------------------------------------------------- 1 | #### Table M.3 – Protocol Buffer descriptor of top-level structure of losslessly compressed JPEG stream 2 | 3 | ```protobuf 4 | message Header { 5 | optional uint64 width = 1; 6 | optional uint64 height = 2; 7 | required uint64 version_and_component_count_code = 3; 8 | optional uint64 subsampling_code = 4; 9 | } 10 | 11 | message Jpeg { 12 | required bytes signature = 1; 13 | required Header header = 2; 14 | optional bytes meta_data = 3; 15 | optional bytes jpeg1_internals = 4; 16 | optional bytes quant_data = 5; 17 | optional bytes histogram_data = 6; 18 | optional bytes dc_data = 7; 19 | optional bytes ac_data = 8; 20 | optional bytes original_jpg = 9; 21 | } 22 | ``` 23 | 24 | -------------------------------------------------------------------------------- /doc/tables/context_modes.md: -------------------------------------------------------------------------------- 1 | #### Table M.29 – context_modes table 2 | 3 | ``` 4 | 0, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 5 | 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 6 | 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0 7 | ``` 8 | 9 | ``` 10 | 0, 1, 1, 1, 1, 0, 0, 0, 2, 3, 1, 1, 1, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 11 | 0, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 13 | ``` 14 | -------------------------------------------------------------------------------- /doc/tables/ducky.md: -------------------------------------------------------------------------------- 1 | #### Table M.7 – "Ducky" marker template 2 | 3 | ``` 4 | 0xEC, 0x00, 0x11, 0x44, 0x75, 0x63, 0x6B, 0x79, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00 5 | ``` 6 | 7 | -------------------------------------------------------------------------------- /doc/tables/freq_context.md: -------------------------------------------------------------------------------- 1 | #### Table M.15 – freq_context 2 | 3 | `scheme == 0`: 4 | ``` 5 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 8 | ``` 9 | 10 | `scheme == 1`: 11 | ``` 12 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 14 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 15 | ``` 16 | 17 | `scheme == 2`: 18 | ``` 19 | 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 20 | 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 21 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1 22 | ``` 23 | 24 | `scheme == 3`: 25 | ``` 26 | 0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 27 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 28 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2 29 | ``` 30 | 31 | `scheme == 4`: 32 | ``` 33 | 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, 34 | 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 35 | 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 36 | 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 37 | ``` 38 | 39 | `scheme == 5`: 40 | ``` 41 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16, 42 | 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 24, 24, 43 | 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 44 | 29, 29, 30, 30, 30, 30, 31, 31, 31, 31 45 | ``` 46 | 47 | `scheme == 6`: 48 | ``` 49 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 50 | 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 51 | 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 52 | 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 53 | ``` 54 | 55 | -------------------------------------------------------------------------------- /doc/tables/is_zero_base.md: -------------------------------------------------------------------------------- 1 | #### Table M.1 – is_zero_base table 2 | 3 | ``` 4 | 228, 216, 216, 195, 192, 189, 182, 184, 179, 176, 171, 168, 166, 159, 5 | 156, 151, 151, 150, 150, 146, 144, 138, 138, 137, 135, 131, 127, 126, 6 | 124, 123, 124, 123, 122, 121, 118, 117, 114, 115, 116, 116, 115, 115, 7 | 114, 111, 111, 111, 112, 111, 110, 110, 110, 111, 111, 114, 110, 111, 8 | 112, 113, 116, 120, 126, 131, 147, 160 9 | ``` 10 | -------------------------------------------------------------------------------- /doc/tables/markdown-pdf.css: -------------------------------------------------------------------------------- 1 | /* 2 | settings.json: 3 | "markdown-pdf.styles": ["markdown-pdf.css",], 4 | "markdown-pdf.format": "Letter", 5 | "markdown-pdf.margin.top": "1in", 6 | "markdown-pdf.margin.bottom": "1in", 7 | "markdown-pdf.margin.left": "1in", 8 | "markdown-pdf.margin.right": "1in", 9 | "markdown-pdf.stylesRelativePathFile" : true, 10 | "markdown-pdf.displayHeaderFooter": false, 11 | */ 12 | 13 | body { 14 | font-family: "Times"; 15 | font-size: 10pt; 16 | padding: 0; 17 | } 18 | 19 | h4 { 20 | font-family: "Times New Roman"; 21 | font-size: 10pt; 22 | font-weight: bold; 23 | } 24 | 25 | code { 26 | font-family: Consolas, "Source Code Pro"; 27 | font-size: 10pt; 28 | } 29 | 30 | pre.hljs code > div { 31 | padding: 0px; 32 | } 33 | 34 | :not(pre):not(.hljs) > code { 35 | color: #4d4d4c; 36 | } 37 | -------------------------------------------------------------------------------- /doc/tables/nonzero_buckets.md: -------------------------------------------------------------------------------- 1 | #### Table M.17 – nonzero_buckets 2 | 3 | ``` 4 | 0, 1, 2, 3, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 5 | 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 6 | 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 7 | 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 8 | ``` 9 | 10 | -------------------------------------------------------------------------------- /doc/tables/num_nonzero_context.md: -------------------------------------------------------------------------------- 1 | #### Table M.16 – num_nonzero_context 2 | 3 | `scheme == 0`: 4 | ``` 5 | 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, 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, 7 8 | ``` 9 | 10 | `scheme == 1`: 11 | ``` 12 | 0, 2, 2, 4, 4, 4, 6, 6, 6, 6, 8, 8, 8, 8, 8, 8, 10, 10, 13 | 10, 10, 10, 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 14 | 12, 12, 12, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15 | 14, 14, 14, 14, 14, 14, 14, 14, 14, 14 16 | ``` 17 | 18 | `scheme == 2`: 19 | ``` 20 | 0, 4, 4, 8, 8, 8, 12, 12, 12, 12, 16, 16, 16, 16, 16, 16, 20, 20, 21 | 20, 20, 20, 20, 20, 20, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 22 | 24, 24, 24, 24, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 23 | 28, 28, 28, 28, 28, 28, 28, 28, 28, 28 24 | ``` 25 | 26 | `scheme == 3`: 27 | ``` 28 | 0, 8, 8, 16, 16, 16, 24, 24, 24, 24, 32, 32, 32, 32, 32, 32, 40, 40, 29 | 40, 40, 40, 40, 40, 40, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 30 | 48, 48, 48, 48, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 31 | 55, 55, 55, 55, 55, 55, 55, 55, 55, 55 32 | ``` 33 | 34 | `scheme == 4`: 35 | ``` 36 | 0, 16, 16, 32, 32, 32, 48, 48, 48, 48, 64, 64, 64, 64, 37 | 64, 64, 80, 80, 80, 80, 80, 80, 80, 80, 95, 95, 95, 95, 38 | 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 109, 109, 39 | 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 40 | 109, 109, 109, 109, 109, 109, 109, 109 41 | ``` 42 | 43 | `scheme == 5`: 44 | ``` 45 | 0, 32, 32, 64, 64, 64, 96, 96, 96, 96, 127, 127, 127, 127, 46 | 127, 127, 157, 157, 157, 157, 157, 157, 157, 157, 185, 185, 185, 185, 47 | 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 211, 211, 48 | 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 49 | 211, 211, 211, 211, 211, 211, 211, 211 50 | ``` 51 | 52 | `scheme == 6`: 53 | ``` 54 | 0, 64, 64, 127, 127, 127, 188, 188, 188, 188, 246, 246, 246, 246, 55 | 246, 246, 300, 300, 300, 300, 300, 300, 300, 300, 348, 348, 348, 348, 56 | 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 388, 388, 57 | 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 58 | 388, 388, 388, 388, 388, 388, 388, 388 59 | ``` 60 | 61 | -------------------------------------------------------------------------------- /doc/tables/quant.md: -------------------------------------------------------------------------------- 1 | #### Table M.13 – template quant tables 2 | 3 | `is_luma == true`: 4 | ``` 5 | 16, 11, 10, 16, 24, 40, 51, 61, 12, 12, 14, 19, 26, 58, 60, 6 | 55, 14, 13, 16, 24, 40, 57, 69, 56, 14, 17, 22, 29, 51, 87, 7 | 80, 62, 18, 22, 37, 56, 68, 109, 103, 77, 24, 35, 55, 64, 81, 8 | 104, 113, 92, 49, 64, 78, 87, 103, 121, 120, 101, 72, 92, 95, 98, 9 | 112, 100, 103, 99 10 | ``` 11 | 12 | `is_luma == false`: 13 | ``` 14 | 17, 18, 24, 47, 99, 99, 99, 99, 18, 21, 26, 66, 99, 99, 99, 99, 24, 26, 15 | 56, 99, 99, 99, 99, 99, 47, 66, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 16 | 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 17 | 99, 99, 99, 99, 99, 99, 99, 99, 99, 99 18 | ``` 19 | 20 | -------------------------------------------------------------------------------- /doc/tables/stock_counts.md: -------------------------------------------------------------------------------- 1 | #### Table M.9 – stock counts arrays 2 | 3 | `is_ac == 0`, `stock_index == 0`: 4 | ``` 5 | 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0 6 | ``` 7 | 8 | `is_ac == 0`, `stock_index == 1`: 9 | ``` 10 | 0, 0, 1, 5, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0 11 | ``` 12 | 13 | `is_ac == 1`, `stock_index == 0`: 14 | ``` 15 | 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 126 16 | ``` 17 | 18 | `is_ac == 1`, `stock_index == 1`: 19 | ``` 20 | 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 120 21 | ``` 22 | 23 | -------------------------------------------------------------------------------- /doc/tables/stock_quant.md: -------------------------------------------------------------------------------- 1 | #### Table M.12 – stock quant tables 2 | 3 | `is_luma == true`, `stock_index == 0`: 4 | ``` 5 | 3, 2, 2, 3, 5, 8, 10, 12, 2, 2, 3, 4, 5, 12, 12, 11, 3, 3, 6 | 3, 5, 8, 11, 14, 11, 3, 3, 4, 6, 10, 17, 16, 12, 4, 4, 7, 11, 7 | 14, 22, 21, 15, 5, 7, 11, 13, 16, 21, 23, 18, 10, 13, 16, 17, 21, 24, 8 | 24, 20, 14, 18, 19, 20, 22, 20, 21, 20 9 | ``` 10 | 11 | `is_luma == true`, `stock_index == 1`: 12 | ``` 13 | 8, 6, 5, 8, 12, 20, 26, 31, 6, 6, 7, 10, 13, 29, 30, 28, 7, 7, 14 | 8, 12, 20, 29, 35, 28, 7, 9, 11, 15, 26, 44, 40, 31, 9, 11, 19, 28, 15 | 34, 55, 52, 39, 12, 18, 28, 32, 41, 52, 57, 46, 25, 32, 39, 44, 52, 61, 16 | 60, 51, 36, 46, 48, 49, 56, 50, 52, 50 17 | ``` 18 | 19 | `is_luma == true`, `stock_index == 2`: 20 | ``` 21 | 6, 4, 4, 6, 10, 16, 20, 24, 5, 5, 6, 8, 10, 23, 24, 22, 6, 5, 22 | 6, 10, 16, 23, 28, 22, 6, 7, 9, 12, 20, 35, 32, 25, 7, 9, 15, 22, 23 | 27, 44, 41, 31, 10, 14, 22, 26, 32, 42, 45, 37, 20, 26, 31, 35, 41, 48, 24 | 48, 40, 29, 37, 38, 39, 45, 40, 41, 40 25 | ``` 26 | 27 | `is_luma == true`, `stock_index == 3`: 28 | ``` 29 | 5, 3, 3, 5, 7, 12, 15, 18, 4, 4, 4, 6, 8, 17, 18, 17, 4, 4, 30 | 5, 7, 12, 17, 21, 17, 4, 5, 7, 9, 15, 26, 24, 19, 5, 7, 11, 17, 31 | 20, 33, 31, 23, 7, 11, 17, 19, 24, 31, 34, 28, 15, 19, 23, 26, 31, 36, 32 | 36, 30, 22, 28, 29, 29, 34, 30, 31, 30 33 | ``` 34 | 35 | `is_luma == true`, `stock_index == 4`: 36 | ``` 37 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 38 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 39 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 40 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 41 | ``` 42 | 43 | `is_luma == true`, `stock_index == 5`: 44 | ``` 45 | 2, 1, 1, 2, 2, 4, 5, 6, 1, 1, 1, 2, 3, 6, 6, 6, 1, 1, 46 | 2, 2, 4, 6, 7, 6, 1, 2, 2, 3, 5, 9, 8, 6, 2, 2, 4, 6, 47 | 7, 11, 10, 8, 2, 4, 6, 6, 8, 10, 11, 9, 5, 6, 8, 9, 10, 12, 48 | 12, 10, 7, 9, 10, 10, 11, 10, 10, 10 49 | ``` 50 | 51 | `is_luma == true`, `stock_index == 6`: 52 | ``` 53 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 54 | 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 55 | 1, 2, 2, 3, 1, 1, 1, 1, 2, 2, 3, 3, 1, 1, 1, 2, 2, 3, 56 | 3, 3, 1, 1, 2, 2, 3, 3, 3, 3 57 | ``` 58 | 59 | `is_luma == true`, `stock_index == 7`: 60 | ``` 61 | 10, 7, 6, 10, 14, 24, 31, 37, 7, 7, 8, 11, 16, 35, 36, 33, 8, 8, 62 | 10, 14, 24, 34, 41, 34, 8, 10, 13, 17, 31, 52, 48, 37, 11, 13, 22, 34, 63 | 41, 65, 62, 46, 14, 21, 33, 38, 49, 62, 68, 55, 29, 38, 47, 52, 62, 73, 64 | 72, 61, 43, 55, 57, 59, 67, 60, 62, 59 65 | ``` 66 | 67 | `is_luma == false`, `stock_index == 0`: 68 | ``` 69 | 9, 9, 9, 12, 11, 12, 24, 13, 13, 24, 50, 33, 28, 33, 50, 50, 50, 50, 70 | 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 71 | 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 72 | 50, 50, 50, 50, 50, 50, 50, 50, 50, 50 73 | ``` 74 | 75 | `is_luma == false`, `stock_index == 1`: 76 | ``` 77 | 3, 4, 5, 9, 20, 20, 20, 20, 4, 4, 5, 13, 20, 20, 20, 20, 5, 5, 78 | 11, 20, 20, 20, 20, 20, 9, 13, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 79 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 80 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 81 | ``` 82 | 83 | `is_luma == false`, `stock_index == 2`: 84 | ``` 85 | 9, 9, 12, 24, 50, 50, 50, 50, 9, 11, 13, 33, 50, 50, 50, 50, 12, 13, 86 | 28, 50, 50, 50, 50, 50, 24, 33, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 87 | 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 88 | 50, 50, 50, 50, 50, 50, 50, 50, 50, 50 89 | ``` 90 | 91 | `is_luma == false`, `stock_index == 3`: 92 | ``` 93 | 5, 5, 7, 14, 30, 30, 30, 30, 5, 6, 8, 20, 30, 30, 30, 30, 7, 8, 94 | 17, 30, 30, 30, 30, 30, 14, 20, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 95 | 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 96 | 30, 30, 30, 30, 30, 30, 30, 30, 30, 30 97 | ``` 98 | 99 | `is_luma == false`, `stock_index == 4`: 100 | ``` 101 | 7, 7, 10, 19, 40, 40, 40, 40, 7, 8, 10, 26, 40, 40, 40, 40, 10, 10, 102 | 22, 40, 40, 40, 40, 40, 19, 26, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 103 | 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 104 | 40, 40, 40, 40, 40, 40, 40, 40, 40, 40 105 | ``` 106 | 107 | `is_luma == false`, `stock_index == 5`: 108 | ``` 109 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 110 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 111 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 112 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 113 | ``` 114 | 115 | `is_luma == false`, `stock_index == 6`: 116 | ``` 117 | 2, 2, 2, 5, 10, 10, 10, 10, 2, 2, 3, 7, 10, 10, 10, 10, 2, 3, 118 | 6, 10, 10, 10, 10, 10, 5, 7, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 119 | 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 120 | 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 121 | ``` 122 | 123 | `is_luma == false`, `stock_index == 7`: 124 | ``` 125 | 10, 11, 14, 28, 59, 59, 59, 59, 11, 13, 16, 40, 59, 59, 59, 59, 14, 16, 126 | 34, 59, 59, 59, 59, 59, 28, 40, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 127 | 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 128 | 59, 59, 59, 59, 59, 59, 59, 59, 59, 59 129 | ``` 130 | 131 | -------------------------------------------------------------------------------- /doc/tables/stock_values.md: -------------------------------------------------------------------------------- 1 | #### Table M.10 – stock values arrays 2 | 3 | `is_ac == 0`, `stock_index == 0`: 4 | ``` 5 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 256 6 | ``` 7 | 8 | `is_ac == 0`, `stock_index == 1`: 9 | ``` 10 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 256 11 | ``` 12 | 13 | `is_ac == 1`, `stock_index == 0`: 14 | ``` 15 | 1, 2, 3, 0, 4, 17, 5, 18, 33, 49, 65, 6, 19, 81, 16 | 97, 7, 34, 113, 20, 50, 129, 145, 161, 8, 35, 66, 177, 193, 17 | 21, 82, 209, 240, 36, 51, 98, 114, 130, 9, 10, 22, 23, 24, 18 | 25, 26, 37, 38, 39, 40, 41, 42, 52, 53, 54, 55, 56, 57, 19 | 58, 67, 68, 69, 70, 71, 72, 73, 74, 83, 84, 85, 86, 87, 20 | 88, 89, 90, 99, 100, 101, 102, 103, 104, 105, 106, 115, 116, 117, 21 | 118, 119, 120, 121, 122, 131, 132, 133, 134, 135, 136, 137, 138, 146, 22 | 147, 148, 149, 150, 151, 152, 153, 154, 162, 163, 164, 165, 166, 167, 23 | 168, 169, 170, 178, 179, 180, 181, 182, 183, 184, 185, 186, 194, 195, 24 | 196, 197, 198, 199, 200, 201, 202, 210, 211, 212, 213, 214, 215, 216, 25 | 217, 218, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 241, 242, 26 | 243, 244, 245, 246, 247, 248, 249, 250, 256 27 | ``` 28 | 29 | `is_ac == 1`, `stock_index == 1`: 30 | ``` 31 | 0, 1, 2, 3, 17, 4, 5, 33, 49, 6, 18, 65, 81, 7, 32 | 97, 113, 19, 34, 50, 129, 8, 20, 66, 145, 161, 177, 193, 9, 33 | 35, 51, 82, 240, 21, 98, 114, 209, 10, 22, 36, 52, 225, 37, 34 | 241, 23, 24, 25, 26, 38, 39, 40, 41, 42, 53, 54, 55, 56, 35 | 57, 58, 67, 68, 69, 70, 71, 72, 73, 74, 83, 84, 85, 86, 36 | 87, 88, 89, 90, 99, 100, 101, 102, 103, 104, 105, 106, 115, 116, 37 | 117, 118, 119, 120, 121, 122, 130, 131, 132, 133, 134, 135, 136, 137, 38 | 138, 146, 147, 148, 149, 150, 151, 152, 153, 154, 162, 163, 164, 165, 39 | 166, 167, 168, 169, 170, 178, 179, 180, 181, 182, 183, 184, 185, 186, 40 | 194, 195, 196, 197, 198, 199, 200, 201, 202, 210, 211, 212, 213, 214, 41 | 215, 216, 217, 218, 226, 227, 228, 229, 230, 231, 232, 233, 234, 242, 42 | 243, 244, 245, 246, 247, 248, 249, 250, 256 43 | ``` 44 | 45 | -------------------------------------------------------------------------------- /doc/tables/symbol_order.md: -------------------------------------------------------------------------------- 1 | #### Table M.11 – predefined symbol order 2 | 3 | `is_ac == 0`: 4 | ``` 5 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 6 | ``` 7 | 8 | `is_ac == 1`: 9 | ``` 10 | 1, 0, 2, 3, 17, 4, 5, 33, 18, 49, 65, 6, 81, 19, 11 | 97, 7, 34, 113, 50, 129, 20, 145, 161, 8, 35, 66, 177, 193, 12 | 21, 82, 209, 240, 36, 51, 98, 114, 9, 130, 10, 22, 52, 225, 13 | 23, 37, 241, 24, 25, 26, 38, 39, 40, 41, 42, 53, 54, 55, 14 | 56, 57, 58, 67, 68, 69, 70, 71, 72, 73, 74, 83, 84, 85, 15 | 86, 87, 88, 89, 90, 99, 100, 101, 102, 103, 104, 105, 106, 115, 16 | 116, 117, 118, 119, 120, 121, 122, 131, 132, 133, 134, 135, 136, 137, 17 | 138, 146, 147, 148, 149, 150, 151, 152, 153, 154, 162, 163, 164, 165, 18 | 166, 167, 168, 169, 170, 178, 179, 180, 181, 182, 183, 184, 185, 186, 19 | 194, 195, 196, 197, 198, 199, 200, 201, 202, 210, 211, 212, 213, 214, 20 | 215, 216, 217, 218, 226, 227, 228, 229, 230, 231, 232, 233, 234, 242, 21 | 243, 244, 245, 246, 247, 248, 249, 250, 16, 32, 48, 64, 80, 96, 22 | 112, 128, 144, 160, 176, 192, 208, 11, 12, 13, 14, 15, 27, 28, 23 | 29, 30, 31, 43, 44, 45, 46, 47, 59, 60, 61, 62, 63, 75, 24 | 76, 77, 78, 79, 91, 92, 93, 94, 95, 107, 108, 109, 110, 111, 25 | 123, 124, 125, 126, 127, 139, 140, 141, 142, 143, 155, 156, 157, 158, 26 | 159, 171, 172, 173, 174, 175, 187, 188, 189, 190, 191, 203, 204, 205, 27 | 206, 207, 219, 220, 221, 222, 223, 224, 235, 236, 237, 238, 239, 251, 28 | 252, 253, 254, 255 29 | ``` 30 | 31 | -------------------------------------------------------------------------------- /docker/Dockerfile.jpegxl-builder: -------------------------------------------------------------------------------- 1 | # Copyright (c) the JPEG XL Project Authors. All rights reserved. 2 | # 3 | # Use of this source code is governed by a BSD-style 4 | # license that can be found in the LICENSE file. 5 | 6 | # Build an Ubuntu-based docker image with the installed software needed to 7 | # develop and test JPEG XL. 8 | 9 | FROM ubuntu:bionic 10 | 11 | # Set a prompt for when using it locally. 12 | ENV PS1="\[\033[01;33m\]\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ " 13 | 14 | COPY scripts/99_norecommends /etc/apt/apt.conf.d/99_norecommends 15 | 16 | COPY scripts /jpegxl_scripts 17 | 18 | ARG DEBIAN_FRONTEND=noninteractive 19 | 20 | RUN /jpegxl_scripts/jpegxl_builder.sh && \ 21 | rm -rf /jpegxl_scripts 22 | -------------------------------------------------------------------------------- /docker/Dockerfile.jpegxl-builder-run-aarch64: -------------------------------------------------------------------------------- 1 | # Copyright (c) the JPEG XL Project Authors. All rights reserved. 2 | # 3 | # Use of this source code is governed by a BSD-style 4 | # license that can be found in the LICENSE file. 5 | 6 | # Build an Ubuntu-based docker image for aarch64 with the installed software 7 | # needed to run JPEG XL. This is only useful when running on actual aarch64 8 | # hardware. 9 | 10 | FROM arm64v8/ubuntu:bionic 11 | 12 | COPY scripts/99_norecommends /etc/apt/apt.conf.d/99_norecommends 13 | 14 | # Set a prompt for when using it locally. 15 | ENV PS1="\[\033[01;33m\]\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ " 16 | 17 | ARG DEBIAN_FRONTEND=noninteractive 18 | 19 | RUN set -ex; \ 20 | apt-get update -y; \ 21 | apt-get install -y \ 22 | bsdmainutils \ 23 | cmake \ 24 | curl \ 25 | ca-certificates \ 26 | extra-cmake-modules \ 27 | git \ 28 | imagemagick \ 29 | libjpeg8 \ 30 | libgif7 \ 31 | libgoogle-perftools4 \ 32 | libopenexr22 \ 33 | libpng16-16 \ 34 | libqt5x11extras5 \ 35 | libsdl2-2.0-0 \ 36 | parallel; \ 37 | rm -rf /var/lib/apt/lists/*; 38 | -------------------------------------------------------------------------------- /docker/README.md: -------------------------------------------------------------------------------- 1 | ### Docker container infrastructure for JPEG XL 2 | 3 | This directory contains the requirements to build a docker image for the 4 | JPEG XL project builder. 5 | 6 | Docker images need to be created and upload manually. See ./build.sh for 7 | details. 8 | -------------------------------------------------------------------------------- /docker/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright (c) the JPEG XL Project Authors. 3 | # 4 | # Use of this source code is governed by a BSD-style 5 | # license that can be found in the LICENSE file or at 6 | # https://developers.google.com/open-source/licenses/bsd 7 | 8 | set -eu 9 | 10 | MYDIR=$(dirname $(realpath "$0")) 11 | 12 | declare -a TARGETS 13 | 14 | load_targets() { 15 | # Built-in OSX "find" does not support "-m". 16 | FIND=$(which "gfind" || which "find") 17 | for f in $(${FIND} -maxdepth 1 -name 'Dockerfile.*' | sort); do 18 | local target="${f#*Dockerfile.}" 19 | TARGETS+=("${target}") 20 | done 21 | } 22 | 23 | usage() { 24 | cat >&2 <&2 32 | done 33 | } 34 | 35 | build_target() { 36 | local target="$1" 37 | 38 | local dockerfile="${MYDIR}/Dockerfile.${target}" 39 | # JPEG XL builder images are stored in the gcr.io/jpegxl project. 40 | local tag="gcr.io/jpegxl/${target}" 41 | 42 | echo "Building ${target}" 43 | if ! sudo docker build --no-cache -t "${tag}" -f "${dockerfile}" "${MYDIR}" \ 44 | >"${target}.log" 2>&1; then 45 | echo "${target} failed. See ${target}.log" >&2 46 | else 47 | echo "Done, to upload image run:" >&2 48 | echo " sudo docker push ${tag}" 49 | if [[ "${JPEGXL_PUSH:-}" == "1" ]]; then 50 | echo "sudo docker push ${tag}" >&2 51 | sudo docker push "${tag}" 52 | # The RepoDigest is only created after it is pushed. 53 | local fulltag=$(sudo docker inspect --format="{{.RepoDigests}}" "${tag}") 54 | fulltag="${fulltag#[}" 55 | fulltag="${fulltag%]}" 56 | echo "Updating .gitlab-ci.yml to ${fulltag}" >&2 57 | sed -E "s;${tag}@sha256:[0-9a-f]+;${fulltag};" \ 58 | -i "${MYDIR}/../.gitlab-ci.yml" 59 | fi 60 | fi 61 | } 62 | 63 | main() { 64 | cd "${MYDIR}" 65 | local target="${1:-}" 66 | 67 | load_targets 68 | if [[ -z "${target}" ]]; then 69 | usage $0 70 | exit 1 71 | fi 72 | 73 | if [[ "${target}" == "all" ]]; then 74 | for target in "${TARGETS[@]}"; do 75 | build_target "${target}" 76 | done 77 | else 78 | for target in "$@"; do 79 | build_target "${target}" 80 | done 81 | fi 82 | } 83 | 84 | main "$@" 85 | -------------------------------------------------------------------------------- /docker/scripts/99_norecommends: -------------------------------------------------------------------------------- 1 | APT::Install-Recommends "false"; 2 | -------------------------------------------------------------------------------- /docker/scripts/binutils_align_fix.patch: -------------------------------------------------------------------------------- 1 | Description: fix lack of alignment in relocations (crashes on mingw) 2 | See https://sourceware.org/git/?p=binutils-gdb.git;a=patch;h=73af69e74974eaa155eec89867e3ccc77ab39f6d 3 | From: Marc 4 | Date: Fri, 9 Nov 2018 11:13:50 +0000 5 | Subject: [PATCH] Allow for compilers that do not produce aligned .rdat 6 | sections in PE format files. 7 | 8 | --- a/upstream/ld/scripttempl/pe.sc 2020-05-12 18:45:12.000000000 +0200 9 | +++ b/upstream/ld/scripttempl/pe.sc 2020-05-12 18:47:12.000000000 +0200 10 | @@ -143,6 +143,7 @@ 11 | .rdata ${RELOCATING+BLOCK(__section_alignment__)} : 12 | { 13 | ${R_RDATA} 14 | + . = ALIGN(4); 15 | ${RELOCATING+__rt_psrelocs_start = .;} 16 | ${RELOCATING+KEEP(*(.rdata_runtime_pseudo_reloc))} 17 | ${RELOCATING+__rt_psrelocs_end = .;} 18 | --- a/upstream/ld/scripttempl/pep.sc 2020-05-12 18:45:19.000000000 +0200 19 | +++ b/upstream/ld/scripttempl/pep.sc 2020-05-12 18:47:18.000000000 +0200 20 | @@ -143,6 +143,7 @@ 21 | .rdata ${RELOCATING+BLOCK(__section_alignment__)} : 22 | { 23 | ${R_RDATA} 24 | + . = ALIGN(4); 25 | ${RELOCATING+__rt_psrelocs_start = .;} 26 | ${RELOCATING+KEEP(*(.rdata_runtime_pseudo_reloc))} 27 | ${RELOCATING+__rt_psrelocs_end = .;} 28 | 29 | -------------------------------------------------------------------------------- /docker/scripts/emsdk_install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright (c) the JPEG XL Project Authors. 3 | # 4 | # Use of this source code is governed by a BSD-style 5 | # license that can be found in the LICENSE file or at 6 | # https://developers.google.com/open-source/licenses/bsd 7 | 8 | EMSDK_URL="https://github.com/emscripten-core/emsdk/archive/main.tar.gz" 9 | EMSDK_DIR="/opt/emsdk" 10 | 11 | EMSDK_RELEASE="2.0.23" 12 | 13 | set -eu -x 14 | 15 | # Temporary files cleanup hooks. 16 | CLEANUP_FILES=() 17 | cleanup() { 18 | if [[ ${#CLEANUP_FILES[@]} -ne 0 ]]; then 19 | rm -fr "${CLEANUP_FILES[@]}" 20 | fi 21 | } 22 | trap "{ set +x; } 2>/dev/null; cleanup" INT TERM EXIT 23 | 24 | main() { 25 | local workdir=$(mktemp -d --suffix=emsdk) 26 | CLEANUP_FILES+=("${workdir}") 27 | 28 | local emsdktar="${workdir}/emsdk.tar.gz" 29 | curl --output "${emsdktar}" "${EMSDK_URL}" --location 30 | mkdir -p "${EMSDK_DIR}" 31 | tar -zxf "${emsdktar}" -C "${EMSDK_DIR}" --strip-components=1 32 | 33 | cd "${EMSDK_DIR}" 34 | ./emsdk install --shallow "${EMSDK_RELEASE}" 35 | ./emsdk activate --embedded "${EMSDK_RELEASE}" 36 | } 37 | 38 | main "$@" 39 | -------------------------------------------------------------------------------- /docker/scripts/msan_install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright (c) the JPEG XL Project Authors. 3 | # 4 | # Use of this source code is governed by a BSD-style 5 | # license that can be found in the LICENSE file or at 6 | # https://developers.google.com/open-source/licenses/bsd 7 | 8 | set -eu 9 | 10 | MYDIR=$(dirname $(realpath "$0")) 11 | 12 | # Convenience flag to pass both CMAKE_C_FLAGS and CMAKE_CXX_FLAGS 13 | CMAKE_FLAGS=${CMAKE_FLAGS:-} 14 | CMAKE_C_FLAGS=${CMAKE_C_FLAGS:-${CMAKE_FLAGS}} 15 | CMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS:-${CMAKE_FLAGS}} 16 | CMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS:-} 17 | 18 | CLANG_VERSION="${CLANG_VERSION:-}" 19 | # Detect the clang version suffix and store it in CLANG_VERSION. For example, 20 | # "6.0" for clang 6 or "7" for clang 7. 21 | detect_clang_version() { 22 | if [[ -n "${CLANG_VERSION}" ]]; then 23 | return 0 24 | fi 25 | local clang_version=$("${CC:-clang}" --version | head -n1) 26 | local llvm_tag 27 | case "${clang_version}" in 28 | "clang version 6."*) 29 | CLANG_VERSION="6.0" 30 | ;; 31 | "clang version 7."*) 32 | CLANG_VERSION="7" 33 | ;; 34 | "clang version 8."*) 35 | CLANG_VERSION="8" 36 | ;; 37 | "clang version 9."*) 38 | CLANG_VERSION="9" 39 | ;; 40 | *) 41 | echo "Unknown clang version: ${clang_version}" >&2 42 | return 1 43 | esac 44 | } 45 | 46 | # Temporary files cleanup hooks. 47 | CLEANUP_FILES=() 48 | cleanup() { 49 | if [[ ${#CLEANUP_FILES[@]} -ne 0 ]]; then 50 | rm -fr "${CLEANUP_FILES[@]}" 51 | fi 52 | } 53 | trap "{ set +x; } 2>/dev/null; cleanup" INT TERM EXIT 54 | 55 | # Install libc++ libraries compiled with msan in the msan_prefix for the current 56 | # compiler version. 57 | cmd_msan_install() { 58 | local tmpdir=$(mktemp -d) 59 | CLEANUP_FILES+=("${tmpdir}") 60 | # Detect the llvm to install: 61 | export CC="${CC:-clang}" 62 | export CXX="${CXX:-clang++}" 63 | detect_clang_version 64 | local llvm_tag 65 | case "${CLANG_VERSION}" in 66 | "6.0") 67 | llvm_tag="llvmorg-6.0.1" 68 | ;; 69 | "7") 70 | llvm_tag="llvmorg-7.0.1" 71 | ;; 72 | "8") 73 | llvm_tag="llvmorg-8.0.0" 74 | ;; 75 | *) 76 | echo "Unknown clang version: ${clang_version}" >&2 77 | return 1 78 | esac 79 | local llvm_targz="${tmpdir}/${llvm_tag}.tar.gz" 80 | curl -L --show-error -o "${llvm_targz}" \ 81 | "https://github.com/llvm/llvm-project/archive/${llvm_tag}.tar.gz" 82 | tar -C "${tmpdir}" -zxf "${llvm_targz}" 83 | local llvm_root="${tmpdir}/llvm-project-${llvm_tag}" 84 | 85 | local msan_prefix="${HOME}/.msan/${CLANG_VERSION}" 86 | rm -rf "${msan_prefix}" 87 | 88 | declare -A CMAKE_EXTRAS 89 | CMAKE_EXTRAS[libcxx]="\ 90 | -DLIBCXX_CXX_ABI=libstdc++ \ 91 | -DLIBCXX_INSTALL_EXPERIMENTAL_LIBRARY=ON" 92 | 93 | for project in libcxx; do 94 | local proj_build="${tmpdir}/build-${project}" 95 | local proj_dir="${llvm_root}/${project}" 96 | mkdir -p "${proj_build}" 97 | cmake -B"${proj_build}" -H"${proj_dir}" \ 98 | -G Ninja \ 99 | -DCMAKE_BUILD_TYPE=Release \ 100 | -DLLVM_USE_SANITIZER=Memory \ 101 | -DLLVM_PATH="${llvm_root}/llvm" \ 102 | -DLLVM_CONFIG_PATH="$(which llvm-config llvm-config-7 llvm-config-6.0 | \ 103 | head -n1)" \ 104 | -DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS}" \ 105 | -DCMAKE_C_FLAGS="${CMAKE_C_FLAGS}" \ 106 | -DCMAKE_EXE_LINKER_FLAGS="${CMAKE_EXE_LINKER_FLAGS}" \ 107 | -DCMAKE_INSTALL_PREFIX="${msan_prefix}" \ 108 | ${CMAKE_EXTRAS[${project}]} 109 | cmake --build "${proj_build}" 110 | ninja -C "${proj_build}" install 111 | done 112 | } 113 | 114 | main() { 115 | set -x 116 | for version in 6.0 7 8; do 117 | if ! which "clang-${version}" >/dev/null; then 118 | echo "Skipping msan install for clang version ${version}" 119 | continue 120 | fi 121 | ( 122 | trap "{ set +x; } 2>/dev/null; cleanup" INT TERM EXIT 123 | export CLANG_VERSION=${version} 124 | export CC=clang-${version} 125 | export CXX=clang++-${version} 126 | cmd_msan_install 127 | ) & 128 | done 129 | wait 130 | } 131 | 132 | main "$@" 133 | -------------------------------------------------------------------------------- /docker/scripts/qemu_install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright (c) the JPEG XL Project Authors. 3 | # 4 | # Use of this source code is governed by a BSD-style 5 | # license that can be found in the LICENSE file or at 6 | # https://developers.google.com/open-source/licenses/bsd 7 | 8 | QEMU_RELEASE="4.1.0" 9 | QEMU_URL="https://download.qemu.org/qemu-${QEMU_RELEASE}.tar.xz" 10 | QEMU_ARCHS=( 11 | aarch64 12 | arm 13 | i386 14 | # TODO: Consider adding these: 15 | # aarch64_be 16 | # mips64el 17 | # mips64 18 | # mips 19 | # ppc64 20 | # ppc 21 | ) 22 | 23 | # Ubuntu packages not installed that are needed to build qemu. 24 | QEMU_BUILD_DEPS=( 25 | libglib2.0-dev 26 | libpixman-1-dev 27 | flex 28 | bison 29 | ) 30 | 31 | set -eu -x 32 | 33 | # Temporary files cleanup hooks. 34 | CLEANUP_FILES=() 35 | cleanup() { 36 | if [[ ${#CLEANUP_FILES[@]} -ne 0 ]]; then 37 | rm -fr "${CLEANUP_FILES[@]}" 38 | fi 39 | } 40 | trap "{ set +x; } 2>/dev/null; cleanup" INT TERM EXIT 41 | 42 | main() { 43 | local workdir=$(mktemp -d --suffix=qemu) 44 | CLEANUP_FILES+=("${workdir}") 45 | 46 | apt install -y "${QEMU_BUILD_DEPS[@]}" 47 | 48 | local qemutar="${workdir}/qemu.tar.gz" 49 | curl --output "${qemutar}" "${QEMU_URL}" 50 | tar -Jxf "${qemutar}" -C "${workdir}" 51 | local srcdir="${workdir}/qemu-${QEMU_RELEASE}" 52 | 53 | local builddir="${workdir}/build" 54 | local prefixdir="${workdir}/prefix" 55 | mkdir -p "${builddir}" 56 | 57 | # List of targets to build. 58 | local targets="" 59 | local make_targets=() 60 | local target 61 | for target in "${QEMU_ARCHS[@]}"; do 62 | targets="${targets} ${target}-linux-user" 63 | # Build just the linux-user targets. 64 | make_targets+=("${target}-linux-user/all") 65 | done 66 | 67 | cd "${builddir}" 68 | "${srcdir}/configure" \ 69 | --prefix="${prefixdir}" \ 70 | --static --disable-system --enable-linux-user \ 71 | --target-list="${targets}" 72 | 73 | make -j $(nproc --all || echo 1) "${make_targets[@]}" 74 | 75 | # Manually install these into the non-standard location. This script runs as 76 | # root anyway. 77 | for target in "${QEMU_ARCHS[@]}"; do 78 | cp "${target}-linux-user/qemu-${target}" "/usr/bin/qemu-${target}-static" 79 | done 80 | 81 | apt autoremove -y --purge "${QEMU_BUILD_DEPS[@]}" 82 | } 83 | 84 | main "$@" 85 | -------------------------------------------------------------------------------- /encoder/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) the JPEG XL Project Authors. 2 | # 3 | # Use of this source code is governed by a BSD-style 4 | # license that can be found in the LICENSE file or at 5 | # https://developers.google.com/open-source/licenses/bsd 6 | 7 | add_library(jxl_tiny STATIC EXCLUDE_FROM_ALL 8 | base/cache_aligned.cc 9 | base/data_parallel.cc 10 | base/padded_bytes.cc 11 | dct_scales.cc 12 | enc_ac_strategy.cc 13 | enc_adaptive_quantization.cc 14 | enc_bit_writer.cc 15 | enc_chroma_from_luma.cc 16 | enc_cluster.cc 17 | enc_entropy_code.cc 18 | enc_file.cc 19 | enc_frame.cc 20 | enc_group.cc 21 | enc_huffman_tree.cc 22 | enc_xyb.cc 23 | image.cc 24 | quant_weights.cc 25 | read_pfm.cc 26 | ) 27 | target_compile_options(jxl_tiny PUBLIC "${JPEGXL_INTERNAL_FLAGS}") 28 | target_include_directories(jxl_tiny PUBLIC "${PROJECT_SOURCE_DIR}") 29 | target_link_libraries(jxl_tiny hwy pthread) 30 | 31 | 32 | add_executable(cjxl_tiny cjxl_main.cc) 33 | target_link_libraries(cjxl_tiny jxl_tiny) 34 | -------------------------------------------------------------------------------- /encoder/ac_context.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #ifndef ENCODER_AC_CONTEXT_H_ 8 | #define ENCODER_AC_CONTEXT_H_ 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | #include "encoder/base/compiler_specific.h" 17 | 18 | namespace jxl { 19 | 20 | // The number of predicted nonzeros goes from 0 to 1008. We use 21 | // ceil(log2(predicted+1)) as a context for the number of nonzeros, so from 0 to 22 | // 10, inclusive. 23 | constexpr uint32_t kNonZeroBuckets = 37; 24 | 25 | static constexpr uint16_t kCoeffFreqContext[64] = { 26 | 0xBAD, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 27 | 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 28 | 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 29 | 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 30 | }; 31 | 32 | static constexpr uint16_t kCoeffNumNonzeroContext[64] = { 33 | 0xBAD, 0, 31, 62, 62, 93, 93, 93, 93, 123, 123, 123, 123, 34 | 152, 152, 152, 152, 152, 152, 152, 152, 180, 180, 180, 180, 180, 35 | 180, 180, 180, 180, 180, 180, 180, 206, 206, 206, 206, 206, 206, 36 | 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 37 | 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 38 | }; 39 | 40 | // Supremum of ZeroDensityContext(x, y) + 1, when x + y < 64. 41 | constexpr int kZeroDensityContextCount = 458; 42 | // Supremum of ZeroDensityContext(x, y) + 1. 43 | constexpr int kZeroDensityContextLimit = 474; 44 | 45 | static constexpr uint8_t kCompactBlockContextMap[] = { 46 | 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // Y 47 | 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, // X 48 | 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, // B 49 | }; 50 | static constexpr uint8_t kBlockContextMap[] = { 51 | // X 52 | 2, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, // 53 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 54 | // Y 55 | 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // 56 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 57 | // B 58 | 2, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, // 59 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60 | }; 61 | static constexpr size_t kNumAcStrategyCodes = 27; 62 | static constexpr size_t kNumBlockCtxs = 4; 63 | 64 | static constexpr size_t BlockContext(size_t c, uint8_t ac_strategy_code) { 65 | return kBlockContextMap[c * kNumAcStrategyCodes + ac_strategy_code]; 66 | } 67 | 68 | // Context map for AC coefficients consists of 2 blocks: 69 | // |num_ctxs x : context for number of non-zeros in the block 70 | // kNonZeroBuckets| computed from block context and predicted 71 | // value (based top and left values) 72 | // |num_ctxs x : context for AC coefficient symbols, 73 | // kZeroDensityContextCount| computed from block context, 74 | // number of non-zeros left and 75 | // index in scan order 76 | static constexpr size_t kNumACContexts = 77 | kNumBlockCtxs * (kNonZeroBuckets + kZeroDensityContextCount); 78 | 79 | /* This function is used for entropy-sources pre-clustering. 80 | * 81 | * Ideally, each combination of |nonzeros_left| and |k| should go to its own 82 | * bucket; but it implies (64 * 63 / 2) == 2016 buckets. If there is other 83 | * dimension (e.g. block context), then number of primary clusters becomes too 84 | * big. 85 | * 86 | * To solve this problem, |nonzeros_left| and |k| values are clustered. It is 87 | * known that their sum is at most 64, consequently, the total number buckets 88 | * is at most A(64) * B(64). 89 | */ 90 | static JXL_INLINE size_t ZeroDensityContext(size_t nonzeros_left, size_t k, 91 | size_t covered_blocks, 92 | size_t log2_covered_blocks, 93 | size_t prev) { 94 | nonzeros_left = (nonzeros_left + covered_blocks - 1) >> log2_covered_blocks; 95 | k >>= log2_covered_blocks; 96 | return (kCoeffNumNonzeroContext[nonzeros_left] + kCoeffFreqContext[k]) * 2 + 97 | prev; 98 | } 99 | 100 | static constexpr uint32_t ZeroDensityContextsOffset(uint32_t block_ctx) { 101 | return (kNumBlockCtxs * kNonZeroBuckets + 102 | kZeroDensityContextCount * block_ctx); 103 | } 104 | 105 | // Non-zero context is based on number of non-zeros and block context. 106 | // For better clustering, contexts with same number of non-zeros are grouped. 107 | static constexpr uint32_t NonZeroContext(uint32_t non_zeros, 108 | uint32_t block_ctx) { 109 | return (non_zeros < 8 ? non_zeros 110 | : non_zeros >= 64 ? 36 111 | : 4 + non_zeros / 2) * 112 | kNumBlockCtxs + 113 | block_ctx; 114 | } 115 | 116 | } // namespace jxl 117 | 118 | #endif // ENCODER_AC_CONTEXT_H_ 119 | -------------------------------------------------------------------------------- /encoder/base/bits.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #ifndef ENCODER_BASE_BITS_H_ 8 | #define ENCODER_BASE_BITS_H_ 9 | 10 | // Specialized instructions for processing register-sized bit arrays. 11 | 12 | #include "encoder/base/compiler_specific.h" 13 | #include "encoder/base/status.h" 14 | 15 | #if JXL_COMPILER_MSVC 16 | #include 17 | #endif 18 | 19 | #include 20 | #include 21 | 22 | namespace jxl { 23 | 24 | // Empty struct used as a size tag type. 25 | template 26 | struct SizeTag {}; 27 | 28 | template 29 | constexpr bool IsSigned() { 30 | return T(0) > T(-1); 31 | } 32 | 33 | // Undefined results for x == 0. 34 | static JXL_INLINE JXL_MAYBE_UNUSED size_t 35 | Num0BitsAboveMS1Bit_Nonzero(SizeTag<4> /* tag */, const uint32_t x) { 36 | JXL_DASSERT(x != 0); 37 | #if JXL_COMPILER_MSVC 38 | unsigned long index; 39 | _BitScanReverse(&index, x); 40 | return 31 - index; 41 | #else 42 | return static_cast(__builtin_clz(x)); 43 | #endif 44 | } 45 | static JXL_INLINE JXL_MAYBE_UNUSED size_t 46 | Num0BitsAboveMS1Bit_Nonzero(SizeTag<8> /* tag */, const uint64_t x) { 47 | JXL_DASSERT(x != 0); 48 | #if JXL_COMPILER_MSVC 49 | #if JXL_ARCH_X64 50 | unsigned long index; 51 | _BitScanReverse64(&index, x); 52 | return 63 - index; 53 | #else // JXL_ARCH_X64 54 | // _BitScanReverse64 not available 55 | uint32_t msb = static_cast(x >> 32u); 56 | unsigned long index; 57 | if (msb == 0) { 58 | uint32_t lsb = static_cast(x & 0xFFFFFFFF); 59 | _BitScanReverse(&index, lsb); 60 | return 63 - index; 61 | } else { 62 | _BitScanReverse(&index, msb); 63 | return 31 - index; 64 | } 65 | #endif // JXL_ARCH_X64 66 | #else 67 | return static_cast(__builtin_clzll(x)); 68 | #endif 69 | } 70 | template 71 | static JXL_INLINE JXL_MAYBE_UNUSED size_t 72 | Num0BitsAboveMS1Bit_Nonzero(const T x) { 73 | static_assert(!IsSigned(), "Num0BitsAboveMS1Bit_Nonzero: use unsigned"); 74 | return Num0BitsAboveMS1Bit_Nonzero(SizeTag(), x); 75 | } 76 | 77 | // Undefined results for x == 0. 78 | static JXL_INLINE JXL_MAYBE_UNUSED size_t 79 | Num0BitsBelowLS1Bit_Nonzero(SizeTag<4> /* tag */, const uint32_t x) { 80 | JXL_DASSERT(x != 0); 81 | #if JXL_COMPILER_MSVC 82 | unsigned long index; 83 | _BitScanForward(&index, x); 84 | return index; 85 | #else 86 | return static_cast(__builtin_ctz(x)); 87 | #endif 88 | } 89 | static JXL_INLINE JXL_MAYBE_UNUSED size_t 90 | Num0BitsBelowLS1Bit_Nonzero(SizeTag<8> /* tag */, const uint64_t x) { 91 | JXL_DASSERT(x != 0); 92 | #if JXL_COMPILER_MSVC 93 | #if JXL_ARCH_X64 94 | unsigned long index; 95 | _BitScanForward64(&index, x); 96 | return index; 97 | #else // JXL_ARCH_64 98 | // _BitScanForward64 not available 99 | uint32_t lsb = static_cast(x & 0xFFFFFFFF); 100 | unsigned long index; 101 | if (lsb == 0) { 102 | uint32_t msb = static_cast(x >> 32u); 103 | _BitScanForward(&index, msb); 104 | return 32 + index; 105 | } else { 106 | _BitScanForward(&index, lsb); 107 | return index; 108 | } 109 | #endif // JXL_ARCH_X64 110 | #else 111 | return static_cast(__builtin_ctzll(x)); 112 | #endif 113 | } 114 | template 115 | static JXL_INLINE JXL_MAYBE_UNUSED size_t Num0BitsBelowLS1Bit_Nonzero(T x) { 116 | static_assert(!IsSigned(), "Num0BitsBelowLS1Bit_Nonzero: use unsigned"); 117 | return Num0BitsBelowLS1Bit_Nonzero(SizeTag(), x); 118 | } 119 | 120 | // Returns base-2 logarithm, rounded down. 121 | template 122 | static JXL_INLINE JXL_MAYBE_UNUSED size_t FloorLog2Nonzero(const T x) { 123 | return (sizeof(T) * 8 - 1) ^ Num0BitsAboveMS1Bit_Nonzero(x); 124 | } 125 | 126 | // Returns base-2 logarithm, rounded up. 127 | template 128 | static JXL_INLINE JXL_MAYBE_UNUSED size_t CeilLog2Nonzero(const T x) { 129 | const size_t floor_log2 = FloorLog2Nonzero(x); 130 | if ((x & (x - 1)) == 0) return floor_log2; // power of two 131 | return floor_log2 + 1; 132 | } 133 | 134 | } // namespace jxl 135 | 136 | #endif // ENCODER_BASE_BITS_H_ 137 | -------------------------------------------------------------------------------- /encoder/base/byte_order.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #ifndef ENCODER_BASE_BYTE_ORDER_H_ 8 | #define ENCODER_BASE_BYTE_ORDER_H_ 9 | 10 | #include 11 | #include // memcpy 12 | 13 | #include "encoder/base/compiler_specific.h" 14 | 15 | #if JXL_COMPILER_MSVC 16 | #include // _byteswap_* 17 | #endif 18 | 19 | #if (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) 20 | #define JXL_BYTE_ORDER_LITTLE 1 21 | #else 22 | // This means that we don't know that the byte order is little endian, in 23 | // this case we use endian-neutral code that works for both little- and 24 | // big-endian. 25 | #define JXL_BYTE_ORDER_LITTLE 0 26 | #endif 27 | 28 | // Returns whether the system is little-endian (least-significant byte first). 29 | #if JXL_BYTE_ORDER_LITTLE 30 | static constexpr bool IsLittleEndian() { return true; } 31 | #else 32 | static inline bool IsLittleEndian() { 33 | const uint32_t multibyte = 1; 34 | uint8_t byte; 35 | memcpy(&byte, &multibyte, 1); 36 | return byte == 1; 37 | } 38 | #endif 39 | 40 | #if JXL_COMPILER_MSVC 41 | #define JXL_BSWAP32(x) _byteswap_ulong(x) 42 | #else 43 | #define JXL_BSWAP32(x) __builtin_bswap32(x) 44 | #endif 45 | 46 | static JXL_INLINE float BSwapFloat(float x) { 47 | uint32_t u; 48 | memcpy(&u, &x, 4); 49 | uint32_t uswap = JXL_BSWAP32(u); 50 | float xswap; 51 | memcpy(&xswap, &uswap, 4); 52 | return xswap; 53 | } 54 | 55 | #endif // ENCODER_BASE_BYTE_ORDER_H_ 56 | -------------------------------------------------------------------------------- /encoder/base/cache_aligned.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #include "encoder/base/cache_aligned.h" 8 | 9 | #include 10 | #include 11 | 12 | // Disabled: slower than malloc + alignment. 13 | #define JXL_USE_MMAP 0 14 | 15 | #if JXL_USE_MMAP 16 | #include 17 | #endif 18 | 19 | #include // std::max 20 | #include 21 | #include // kMaxVectorSize 22 | #include 23 | 24 | #include "encoder/base/printf_macros.h" 25 | #include "encoder/base/status.h" 26 | 27 | namespace jxl { 28 | namespace { 29 | 30 | #pragma pack(push, 1) 31 | struct AllocationHeader { 32 | void* allocated; 33 | size_t allocated_size; 34 | uint8_t left_padding[hwy::kMaxVectorSize]; 35 | }; 36 | #pragma pack(pop) 37 | 38 | std::atomic num_allocations{0}; 39 | std::atomic bytes_in_use{0}; 40 | std::atomic max_bytes_in_use{0}; 41 | 42 | } // namespace 43 | 44 | // Avoids linker errors in pre-C++17 builds. 45 | constexpr size_t CacheAligned::kPointerSize; 46 | constexpr size_t CacheAligned::kCacheLineSize; 47 | constexpr size_t CacheAligned::kAlignment; 48 | constexpr size_t CacheAligned::kAlias; 49 | 50 | size_t CacheAligned::NextOffset() { 51 | static std::atomic next{0}; 52 | constexpr uint32_t kGroups = CacheAligned::kAlias / CacheAligned::kAlignment; 53 | const uint32_t group = next.fetch_add(1, std::memory_order_relaxed) % kGroups; 54 | return CacheAligned::kAlignment * group; 55 | } 56 | 57 | void* CacheAligned::Allocate(const size_t payload_size, size_t offset) { 58 | JXL_ASSERT(payload_size <= std::numeric_limits::max() / 2); 59 | JXL_ASSERT((offset % kAlignment == 0) && offset <= kAlias); 60 | 61 | // What: | misalign | unused | AllocationHeader |payload 62 | // Size: |<= kAlias | offset | |payload_size 63 | // ^allocated.^aligned.^header............^payload 64 | // The header must immediately precede payload, which must remain aligned. 65 | // To avoid wasting space, the header resides at the end of `unused`, 66 | // which therefore cannot be empty (offset == 0). 67 | if (offset == 0) { 68 | // SVE/RVV vectors can be large, so we cannot rely on them (including the 69 | // padding at the end of AllocationHeader) to fit in kAlignment. 70 | offset = hwy::RoundUpTo(sizeof(AllocationHeader), kAlignment); 71 | } 72 | 73 | #if JXL_USE_MMAP 74 | const size_t allocated_size = offset + payload_size; 75 | const int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE; 76 | void* allocated = 77 | mmap(nullptr, allocated_size, PROT_READ | PROT_WRITE, flags, -1, 0); 78 | if (allocated == MAP_FAILED) return nullptr; 79 | const uintptr_t aligned = reinterpret_cast(allocated); 80 | #else 81 | const size_t allocated_size = kAlias + offset + payload_size; 82 | void* allocated = malloc(allocated_size); 83 | if (allocated == nullptr) return nullptr; 84 | // Always round up even if already aligned - we already asked for kAlias 85 | // extra bytes and there's no way to give them back. 86 | uintptr_t aligned = reinterpret_cast(allocated) + kAlias; 87 | static_assert((kAlias & (kAlias - 1)) == 0, "kAlias must be a power of 2"); 88 | static_assert(kAlias >= kAlignment, "Cannot align to more than kAlias"); 89 | aligned &= ~(kAlias - 1); 90 | #endif 91 | 92 | #if 0 93 | // No effect. 94 | uintptr_t page_aligned = reinterpret_cast(allocated); 95 | page_aligned &= ~(4096 - 1); 96 | if (madvise(reinterpret_cast(page_aligned), allocated_size, 97 | MADV_WILLNEED) != 0) { 98 | JXL_NOTIFY_ERROR("madvise failed"); 99 | } 100 | #elif 0 101 | // INCREASES both first and subsequent decode times. 102 | if (mlock(allocated, allocated_size) != 0) { 103 | JXL_NOTIFY_ERROR("mlock failed"); 104 | } 105 | #endif 106 | 107 | // Update statistics (#allocations and max bytes in use) 108 | num_allocations.fetch_add(1, std::memory_order_relaxed); 109 | const uint64_t prev_bytes = 110 | bytes_in_use.fetch_add(allocated_size, std::memory_order_acq_rel); 111 | uint64_t expected_max = max_bytes_in_use.load(std::memory_order_acquire); 112 | for (;;) { 113 | const uint64_t desired = 114 | std::max(expected_max, prev_bytes + allocated_size); 115 | if (max_bytes_in_use.compare_exchange_strong(expected_max, desired, 116 | std::memory_order_acq_rel)) { 117 | break; 118 | } 119 | } 120 | 121 | const uintptr_t payload = aligned + offset; // still aligned 122 | 123 | // Stash `allocated` and payload_size inside header for use by Free(). 124 | AllocationHeader* header = reinterpret_cast(payload) - 1; 125 | header->allocated = allocated; 126 | header->allocated_size = allocated_size; 127 | 128 | return JXL_ASSUME_ALIGNED(reinterpret_cast(payload), 64); 129 | } 130 | 131 | void CacheAligned::Free(const void* aligned_pointer) { 132 | if (aligned_pointer == nullptr) { 133 | return; 134 | } 135 | const uintptr_t payload = reinterpret_cast(aligned_pointer); 136 | JXL_ASSERT(payload % kAlignment == 0); 137 | const AllocationHeader* header = 138 | reinterpret_cast(payload) - 1; 139 | 140 | // Subtract (2's complement negation). 141 | bytes_in_use.fetch_add(~header->allocated_size + 1, 142 | std::memory_order_acq_rel); 143 | 144 | #if JXL_USE_MMAP 145 | munmap(header->allocated, header->allocated_size); 146 | #else 147 | free(header->allocated); 148 | #endif 149 | } 150 | 151 | } // namespace jxl 152 | -------------------------------------------------------------------------------- /encoder/base/cache_aligned.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #ifndef ENCODER_BASE_CACHE_ALIGNED_H_ 8 | #define ENCODER_BASE_CACHE_ALIGNED_H_ 9 | 10 | // Memory allocator with support for alignment + misalignment. 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include "encoder/base/compiler_specific.h" 18 | 19 | namespace jxl { 20 | 21 | // Functions that depend on the cache line size. 22 | class CacheAligned { 23 | public: 24 | static constexpr size_t kPointerSize = sizeof(void*); 25 | static constexpr size_t kCacheLineSize = 64; 26 | // To avoid RFOs, match L2 fill size (pairs of lines). 27 | static constexpr size_t kAlignment = 2 * kCacheLineSize; 28 | // Minimum multiple for which cache set conflicts and/or loads blocked by 29 | // preceding stores can occur. 30 | static constexpr size_t kAlias = 2048; 31 | 32 | // Returns a 'random' (cyclical) offset suitable for Allocate. 33 | static size_t NextOffset(); 34 | 35 | // Returns null or memory whose address is congruent to `offset` (mod kAlias). 36 | // This reduces cache conflicts and load/store stalls, especially with large 37 | // allocations that would otherwise have similar alignments. At least 38 | // `payload_size` (which can be zero) bytes will be accessible. 39 | static void* Allocate(size_t payload_size, size_t offset); 40 | 41 | static void* Allocate(const size_t payload_size) { 42 | return Allocate(payload_size, NextOffset()); 43 | } 44 | 45 | static void Free(const void* aligned_pointer); 46 | }; 47 | 48 | // Avoids the need for a function pointer (deleter) in CacheAlignedUniquePtr. 49 | struct CacheAlignedDeleter { 50 | void operator()(uint8_t* aligned_pointer) const { 51 | return CacheAligned::Free(aligned_pointer); 52 | } 53 | }; 54 | 55 | using CacheAlignedUniquePtr = std::unique_ptr; 56 | 57 | // Does not invoke constructors. 58 | static inline CacheAlignedUniquePtr AllocateArray(const size_t bytes) { 59 | return CacheAlignedUniquePtr( 60 | static_cast(CacheAligned::Allocate(bytes)), 61 | CacheAlignedDeleter()); 62 | } 63 | 64 | static inline CacheAlignedUniquePtr AllocateArray(const size_t bytes, 65 | const size_t offset) { 66 | return CacheAlignedUniquePtr( 67 | static_cast(CacheAligned::Allocate(bytes, offset)), 68 | CacheAlignedDeleter()); 69 | } 70 | 71 | } // namespace jxl 72 | 73 | #endif // ENCODER_BASE_CACHE_ALIGNED_H_ 74 | -------------------------------------------------------------------------------- /encoder/base/compiler_specific.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #ifndef ENCODER_BASE_COMPILER_SPECIFIC_H_ 8 | #define ENCODER_BASE_COMPILER_SPECIFIC_H_ 9 | 10 | // Macros for compiler version + nonstandard keywords, e.g. __builtin_expect. 11 | 12 | #include 13 | 14 | #include "encoder/base/sanitizer_definitions.h" 15 | 16 | // #if is shorter and safer than #ifdef. *_VERSION are zero if not detected, 17 | // otherwise 100 * major + minor version. Note that other packages check for 18 | // #ifdef COMPILER_MSVC, so we cannot use that same name. 19 | 20 | #ifdef _MSC_VER 21 | #define JXL_COMPILER_MSVC _MSC_VER 22 | #else 23 | #define JXL_COMPILER_MSVC 0 24 | #endif 25 | 26 | #ifdef __GNUC__ 27 | #define JXL_COMPILER_GCC (__GNUC__ * 100 + __GNUC_MINOR__) 28 | #else 29 | #define JXL_COMPILER_GCC 0 30 | #endif 31 | 32 | #ifdef __clang__ 33 | #define JXL_COMPILER_CLANG (__clang_major__ * 100 + __clang_minor__) 34 | // Clang pretends to be GCC for compatibility. 35 | #undef JXL_COMPILER_GCC 36 | #define JXL_COMPILER_GCC 0 37 | #else 38 | #define JXL_COMPILER_CLANG 0 39 | #endif 40 | 41 | #if JXL_COMPILER_MSVC 42 | #define JXL_RESTRICT __restrict 43 | #elif JXL_COMPILER_GCC || JXL_COMPILER_CLANG 44 | #define JXL_RESTRICT __restrict__ 45 | #else 46 | #define JXL_RESTRICT 47 | #endif 48 | 49 | #if JXL_COMPILER_MSVC 50 | #define JXL_INLINE __forceinline 51 | #define JXL_NOINLINE __declspec(noinline) 52 | #else 53 | #define JXL_INLINE inline __attribute__((always_inline)) 54 | #define JXL_NOINLINE __attribute__((noinline)) 55 | #endif 56 | 57 | #if JXL_COMPILER_MSVC 58 | #define JXL_NORETURN __declspec(noreturn) 59 | #elif JXL_COMPILER_GCC || JXL_COMPILER_CLANG 60 | #define JXL_NORETURN __attribute__((noreturn)) 61 | #else 62 | #define JXL_NORETURN 63 | #endif 64 | 65 | #if JXL_COMPILER_MSVC 66 | #define JXL_UNREACHABLE __assume(false) 67 | #elif JXL_COMPILER_CLANG || JXL_COMPILER_GCC >= 405 68 | #define JXL_UNREACHABLE __builtin_unreachable() 69 | #else 70 | #define JXL_UNREACHABLE 71 | #endif 72 | 73 | #if JXL_COMPILER_MSVC 74 | #define JXL_MAYBE_UNUSED 75 | #else 76 | // Encountered "attribute list cannot appear here" when using the C++17 77 | // [[maybe_unused]], so only use the old style attribute for now. 78 | #define JXL_MAYBE_UNUSED __attribute__((unused)) 79 | #endif 80 | 81 | // MSAN execution won't hurt if some code it not inlined, but this can greatly 82 | // improve compilation time. Unfortunately this macro can not be used just 83 | // everywhere - inside header files it leads to "multiple definition" error; 84 | // though it would be better not to have JXL_INLINE in header overall. 85 | #if JXL_MEMORY_SANITIZER || JXL_ADDRESS_SANITIZER || JXL_THREAD_SANITIZER 86 | #define JXL_MAYBE_INLINE JXL_MAYBE_UNUSED 87 | #else 88 | #define JXL_MAYBE_INLINE JXL_INLINE 89 | #endif 90 | 91 | #if JXL_COMPILER_MSVC 92 | // Unsupported, __assume is not the same. 93 | #define JXL_LIKELY(expr) expr 94 | #define JXL_UNLIKELY(expr) expr 95 | #else 96 | #define JXL_LIKELY(expr) __builtin_expect(!!(expr), 1) 97 | #define JXL_UNLIKELY(expr) __builtin_expect(!!(expr), 0) 98 | #endif 99 | 100 | // Returns a void* pointer which the compiler then assumes is N-byte aligned. 101 | // Example: float* JXL_RESTRICT aligned = (float*)JXL_ASSUME_ALIGNED(in, 32); 102 | // 103 | // The assignment semantics are required by GCC/Clang. ICC provides an in-place 104 | // __assume_aligned, whereas MSVC's __assume appears unsuitable. 105 | #if JXL_COMPILER_CLANG 106 | // Early versions of Clang did not support __builtin_assume_aligned. 107 | #define JXL_HAS_ASSUME_ALIGNED __has_builtin(__builtin_assume_aligned) 108 | #elif JXL_COMPILER_GCC 109 | #define JXL_HAS_ASSUME_ALIGNED 1 110 | #else 111 | #define JXL_HAS_ASSUME_ALIGNED 0 112 | #endif 113 | 114 | #if JXL_HAS_ASSUME_ALIGNED 115 | #define JXL_ASSUME_ALIGNED(ptr, align) __builtin_assume_aligned((ptr), (align)) 116 | #else 117 | #define JXL_ASSUME_ALIGNED(ptr, align) (ptr) /* not supported */ 118 | #endif 119 | 120 | #ifdef __has_attribute 121 | #define JXL_HAVE_ATTRIBUTE(x) __has_attribute(x) 122 | #else 123 | #define JXL_HAVE_ATTRIBUTE(x) 0 124 | #endif 125 | 126 | // Raises warnings if the function return value is unused. Should appear as the 127 | // first part of a function definition/declaration. 128 | #if JXL_HAVE_ATTRIBUTE(nodiscard) 129 | #define JXL_MUST_USE_RESULT [[nodiscard]] 130 | #elif JXL_COMPILER_CLANG && JXL_HAVE_ATTRIBUTE(warn_unused_result) 131 | #define JXL_MUST_USE_RESULT __attribute__((warn_unused_result)) 132 | #else 133 | #define JXL_MUST_USE_RESULT 134 | #endif 135 | 136 | // Disable certain -fsanitize flags for functions that are expected to include 137 | // things like unsigned integer overflow. For example use in the function 138 | // declaration JXL_NO_SANITIZE("unsigned-integer-overflow") to silence unsigned 139 | // integer overflow ubsan messages. 140 | #if JXL_COMPILER_CLANG && JXL_HAVE_ATTRIBUTE(no_sanitize) 141 | #define JXL_NO_SANITIZE(X) __attribute__((no_sanitize(X))) 142 | #else 143 | #define JXL_NO_SANITIZE(X) 144 | #endif 145 | 146 | #if JXL_HAVE_ATTRIBUTE(__format__) 147 | #define JXL_FORMAT(idx_fmt, idx_arg) \ 148 | __attribute__((__format__(__printf__, idx_fmt, idx_arg))) 149 | #else 150 | #define JXL_FORMAT(idx_fmt, idx_arg) 151 | #endif 152 | 153 | #if JXL_COMPILER_MSVC 154 | using ssize_t = intptr_t; 155 | #endif 156 | 157 | #endif // ENCODER_BASE_COMPILER_SPECIFIC_H_ 158 | -------------------------------------------------------------------------------- /encoder/base/padded_bytes.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #include "encoder/base/padded_bytes.h" 8 | 9 | namespace jxl { 10 | 11 | void PaddedBytes::IncreaseCapacityTo(size_t capacity) { 12 | JXL_ASSERT(capacity > capacity_); 13 | 14 | size_t new_capacity = std::max(capacity, 3 * capacity_ / 2); 15 | new_capacity = std::max(64, new_capacity); 16 | 17 | // BitWriter writes up to 7 bytes past the end. 18 | CacheAlignedUniquePtr new_data = AllocateArray(new_capacity + 8); 19 | if (new_data == nullptr) { 20 | // Allocation failed, discard all data to ensure this is noticed. 21 | size_ = capacity_ = 0; 22 | return; 23 | } 24 | 25 | if (data_ == nullptr) { 26 | // First allocation: ensure first byte is initialized (won't be copied). 27 | new_data[0] = 0; 28 | } else { 29 | // Subsequent resize: copy existing data to new location. 30 | memcpy(new_data.get(), data_.get(), size_); 31 | // Ensure that the first new byte is initialized, to allow write_bits to 32 | // safely append to the newly-resized PaddedBytes. 33 | new_data[size_] = 0; 34 | } 35 | 36 | capacity_ = new_capacity; 37 | std::swap(new_data, data_); 38 | } 39 | 40 | void PaddedBytes::assign(const uint8_t* new_begin, const uint8_t* new_end) { 41 | JXL_DASSERT(new_begin <= new_end); 42 | const size_t new_size = static_cast(new_end - new_begin); 43 | 44 | // memcpy requires non-overlapping ranges, and resizing might invalidate the 45 | // new range. Neither happens if the new range is completely to the left or 46 | // right of the _allocated_ range (irrespective of size_). 47 | const uint8_t* allocated_end = begin() + capacity_; 48 | const bool outside = new_end <= begin() || new_begin >= allocated_end; 49 | if (outside) { 50 | resize(new_size); // grow or shrink 51 | memcpy(data(), new_begin, new_size); 52 | return; 53 | } 54 | 55 | // There is overlap. The new size cannot be larger because we own the memory 56 | // and the new range cannot include anything outside the allocated range. 57 | JXL_ASSERT(new_size <= capacity_); 58 | 59 | // memmove allows overlap and capacity_ is sufficient. 60 | memmove(data(), new_begin, new_size); 61 | size_ = new_size; // shrink 62 | } 63 | 64 | } // namespace jxl 65 | -------------------------------------------------------------------------------- /encoder/base/printf_macros.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #ifndef ENCODER_BASE_PRINTF_MACROS_H_ 8 | #define ENCODER_BASE_PRINTF_MACROS_H_ 9 | 10 | // Format string macros. These should be included after any other system 11 | // library since those may unconditionally define these, depending on the 12 | // platform. 13 | 14 | // PRIuS and PRIdS macros to print size_t and ssize_t respectively. 15 | #if !defined(PRIdS) 16 | #if defined(_WIN64) 17 | #define PRIdS "lld" 18 | #elif defined(_WIN32) 19 | #define PRIdS "d" 20 | #else 21 | #define PRIdS "zd" 22 | #endif 23 | #endif // PRIdS 24 | 25 | #if !defined(PRIuS) 26 | #if defined(_WIN64) 27 | #define PRIuS "llu" 28 | #elif defined(_WIN32) 29 | #define PRIuS "u" 30 | #else 31 | #define PRIuS "zu" 32 | #endif 33 | #endif // PRIuS 34 | 35 | #endif // ENCODER_BASE_PRINTF_MACROS_H_ 36 | -------------------------------------------------------------------------------- /encoder/base/sanitizer_definitions.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #ifndef ENCODER_BASE_SANITIZER_DEFINITIONS_H_ 8 | #define ENCODER_BASE_SANITIZER_DEFINITIONS_H_ 9 | 10 | #ifdef MEMORY_SANITIZER 11 | #define JXL_MEMORY_SANITIZER 1 12 | #elif defined(__has_feature) 13 | #if __has_feature(memory_sanitizer) 14 | #define JXL_MEMORY_SANITIZER 1 15 | #else 16 | #define JXL_MEMORY_SANITIZER 0 17 | #endif 18 | #else 19 | #define JXL_MEMORY_SANITIZER 0 20 | #endif 21 | 22 | #ifdef ADDRESS_SANITIZER 23 | #define JXL_ADDRESS_SANITIZER 1 24 | #elif defined(__has_feature) 25 | #if __has_feature(address_sanitizer) 26 | #define JXL_ADDRESS_SANITIZER 1 27 | #else 28 | #define JXL_ADDRESS_SANITIZER 0 29 | #endif 30 | #else 31 | #define JXL_ADDRESS_SANITIZER 0 32 | #endif 33 | 34 | #ifdef THREAD_SANITIZER 35 | #define JXL_THREAD_SANITIZER 1 36 | #elif defined(__has_feature) 37 | #if __has_feature(thread_sanitizer) 38 | #define JXL_THREAD_SANITIZER 1 39 | #else 40 | #define JXL_THREAD_SANITIZER 0 41 | #endif 42 | #else 43 | #define JXL_THREAD_SANITIZER 0 44 | #endif 45 | 46 | #if JXL_MEMORY_SANITIZER 47 | #include 48 | #include 49 | 50 | #include "sanitizer/msan_interface.h" 51 | namespace jxl { 52 | namespace msan { 53 | // Chosen so that kSanitizerSentinel is four copies of kSanitizerSentinelByte. 54 | constexpr uint8_t kSanitizerSentinelByte = 0x48; 55 | constexpr float kSanitizerSentinel = 205089.125f; 56 | } // namespace msan 57 | } // namespace jxl 58 | #endif // JXL_MEMORY_SANITIZER 59 | 60 | #endif // ENCODER_BASE_SANITIZER_DEFINITIONS_H 61 | -------------------------------------------------------------------------------- /encoder/base/span.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #ifndef ENCODER_BASE_SPAN_H_ 8 | #define ENCODER_BASE_SPAN_H_ 9 | 10 | // Span (array view) is a non-owning container that provides cheap "cut" 11 | // operations and could be used as "ArrayLike" data source for PaddedBytes. 12 | 13 | #include 14 | 15 | #include "encoder/base/status.h" 16 | 17 | namespace jxl { 18 | 19 | template 20 | class Span { 21 | public: 22 | constexpr Span() noexcept : Span(nullptr, 0) {} 23 | 24 | constexpr Span(T* array, size_t length) noexcept 25 | : ptr_(array), len_(length) {} 26 | 27 | template 28 | explicit constexpr Span(T (&a)[N]) noexcept : Span(a, N) {} 29 | 30 | template 31 | explicit constexpr Span(const ArrayLike& other) noexcept 32 | : Span(reinterpret_cast(other.data()), other.size()) { 33 | static_assert(sizeof(*other.data()) == sizeof(T), 34 | "Incompatible type of source."); 35 | } 36 | 37 | constexpr T* data() const noexcept { return ptr_; } 38 | 39 | constexpr size_t size() const noexcept { return len_; } 40 | 41 | constexpr bool empty() const noexcept { return len_ == 0; } 42 | 43 | constexpr T& operator[](size_t i) const noexcept { 44 | // MSVC 2015 accepts this as constexpr, but not ptr_[i] 45 | return *(data() + i); 46 | } 47 | 48 | void remove_prefix(size_t n) noexcept { 49 | JXL_ASSERT(size() >= n); 50 | ptr_ += n; 51 | len_ -= n; 52 | } 53 | 54 | private: 55 | T* ptr_; 56 | size_t len_; 57 | }; 58 | 59 | } // namespace jxl 60 | 61 | #endif // ENCODER_BASE_SPAN_H_ 62 | -------------------------------------------------------------------------------- /encoder/chroma_from_luma.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #ifndef ENCODER_CHROMA_FROM_LUMA_H_ 8 | #define ENCODER_CHROMA_FROM_LUMA_H_ 9 | 10 | // Chroma-from-luma, computed using heuristics to determine the best linear 11 | // model for the X and B channels from the Y channel. 12 | 13 | #include 14 | #include 15 | 16 | #include "encoder/common.h" 17 | #include "encoder/image.h" 18 | 19 | namespace jxl { 20 | 21 | static constexpr float kInvColorFactor = 1.0f / 84; 22 | 23 | static inline float YtoXRatio(int8_t x) { return x * kInvColorFactor; } 24 | static inline float YtoBRatio(int8_t b) { return 1.0f + b * kInvColorFactor; } 25 | 26 | } // namespace jxl 27 | 28 | #endif // ENCODER_CHROMA_FROM_LUMA_H_ 29 | -------------------------------------------------------------------------------- /encoder/cjxl_main.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #include 8 | #include 9 | 10 | #include "encoder/base/printf_macros.h" 11 | #include "encoder/enc_file.h" 12 | #include "encoder/image.h" 13 | #include "encoder/read_pfm.h" 14 | 15 | namespace { 16 | struct CompressArgs { 17 | const char* file_in = nullptr; 18 | const char* file_out = nullptr; 19 | float distance = 1.0; 20 | }; 21 | 22 | bool WriteFile(const char* filename, const std::vector& bytes) { 23 | FILE* file = fopen(filename, "wb"); 24 | if (!file) { 25 | fprintf(stderr, "Could not open %s for writing\nError: %s", filename, 26 | strerror(errno)); 27 | return false; 28 | } 29 | if (fwrite(bytes.data(), 1, bytes.size(), file) != bytes.size()) { 30 | fprintf(stderr, "Could not write to file\nError: %s", strerror(errno)); 31 | return false; 32 | } 33 | if (fclose(file) != 0) { 34 | fprintf(stderr, "Could not close file\nError: %s", strerror(errno)); 35 | return false; 36 | } 37 | return true; 38 | } 39 | 40 | void PrintHelp(char* arg0) { 41 | fprintf(stderr, 42 | "Usage: %s [] [-d distance]\n\n" 43 | " NOTE: is a .pfm file in linear SRGB colorspace\n", 44 | arg0); 45 | } 46 | 47 | } // namespace 48 | 49 | int main(int argc, char** argv) { 50 | CompressArgs args; 51 | for (int i = 1; i < argc; i++) { 52 | if (!strcmp("-h", argv[i]) || !strcmp("--help", argv[i])) { 53 | PrintHelp(argv[0]); 54 | return EXIT_SUCCESS; 55 | } 56 | if (argv[i][0] == '-' && argv[i][1] == 'd') { 57 | char* arg = argv[i][2] != '\0' ? &argv[i][2] : argv[++i]; 58 | if (i == argc) { 59 | fprintf(stderr, "-d requires an argument\n"); 60 | return EXIT_FAILURE; 61 | } 62 | char* end; 63 | args.distance = static_cast(strtod(arg, &end)); 64 | if (*end != '\0') { 65 | fprintf(stderr, "Unable to interpret as float: %s\n", arg); 66 | return EXIT_FAILURE; 67 | } 68 | continue; 69 | } 70 | if (!args.file_in) { 71 | args.file_in = argv[i]; 72 | } else if (!args.file_out) { 73 | args.file_out = argv[i]; 74 | } 75 | } 76 | if (!args.file_in) { 77 | fprintf(stderr, "Missing input file.\n"); 78 | return EXIT_FAILURE; 79 | } 80 | jxl::Image3F image; 81 | if (!jxl::ReadPFM(args.file_in, &image)) { 82 | fprintf(stderr, "Error reading PFM input file.\n"); 83 | return EXIT_FAILURE; 84 | } 85 | fprintf(stderr, "Read %" PRIuS "x%" PRIuS " pixels input image.\n", 86 | image.xsize(), image.ysize()); 87 | 88 | std::vector output; 89 | if (!jxl::EncodeFile(image, args.distance, &output)) { 90 | fprintf(stderr, "Encoding failed.\n"); 91 | return EXIT_FAILURE; 92 | } 93 | fprintf(stderr, "Compressed to %" PRIuS " bytes.\n", output.size()); 94 | 95 | if (args.file_out && !WriteFile(args.file_out, output)) { 96 | fprintf(stderr, "Failed to write to output file %s\n", args.file_out); 97 | return EXIT_FAILURE; 98 | } 99 | 100 | return EXIT_SUCCESS; 101 | } 102 | -------------------------------------------------------------------------------- /encoder/common.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #ifndef ENCODER_COMMON_H_ 8 | #define ENCODER_COMMON_H_ 9 | 10 | // Shared constants and helper functions. 11 | 12 | #include 13 | #include 14 | 15 | #include "encoder/base/compiler_specific.h" 16 | #include "encoder/config.h" 17 | 18 | namespace jxl { 19 | 20 | constexpr size_t kBitsPerByte = 8; // more clear than CHAR_BIT 21 | 22 | template 23 | constexpr inline T1 DivCeil(T1 a, T2 b) { 24 | return (a + b - 1) / b; 25 | } 26 | 27 | // Works for any `align`; if a power of two, compiler emits ADD+AND. 28 | constexpr inline size_t RoundUpTo(size_t what, size_t align) { 29 | return DivCeil(what, align) * align; 30 | } 31 | 32 | // Block is the square grid of pixels to which an "energy compaction" 33 | // transformation (e.g. DCT) is applied. Each block has its own AC quantizer. 34 | constexpr size_t kBlockDim = 8; 35 | constexpr size_t kDCTBlockSize = kBlockDim * kBlockDim; 36 | constexpr size_t kGroupDim = 256; 37 | constexpr size_t kGroupDimInBlocks = kGroupDim / kBlockDim; 38 | constexpr size_t kDCGroupDim = kGroupDim * kBlockDim; 39 | constexpr size_t kColorTileDim = 64; 40 | #if OPTIMIZE_CHROMA_FROM_LUMA 41 | constexpr size_t kTileDim = kColorTileDim; 42 | #else 43 | constexpr size_t kTileDim = 16; 44 | #endif 45 | constexpr size_t kTileDimInBlocks = kTileDim / kBlockDim; 46 | constexpr size_t kGroupDimInTiles = kGroupDim / kTileDim; 47 | 48 | template 49 | JXL_INLINE T Clamp1(T val, T low, T hi) { 50 | return val < low ? low : val > hi ? hi : val; 51 | } 52 | 53 | // Encodes non-negative (X) into (2 * X), negative (-X) into (2 * X - 1) 54 | constexpr uint32_t PackSigned(int32_t value) 55 | JXL_NO_SANITIZE("unsigned-integer-overflow") { 56 | return (static_cast(value) << 1) ^ 57 | ((static_cast(~value) >> 31) - 1); 58 | } 59 | 60 | } // namespace jxl 61 | 62 | #endif // ENCODER_COMMON_H_ 63 | -------------------------------------------------------------------------------- /encoder/config.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #ifndef ENCODER_CONFIG_H_ 8 | #define ENCODER_CONFIG_H_ 9 | 10 | #define OPTIMIZE_CODE 1 11 | #define OPTIMIZE_CHROMA_FROM_LUMA 1 12 | #define OPTIMIZE_BLOCK_SIZES 1 13 | 14 | #endif // ENCODER_CONFIG_H_ 15 | -------------------------------------------------------------------------------- /encoder/dc_group_data.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #ifndef ENCODER_DC_GROUP_DATA_H_ 8 | #define ENCODER_DC_GROUP_DATA_H_ 9 | 10 | #include 11 | #include 12 | 13 | #include "encoder/ac_strategy.h" 14 | #include "encoder/common.h" 15 | #include "encoder/image.h" 16 | 17 | namespace jxl { 18 | 19 | struct DCGroupData { 20 | DCGroupData(size_t xsize_blocks, size_t ysize_blocks) 21 | : quant_dc(xsize_blocks, ysize_blocks), 22 | raw_quant_field(xsize_blocks, ysize_blocks), 23 | ac_strategy(xsize_blocks, ysize_blocks), 24 | ytox_map(DivCeil(xsize_blocks * kBlockDim, kColorTileDim), 25 | DivCeil(ysize_blocks * kBlockDim, kColorTileDim)), 26 | ytob_map(DivCeil(xsize_blocks * kBlockDim, kColorTileDim), 27 | DivCeil(ysize_blocks * kBlockDim, kColorTileDim)) { 28 | ac_strategy.FillDCT8(); 29 | ZeroFillImage(&ytox_map); 30 | ZeroFillImage(&ytob_map); 31 | } 32 | Image3S quant_dc; 33 | ImageB raw_quant_field; 34 | AcStrategyImage ac_strategy; 35 | ImageSB ytox_map; 36 | ImageSB ytob_map; 37 | }; 38 | 39 | } // namespace jxl 40 | 41 | #endif // ENCODER_DC_GROUP_DATA_H_ 42 | -------------------------------------------------------------------------------- /encoder/dct_scales.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #include "encoder/dct_scales.h" 8 | 9 | namespace jxl { 10 | 11 | // Definition of constexpr arrays. 12 | constexpr float DCTResampleScales<1, 8>::kScales[]; 13 | constexpr float DCTResampleScales<2, 16>::kScales[]; 14 | constexpr float DCTResampleScales<8, 1>::kScales[]; 15 | constexpr float DCTResampleScales<16, 2>::kScales[]; 16 | constexpr float WcMultipliers<4>::kMultipliers[]; 17 | constexpr float WcMultipliers<8>::kMultipliers[]; 18 | constexpr float WcMultipliers<16>::kMultipliers[]; 19 | 20 | } // namespace jxl 21 | -------------------------------------------------------------------------------- /encoder/dct_scales.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #ifndef ENCODER_DCT_SCALES_H_ 8 | #define ENCODER_DCT_SCALES_H_ 9 | 10 | // Scaling factors. 11 | 12 | #include 13 | 14 | namespace jxl { 15 | 16 | static constexpr float kSqrt2 = 1.41421356237f; 17 | 18 | // For n != 0, the n-th basis function of a N-DCT, evaluated in pixel k, has a 19 | // value of cos((k+1/2) n/(2N) pi). When downsampling by 2x, we average 20 | // the values for pixel k and k+1 to get the value for pixel (k/2), thus we get 21 | // 22 | // [cos((k+1/2) n/N pi) + cos((k+3/2) n/N pi)]/2 = 23 | // cos(n/(2N) pi) cos((k+1) n/N pi) = 24 | // cos(n/(2N) pi) cos(((k/2)+1/2) n/(N/2) pi) 25 | // 26 | // which is exactly the same as the value of pixel k/2 of a N/2-sized DCT, 27 | // except for the cos(n/(2N) pi) scaling factor (which does *not* 28 | // depend on the pixel). Thus, when using the lower-frequency coefficients of a 29 | // DCT-N to compute a DCT-(N/2), they should be scaled by this constant. Scaling 30 | // factors for a DCT-(N/4) etc can then be obtained by successive 31 | // multiplications. The structs below contain the above-mentioned scaling 32 | // factors. 33 | // 34 | // Python code for the tables below: 35 | // 36 | // for i in range(N // 8): 37 | // v = math.cos(i / (2 * N) * math.pi) 38 | // v *= math.cos(i / (N) * math.pi) 39 | // v *= math.cos(i / (N / 2) * math.pi) 40 | // print(v, end=", ") 41 | 42 | template 43 | struct DCTResampleScales; 44 | 45 | template <> 46 | struct DCTResampleScales<8, 1> { 47 | static constexpr float kScales[] = { 48 | 1.000000000000000000, 49 | }; 50 | }; 51 | 52 | template <> 53 | struct DCTResampleScales<16, 2> { 54 | static constexpr float kScales[] = { 55 | 1.000000000000000000, 56 | 0.901764195028874394, 57 | }; 58 | }; 59 | 60 | // Inverses of the above. 61 | template <> 62 | struct DCTResampleScales<1, 8> { 63 | static constexpr float kScales[] = { 64 | 1.000000000000000000, 65 | }; 66 | }; 67 | 68 | template <> 69 | struct DCTResampleScales<2, 16> { 70 | static constexpr float kScales[] = { 71 | 1.000000000000000000, 72 | 1.108937353592731823, 73 | }; 74 | }; 75 | 76 | // Constants for DCT implementation. Generated by the following snippet: 77 | // for i in range(N // 2): 78 | // print(1.0 / (2 * math.cos((i + 0.5) * math.pi / N)), end=", ") 79 | template 80 | struct WcMultipliers; 81 | 82 | template <> 83 | struct WcMultipliers<4> { 84 | static constexpr float kMultipliers[] = { 85 | 0.541196100146197, 86 | 1.3065629648763764, 87 | }; 88 | }; 89 | 90 | template <> 91 | struct WcMultipliers<8> { 92 | static constexpr float kMultipliers[] = { 93 | 0.5097955791041592, 94 | 0.6013448869350453, 95 | 0.8999762231364156, 96 | 2.5629154477415055, 97 | }; 98 | }; 99 | 100 | template <> 101 | struct WcMultipliers<16> { 102 | static constexpr float kMultipliers[] = { 103 | 0.5024192861881557, 0.5224986149396889, 0.5669440348163577, 104 | 0.6468217833599901, 0.7881546234512502, 1.060677685990347, 105 | 1.7224470982383342, 5.101148618689155, 106 | }; 107 | }; 108 | 109 | // Apply the DCT algorithm-intrinsic constants to DCTResampleScale. 110 | template 111 | constexpr float DCTTotalResampleScale(size_t x) { 112 | return DCTResampleScales::kScales[x]; 113 | } 114 | 115 | } // namespace jxl 116 | 117 | #endif // ENCODER_DCT_SCALES_H_ 118 | -------------------------------------------------------------------------------- /encoder/enc_ac_strategy.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #ifndef ENCODER_ENC_AC_STRATEGY_H_ 8 | #define ENCODER_ENC_AC_STRATEGY_H_ 9 | 10 | #include "encoder/ac_strategy.h" 11 | #include "encoder/base/status.h" 12 | #include "encoder/image.h" 13 | #include "encoder/quant_weights.h" 14 | 15 | namespace jxl { 16 | 17 | void FindBest16x16Transform(const Image3F& opsin, const Rect& block_rect, 18 | size_t bx, size_t by, size_t cx, size_t cy, 19 | float distance, const DequantMatrices& matrices, 20 | const ImageF& qf, const ImageF& maskf, int8_t ytox, 21 | int8_t ytob, 22 | AcStrategyImage* JXL_RESTRICT ac_strategy, 23 | float* block, float* scratch_space); 24 | 25 | void AdjustQuantField(const AcStrategyImage& ac_strategy, 26 | const Rect& block_rect, ImageB* quant_field); 27 | 28 | } // namespace jxl 29 | 30 | #endif // ENCODER_ENC_AC_STRATEGY_H_ 31 | -------------------------------------------------------------------------------- /encoder/enc_adaptive_quantization.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #ifndef ENCODER_ENC_ADAPTIVE_QUANTIZATION_H_ 8 | #define ENCODER_ENC_ADAPTIVE_QUANTIZATION_H_ 9 | 10 | #include "encoder/image.h" 11 | 12 | namespace jxl { 13 | 14 | void ComputeAdaptiveQuantFieldTile(const Image3F& xyb, const Rect& rect, 15 | const Rect& block_rect, float inv_scale, 16 | float distance, ImageF* pre_erosion, 17 | float* diff_buffer, ImageF* aq_map, 18 | ImageF* mask, ImageB* raw_quant_field); 19 | 20 | } // namespace jxl 21 | 22 | #endif // ENCODER_ENC_ADAPTIVE_QUANTIZATION_H_ 23 | -------------------------------------------------------------------------------- /encoder/enc_bit_writer.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #include "encoder/enc_bit_writer.h" 8 | 9 | #include // memcpy 10 | 11 | #include "encoder/base/byte_order.h" 12 | 13 | namespace jxl { 14 | 15 | BitWriter::Allotment::Allotment(BitWriter* JXL_RESTRICT writer, size_t max_bits) 16 | : max_bits_(max_bits) { 17 | if (writer == nullptr) return; 18 | prev_bits_written_ = writer->BitsWritten(); 19 | const size_t prev_bytes = writer->storage_.size(); 20 | const size_t next_bytes = DivCeil(max_bits, kBitsPerByte); 21 | writer->storage_.resize(prev_bytes + next_bytes); 22 | parent_ = writer->current_allotment_; 23 | writer->current_allotment_ = this; 24 | } 25 | 26 | BitWriter::Allotment::~Allotment() { 27 | if (!called_) { 28 | // Not calling is a bug - unused storage will not be reclaimed. 29 | JXL_ABORT("Did not call Allotment::ReclaimUnused"); 30 | } 31 | } 32 | 33 | void BitWriter::Allotment::PrivateReclaim(BitWriter* JXL_RESTRICT writer, 34 | size_t* JXL_RESTRICT used_bits, 35 | size_t* JXL_RESTRICT unused_bits) { 36 | JXL_ASSERT(!called_); // Do not call twice 37 | called_ = true; 38 | if (writer == nullptr) return; 39 | 40 | JXL_ASSERT(writer->BitsWritten() >= prev_bits_written_); 41 | *used_bits = writer->BitsWritten() - prev_bits_written_; 42 | JXL_ASSERT(*used_bits <= max_bits_); 43 | *unused_bits = max_bits_ - *used_bits; 44 | 45 | // Reclaim unused bytes whole bytes from writer's allotment. 46 | const size_t unused_bytes = *unused_bits / kBitsPerByte; // truncate 47 | JXL_ASSERT(writer->storage_.size() >= unused_bytes); 48 | writer->storage_.resize(writer->storage_.size() - unused_bytes); 49 | writer->current_allotment_ = parent_; 50 | // Ensure we don't also charge the parent for these bits. 51 | auto parent = parent_; 52 | while (parent != nullptr) { 53 | parent->prev_bits_written_ += *used_bits; 54 | parent = parent->parent_; 55 | } 56 | } 57 | 58 | void BitWriter::AppendByteAligned(std::vector* others) { 59 | // Total size to add so we can preallocate 60 | size_t other_bytes = 0; 61 | for (const BitWriter& writer : *others) { 62 | other_bytes += DivCeil(writer.BitsWritten(), kBitsPerByte); 63 | } 64 | if (other_bytes == 0) { 65 | // No bytes to append: this happens for example when creating per-group 66 | // storage for groups, but not writing anything in them for e.g. lossless 67 | // images with no alpha. Do nothing. 68 | return; 69 | } 70 | storage_.resize(storage_.size() + other_bytes + 1); // extra zero padding 71 | 72 | // Concatenate by copying bytes because both source and destination are bytes. 73 | JXL_ASSERT(BitsWritten() % kBitsPerByte == 0); 74 | size_t pos = BitsWritten() / kBitsPerByte; 75 | for (BitWriter& writer : *others) { 76 | BitWriter::Allotment allotment(&writer, 8); 77 | writer.ZeroPadToByte(); 78 | allotment.Reclaim(&writer); 79 | const Span span = writer.GetSpan(); 80 | if (!span.empty()) { 81 | memcpy(storage_.data() + pos, span.data(), span.size()); 82 | pos += span.size(); 83 | } 84 | } 85 | storage_[pos++] = 0; // for next Write 86 | JXL_ASSERT(pos <= storage_.size()); 87 | bits_written_ += other_bytes * kBitsPerByte; 88 | } 89 | 90 | void BitWriter::Append(const BitWriter& other) { 91 | // Total size to add so we can preallocate 92 | size_t other_bytes = DivCeil(other.BitsWritten(), kBitsPerByte); 93 | if (other_bytes == 0) { 94 | return; 95 | } 96 | storage_.resize(storage_.size() + other_bytes + 1); // extra zero padding 97 | 98 | size_t other_full_bytes = other.BitsWritten() / kBitsPerByte; 99 | size_t other_trailing_bits = other.BitsWritten() % kBitsPerByte; 100 | for (size_t i = 0; i < other_full_bytes; ++i) { 101 | Write(8, other.storage_[i]); 102 | } 103 | if (other_trailing_bits > 0) { 104 | uint64_t last_byte = other.storage_[other_full_bytes]; 105 | uint64_t last_byte_mask = (1u << other_trailing_bits) - 1; 106 | Write(other_trailing_bits, last_byte & last_byte_mask); 107 | } 108 | } 109 | 110 | // Example: let's assume that 3 bits (Rs below) have been written already: 111 | // BYTE+0 BYTE+1 BYTE+2 112 | // 0000 0RRR ???? ???? ???? ???? 113 | // 114 | // Now, we could write up to 5 bits by just shifting them left by 3 bits and 115 | // OR'ing to BYTE-0. 116 | // 117 | // For n > 5 bits, we write the lowest 5 bits as above, then write the next 118 | // lowest bits into BYTE+1 starting from its lower bits and so on. 119 | void BitWriter::Write(size_t n_bits, uint64_t bits) { 120 | JXL_DASSERT((bits >> n_bits) == 0); 121 | JXL_DASSERT(n_bits <= kMaxBitsPerCall); 122 | uint8_t* p = &storage_[bits_written_ / kBitsPerByte]; 123 | const size_t bits_in_first_byte = bits_written_ % kBitsPerByte; 124 | bits <<= bits_in_first_byte; 125 | #if JXL_BYTE_ORDER_LITTLE 126 | uint64_t v = *p; 127 | // Last (partial) or next byte to write must be zero-initialized! 128 | // PaddedBytes initializes the first, and Write/Append maintain this. 129 | JXL_DASSERT(v >> bits_in_first_byte == 0); 130 | v |= bits; 131 | memcpy(p, &v, sizeof(v)); // Write bytes: possibly more than n_bits/8 132 | #else 133 | *p++ |= static_cast(bits & 0xFF); 134 | for (size_t bits_left_to_write = n_bits + bits_in_first_byte; 135 | bits_left_to_write >= 9; bits_left_to_write -= 8) { 136 | bits >>= 8; 137 | *p++ = static_cast(bits & 0xFF); 138 | } 139 | *p = 0; 140 | #endif 141 | bits_written_ += n_bits; 142 | } 143 | 144 | } // namespace jxl 145 | -------------------------------------------------------------------------------- /encoder/enc_bit_writer.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #ifndef LIB_JXL_ENC_BIT_WRITER_H_ 8 | #define LIB_JXL_ENC_BIT_WRITER_H_ 9 | 10 | // BitWriter class: unbuffered writes using unaligned 64-bit stores. 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | #include "encoder/base/compiler_specific.h" 19 | #include "encoder/base/padded_bytes.h" 20 | #include "encoder/base/span.h" 21 | #include "encoder/base/status.h" 22 | #include "encoder/common.h" 23 | 24 | namespace jxl { 25 | 26 | constexpr inline size_t RoundUpBitsToByteMultiple(size_t bits) { 27 | return (bits + 7) & ~size_t(7); 28 | } 29 | 30 | struct BitWriter { 31 | // Upper bound on `n_bits` in each call to Write. We shift a 64-bit word by 32 | // 7 bits (max already valid bits in the last byte) and at least 1 bit is 33 | // needed to zero-initialize the bit-stream ahead (i.e. if 7 bits are valid 34 | // and we write 57 bits, then the next write will access a byte that was not 35 | // yet zero-initialized). 36 | static constexpr size_t kMaxBitsPerCall = 56; 37 | 38 | BitWriter() : bits_written_(0) {} 39 | 40 | // Disallow copying - may lead to bugs. 41 | BitWriter(const BitWriter&) = delete; 42 | BitWriter& operator=(const BitWriter&) = delete; 43 | BitWriter(BitWriter&&) = default; 44 | BitWriter& operator=(BitWriter&&) = default; 45 | 46 | size_t BitsWritten() const { return bits_written_; } 47 | 48 | Span GetSpan() const { 49 | // Callers must ensure byte alignment to avoid uninitialized bits. 50 | JXL_ASSERT(bits_written_ % kBitsPerByte == 0); 51 | return Span(storage_.data(), bits_written_ / kBitsPerByte); 52 | } 53 | 54 | // Example usage: bytes = std::move(writer).TakeBytes(); Useful for the 55 | // top-level encoder which returns PaddedBytes, not a BitWriter. 56 | // *this must be an rvalue reference and is invalid afterwards. 57 | PaddedBytes&& TakeBytes() && { 58 | // Callers must ensure byte alignment to avoid uninitialized bits. 59 | JXL_ASSERT(bits_written_ % kBitsPerByte == 0); 60 | storage_.resize(bits_written_ / kBitsPerByte); 61 | return std::move(storage_); 62 | } 63 | 64 | public: 65 | void Append(const BitWriter& other); 66 | void AppendByteAligned(std::vector* others); 67 | 68 | class Allotment { 69 | public: 70 | // Expands a BitWriter's storage. Must happen before calling Write or 71 | // ZeroPadToByte. Must call ReclaimUnused after writing to reclaim the 72 | // unused storage so that BitWriter memory use remains tightly bounded. 73 | Allotment(BitWriter* JXL_RESTRICT writer, size_t max_bits); 74 | ~Allotment(); 75 | 76 | void PrivateReclaim(BitWriter* JXL_RESTRICT writer, 77 | size_t* JXL_RESTRICT used_bits, 78 | size_t* JXL_RESTRICT unused_bits); 79 | 80 | void Reclaim(BitWriter* writer) { 81 | size_t used, unused; 82 | PrivateReclaim(writer, &used, &unused); 83 | } 84 | 85 | private: 86 | size_t prev_bits_written_; 87 | const size_t max_bits_; 88 | bool called_ = false; 89 | Allotment* parent_; 90 | }; 91 | 92 | // Writes bits into bytes in increasing addresses, and within a byte 93 | // least-significant-bit first. 94 | // 95 | // The function can write up to 56 bits in one go. 96 | void Write(size_t n_bits, uint64_t bits); 97 | 98 | void AllocateAndWrite(size_t n_bits, uint64_t bits) { 99 | Allotment allotment(this, n_bits); 100 | Write(n_bits, bits); 101 | allotment.Reclaim(this); 102 | } 103 | 104 | // This should only rarely be used - e.g. when the current location will be 105 | // referenced via byte offset (TOCs point to groups), or byte-aligned reading 106 | // is required for speed. 107 | void ZeroPadToByte() { 108 | const size_t remainder_bits = 109 | RoundUpBitsToByteMultiple(bits_written_) - bits_written_; 110 | if (remainder_bits == 0) return; 111 | Write(remainder_bits, 0); 112 | JXL_ASSERT(bits_written_ % kBitsPerByte == 0); 113 | } 114 | 115 | private: 116 | size_t bits_written_; 117 | PaddedBytes storage_; 118 | Allotment* current_allotment_ = nullptr; 119 | }; 120 | 121 | } // namespace jxl 122 | 123 | #endif // LIB_JXL_ENC_BIT_WRITER_H_ 124 | -------------------------------------------------------------------------------- /encoder/enc_chroma_from_luma.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #ifndef ENCODER_ENC_CHROMA_FROM_LUMA_H_ 8 | #define ENCODER_ENC_CHROMA_FROM_LUMA_H_ 9 | 10 | // Chroma-from-luma, computed using heuristics to determine the best linear 11 | // model for the X and B channels from the Y channel. 12 | 13 | #include "encoder/base/status.h" 14 | #include "encoder/image.h" 15 | #include "encoder/quant_weights.h" 16 | 17 | namespace jxl { 18 | 19 | void ComputeCmapTile(const Image3F& opsin, const Rect& tile_brect, 20 | const DequantMatrices& dequant, int8_t* ytox, int8_t* ytob, 21 | float* block_storage, float* scratch_space, 22 | float* coeff_storage); 23 | 24 | } // namespace jxl 25 | 26 | #endif // ENCODER_ENC_CHROMA_FROM_LUMA_H_ 27 | -------------------------------------------------------------------------------- /encoder/enc_cluster.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #include "encoder/enc_cluster.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "encoder/enc_huffman_tree.h" 14 | 15 | namespace jxl { 16 | namespace { 17 | 18 | void HistogramBitCost(const Histogram& a) { 19 | a.bit_cost = 0; 20 | if (a.total_count == 0) return; 21 | uint8_t depths[kAlphabetSize] = {}; 22 | CreateHuffmanTree(a.counts, kAlphabetSize, 15, depths); 23 | for (size_t i = 0; i < kAlphabetSize; ++i) { 24 | a.bit_cost += a.counts[i] * depths[i]; 25 | } 26 | } 27 | 28 | float HistogramDistance(const Histogram& a, const Histogram& b) { 29 | if (a.total_count == 0 || b.total_count == 0) return 0; 30 | Histogram combined; 31 | combined.AddHistogram(a); 32 | combined.AddHistogram(b); 33 | HistogramBitCost(combined); 34 | return combined.bit_cost - a.bit_cost - b.bit_cost; 35 | } 36 | 37 | // First step of a k-means clustering with a fancy distance metric. 38 | void FastClusterHistograms(const std::vector& in, 39 | size_t max_histograms, std::vector* out, 40 | std::vector* histogram_symbols) { 41 | out->clear(); 42 | out->reserve(max_histograms); 43 | histogram_symbols->clear(); 44 | histogram_symbols->resize(in.size(), max_histograms); 45 | 46 | std::vector dists(in.size(), std::numeric_limits::max()); 47 | size_t largest_idx = 0; 48 | for (size_t i = 0; i < in.size(); i++) { 49 | if (in[i].total_count == 0) { 50 | (*histogram_symbols)[i] = 0; 51 | dists[i] = 0.0f; 52 | continue; 53 | } 54 | HistogramBitCost(in[i]); 55 | if (in[i].total_count > in[largest_idx].total_count) { 56 | largest_idx = i; 57 | } 58 | } 59 | 60 | constexpr float kMinDistanceForDistinct = 64.0f; 61 | while (out->size() < max_histograms) { 62 | (*histogram_symbols)[largest_idx] = out->size(); 63 | out->push_back(in[largest_idx]); 64 | dists[largest_idx] = 0.0f; 65 | largest_idx = 0; 66 | for (size_t i = 0; i < in.size(); i++) { 67 | if (dists[i] == 0.0f) continue; 68 | float dist = HistogramDistance(in[i], out->back()); 69 | dists[i] = std::min(dist, dists[i]); 70 | if (dists[i] > dists[largest_idx]) largest_idx = i; 71 | } 72 | if (dists[largest_idx] < kMinDistanceForDistinct) break; 73 | } 74 | 75 | for (size_t i = 0; i < in.size(); i++) { 76 | if ((*histogram_symbols)[i] != max_histograms) continue; 77 | size_t best = 0; 78 | float best_dist = HistogramDistance(in[i], (*out)[best]); 79 | for (size_t j = 1; j < out->size(); j++) { 80 | float dist = HistogramDistance(in[i], (*out)[j]); 81 | if (dist < best_dist) { 82 | best = j; 83 | best_dist = dist; 84 | } 85 | } 86 | (*out)[best].AddHistogram(in[i]); 87 | HistogramBitCost((*out)[best]); 88 | (*histogram_symbols)[i] = best; 89 | } 90 | } 91 | 92 | // ----------------------------------------------------------------------------- 93 | // Histogram refinement 94 | 95 | // Reorder histograms in *out so that the new symbols in *symbols come in 96 | // increasing order. 97 | void HistogramReindex(const std::vector& symbols, 98 | std::vector* out, 99 | std::vector* context_map) { 100 | std::vector tmp(*out); 101 | std::map new_index; 102 | int next_index = 0; 103 | for (uint32_t symbol : symbols) { 104 | if (new_index.find(symbol) == new_index.end()) { 105 | new_index[symbol] = next_index; 106 | (*out)[next_index] = tmp[symbol]; 107 | ++next_index; 108 | } 109 | } 110 | out->resize(next_index); 111 | context_map->resize(symbols.size()); 112 | for (size_t i = 0; i < symbols.size(); ++i) { 113 | (*context_map)[i] = static_cast(new_index[symbols[i]]); 114 | } 115 | } 116 | 117 | } // namespace 118 | 119 | void ClusterHistograms(std::vector* histograms, 120 | std::vector* context_map) { 121 | if (histograms->size() <= 1) return; 122 | static const size_t kClustersLimit = 8; 123 | size_t max_histograms = std::min(kClustersLimit, histograms->size()); 124 | 125 | std::vector in(*histograms); 126 | std::vector histogram_symbols; 127 | FastClusterHistograms(in, max_histograms, histograms, &histogram_symbols); 128 | 129 | // Convert the context map to a canonical form. 130 | HistogramReindex(histogram_symbols, histograms, context_map); 131 | } 132 | 133 | } // namespace jxl 134 | -------------------------------------------------------------------------------- /encoder/enc_cluster.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | // Functions for clustering similar histograms together. 8 | 9 | #ifndef ENCODER_ENC_CLUSTER_H_ 10 | #define ENCODER_ENC_CLUSTER_H_ 11 | 12 | #include 13 | 14 | #include 15 | 16 | #include "encoder/histogram.h" 17 | 18 | namespace jxl { 19 | 20 | void ClusterHistograms(std::vector* histograms, 21 | std::vector* context_map); 22 | } // namespace jxl 23 | 24 | #endif // ENCODER_ENC_CLUSTER_H_ 25 | -------------------------------------------------------------------------------- /encoder/enc_entropy_code.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #ifndef ENCODER_ENC_ENTROPY_CODE_H_ 8 | #define ENCODER_ENC_ENTROPY_CODE_H_ 9 | 10 | #include 11 | #include 12 | 13 | #include "encoder/enc_bit_writer.h" 14 | #include "encoder/entropy_code.h" 15 | #include "encoder/histogram.h" 16 | #include "encoder/token.h" 17 | 18 | namespace jxl { 19 | 20 | void OptimizePrefixCodes(const std::vector& tokens, EntropyCode* code); 21 | 22 | void OptimizeEntropyCode(const std::vector& tokens, EntropyCode* code); 23 | 24 | void OptimizeEntropyCode(std::vector* histograms, EntropyCode* code); 25 | 26 | void WriteContextMap(const EntropyCode& code, BitWriter* writer); 27 | 28 | void WriteEntropyCode(const EntropyCode& code, BitWriter* writer); 29 | 30 | // This is an upper bound on the average bits per token on an array of 31 | // at most 256x256 entropy coded tokens. 32 | static constexpr size_t kMaxBitsPerToken = 24; 33 | 34 | static inline void WriteToken(const Token& token, const EntropyCode& code, 35 | BitWriter* writer) { 36 | uint32_t tok, nbits, bits; 37 | UintCoder().Encode(token.value, &tok, &nbits, &bits); 38 | const PrefixCode& pc = code.prefix_codes[code.context_map[token.context]]; 39 | uint64_t data = pc.bits[tok]; 40 | data |= bits << pc.depths[tok]; 41 | writer->Write(pc.depths[tok] + nbits, data); 42 | } 43 | 44 | } // namespace jxl 45 | #endif // ENCODER_ENC_ENTROPY_CODE_H_ 46 | -------------------------------------------------------------------------------- /encoder/enc_file.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #include "encoder/enc_file.h" 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include "encoder/base/data_parallel.h" 15 | #include "encoder/enc_bit_writer.h" 16 | #include "encoder/enc_frame.h" 17 | #include "encoder/image.h" 18 | 19 | namespace jxl { 20 | 21 | namespace { 22 | 23 | // Reserved by ISO/IEC 10918-1. LF causes files opened in text mode to be 24 | // rejected because the marker changes to 0x0D instead. The 0xFF prefix also 25 | // ensures there were no 7-bit transmission limitations. 26 | static constexpr uint8_t kCodestreamMarker = 0x0A; 27 | 28 | void WriteSize(uint32_t size, BitWriter* writer) { 29 | size -= 1; 30 | uint32_t kBits[4] = {9, 13, 18, 30}; 31 | for (size_t i = 0; i < 4; ++i) { 32 | if (size < (1u << kBits[i])) { 33 | writer->Write(2, i); 34 | writer->Write(kBits[i], size); 35 | return; 36 | } 37 | } 38 | } 39 | 40 | Status WriteSizeHeader(size_t xsize64, size_t ysize64, BitWriter* writer) { 41 | if (xsize64 > 0x3FFFFFFFull || ysize64 > 0x3FFFFFFFull) { 42 | return JXL_FAILURE("Image too large"); 43 | } 44 | const uint32_t xsize32 = static_cast(xsize64); 45 | const uint32_t ysize32 = static_cast(ysize64); 46 | writer->Write(1, 0); // small 47 | WriteSize(ysize32, writer); 48 | writer->Write(3, 0); // ratio 49 | WriteSize(xsize32, writer); 50 | return true; 51 | } 52 | 53 | } // namespace 54 | 55 | bool EncodeFile(const Image3F& input, float distance, 56 | std::vector* output) { 57 | if (distance < 0.0) { 58 | return JXL_FAILURE("Invalid butteraugli distance (%f)", distance); 59 | } else if (distance == 0.0) { 60 | return JXL_FAILURE("Lossless compression is not supported."); 61 | } else if (distance <= 0.03) { 62 | // Distance where the average BPP is still slightly smaller on photographs 63 | // than for lossless JPEG XL. 64 | distance = 0.03; 65 | } 66 | if (input.xsize() == 0 || input.ysize() == 0) { 67 | return JXL_FAILURE("Empty image"); 68 | } 69 | 70 | BitWriter writer; 71 | BitWriter::Allotment allotment(&writer, 1024); 72 | writer.Write(8, 0xFF); 73 | writer.Write(8, kCodestreamMarker); 74 | JXL_RETURN_IF_ERROR(WriteSizeHeader(input.xsize(), input.ysize(), &writer)); 75 | writer.Write(1, 0); // not all default image metadata 76 | writer.Write(1, 0); // no extra fields in image metadata 77 | writer.Write(1, 1); // floating point samples 78 | writer.Write(2, 0); // 32 bits per sample 79 | writer.Write(4, 7); // 8 exponent bits per sample 80 | writer.Write(1, 0); // modular 16 bit sufficient 81 | writer.Write(2, 0); // no extra channels 82 | writer.Write(1, 1); // xyb encoded 83 | writer.Write(1, 0); // not all default color encoding 84 | writer.Write(1, 0); // no icc 85 | writer.Write(2, 0); // RGB color space 86 | writer.Write(2, 1); // D65 white point 87 | writer.Write(2, 1); // SRGB primaries 88 | writer.Write(1, 0); // no gamma 89 | writer.Write(2, 2); // transfer function selector bits (2 .. 17) 90 | writer.Write(4, 6); // linear transfer function (enum value 8) 91 | writer.Write(2, 1); // relative rendering intent 92 | writer.Write(2, 0); // no extensions 93 | writer.Write(1, 1); // all default transform data 94 | writer.ZeroPadToByte(); 95 | allotment.Reclaim(&writer); 96 | 97 | ThreadPool pool; 98 | JXL_RETURN_IF_ERROR(EncodeFrame(distance, input, &pool, &writer)); 99 | 100 | PaddedBytes compressed; 101 | compressed = std::move(writer).TakeBytes(); 102 | output->assign(compressed.data(), compressed.data() + compressed.size()); 103 | 104 | return true; 105 | } 106 | 107 | } // namespace jxl 108 | -------------------------------------------------------------------------------- /encoder/enc_file.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #ifndef ENCODER_ENC_FILE_H_ 8 | #define ENCODER_ENC_FILE_H_ 9 | 10 | #include 11 | 12 | #include 13 | 14 | #include "encoder/image.h" 15 | 16 | namespace jxl { 17 | 18 | // Input is in linear sRGB colorspace, individual sample values can be outside 19 | // the [0.0, 1.0] range for out-of-gammut colors. 20 | bool EncodeFile(const Image3F& input, float distance, 21 | std::vector* output); 22 | 23 | } // namespace jxl 24 | 25 | #endif // ENCODER_ENC_FILE_H_ 26 | -------------------------------------------------------------------------------- /encoder/enc_frame.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #ifndef ENCODER_ENC_FRAME_H_ 8 | #define ENCODER_ENC_FRAME_H_ 9 | 10 | #include "encoder/base/data_parallel.h" 11 | #include "encoder/base/status.h" 12 | #include "encoder/enc_bit_writer.h" 13 | #include "encoder/image.h" 14 | 15 | namespace jxl { 16 | 17 | // Encodes a single frame (including its header) into a byte stream. 18 | // Groups may be processed in parallel by `pool`. 19 | Status EncodeFrame(const float distance, const Image3F& linear, 20 | ThreadPool* pool, BitWriter* writer); 21 | 22 | } // namespace jxl 23 | 24 | #endif // ENCODER_ENC_FRAME_H_ 25 | -------------------------------------------------------------------------------- /encoder/enc_group.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #ifndef ENCODER_ENC_GROUP_H_ 8 | #define ENCODER_ENC_GROUP_H_ 9 | 10 | #include 11 | 12 | #include "encoder/ac_strategy.h" 13 | #include "encoder/dc_group_data.h" 14 | #include "encoder/enc_bit_writer.h" 15 | #include "encoder/entropy_code.h" 16 | #include "encoder/image.h" 17 | #include "encoder/quant_weights.h" 18 | 19 | namespace jxl { 20 | 21 | struct GroupProcessorMemory { 22 | GroupProcessorMemory() { 23 | mem_dct = hwy::AllocateAligned(kMaxCoeffArea * 4); 24 | mem_coeff = hwy::AllocateAligned(kMaxCoeffArea * 3); 25 | } 26 | float* block_storage() { return mem_dct.get(); } 27 | float* scratch_space() { return mem_dct.get() + 3 * kMaxCoeffArea; } 28 | int32_t* coeff_storage() { return mem_coeff.get(); } 29 | hwy::AlignedFreeUniquePtr mem_dct; 30 | hwy::AlignedFreeUniquePtr mem_coeff; 31 | }; 32 | 33 | void WriteACGroup(const Image3F& opsin, const Rect& group_brect, 34 | const DequantMatrices& matrices, const float scale, 35 | const float scale_dc, const uint32_t x_qm_scale, 36 | DCGroupData* dc_data, const EntropyCode& ac_code, 37 | Image3B* num_nzeros, GroupProcessorMemory* mem, 38 | BitWriter* writer); 39 | 40 | } // namespace jxl 41 | 42 | #endif // ENCODER_ENC_GROUP_H_ 43 | -------------------------------------------------------------------------------- /encoder/enc_huffman_tree.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | #include "encoder/enc_huffman_tree.h" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "encoder/base/compiler_specific.h" 13 | #include "encoder/base/status.h" 14 | 15 | namespace jxl { 16 | 17 | namespace { 18 | // A node of a Huffman tree. 19 | struct HuffmanTree { 20 | HuffmanTree(uint32_t count, int16_t left, int16_t right) 21 | : total_count(count), index_left(left), index_right_or_value(right) {} 22 | uint32_t total_count; 23 | int16_t index_left; 24 | int16_t index_right_or_value; 25 | }; 26 | 27 | void SetDepth(const HuffmanTree& p, HuffmanTree* pool, uint8_t* depth, 28 | uint8_t level) { 29 | if (p.index_left >= 0) { 30 | ++level; 31 | SetDepth(pool[p.index_left], pool, depth, level); 32 | SetDepth(pool[p.index_right_or_value], pool, depth, level); 33 | } else { 34 | depth[p.index_right_or_value] = level; 35 | } 36 | } 37 | 38 | // Sort the root nodes, least popular first. 39 | static JXL_INLINE bool Compare(const HuffmanTree& v0, const HuffmanTree& v1) { 40 | return v0.total_count < v1.total_count; 41 | } 42 | } // namespace 43 | 44 | // This function will create a Huffman tree. 45 | // 46 | // The (data,length) contains the population counts. 47 | // The tree_limit is the maximum bit depth of the Huffman codes. 48 | // 49 | // The depth contains the tree, i.e., how many bits are used for 50 | // the symbol. 51 | // 52 | // The catch here is that the tree cannot be arbitrarily deep. 53 | // Brotli specifies a maximum depth of 15 bits for "code trees" 54 | // and 7 bits for "code length code trees." 55 | // 56 | // count_limit is the value that is to be faked as the minimum value 57 | // and this minimum value is raised until the tree matches the 58 | // maximum length requirement. 59 | // 60 | // This algorithm is not of excellent performance for very long data blocks, 61 | // especially when population counts are longer than 2**tree_limit, but 62 | // we are not planning to use this with extremely long blocks. 63 | // 64 | // See http://en.wikipedia.org/wiki/Huffman_coding 65 | void CreateHuffmanTree(const uint32_t* data, const size_t length, 66 | const int tree_limit, uint8_t* depth) { 67 | // For block sizes below 64 kB, we never need to do a second iteration 68 | // of this loop. Probably all of our block sizes will be smaller than 69 | // that, so this loop is mostly of academic interest. If we actually 70 | // would need this, we would be better off with the Katajainen algorithm. 71 | for (uint32_t count_limit = 1;; count_limit *= 2) { 72 | std::vector tree; 73 | tree.reserve(2 * length + 1); 74 | 75 | for (size_t i = length; i != 0;) { 76 | --i; 77 | if (data[i]) { 78 | const uint32_t count = std::max(data[i], count_limit - 1); 79 | tree.emplace_back(count, -1, static_cast(i)); 80 | } 81 | } 82 | 83 | const size_t n = tree.size(); 84 | if (n == 1) { 85 | // Fake value; will be fixed on upper level. 86 | depth[tree[0].index_right_or_value] = 1; 87 | break; 88 | } 89 | 90 | std::stable_sort(tree.begin(), tree.end(), Compare); 91 | 92 | // The nodes are: 93 | // [0, n): the sorted leaf nodes that we start with. 94 | // [n]: we add a sentinel here. 95 | // [n + 1, 2n): new parent nodes are added here, starting from 96 | // (n+1). These are naturally in ascending order. 97 | // [2n]: we add a sentinel at the end as well. 98 | // There will be (2n+1) elements at the end. 99 | const HuffmanTree sentinel(std::numeric_limits::max(), -1, -1); 100 | tree.push_back(sentinel); 101 | tree.push_back(sentinel); 102 | 103 | size_t i = 0; // Points to the next leaf node. 104 | size_t j = n + 1; // Points to the next non-leaf node. 105 | for (size_t k = n - 1; k != 0; --k) { 106 | size_t left, right; 107 | if (tree[i].total_count <= tree[j].total_count) { 108 | left = i; 109 | ++i; 110 | } else { 111 | left = j; 112 | ++j; 113 | } 114 | if (tree[i].total_count <= tree[j].total_count) { 115 | right = i; 116 | ++i; 117 | } else { 118 | right = j; 119 | ++j; 120 | } 121 | 122 | // The sentinel node becomes the parent node. 123 | size_t j_end = tree.size() - 1; 124 | tree[j_end].total_count = 125 | tree[left].total_count + tree[right].total_count; 126 | tree[j_end].index_left = static_cast(left); 127 | tree[j_end].index_right_or_value = static_cast(right); 128 | 129 | // Add back the last sentinel node. 130 | tree.push_back(sentinel); 131 | } 132 | JXL_DASSERT(tree.size() == 2 * n + 1); 133 | SetDepth(tree[2 * n - 1], &tree[0], depth, 0); 134 | 135 | // We need to pack the Huffman tree in tree_limit bits. 136 | // If this was not successful, add fake entities to the lowest values 137 | // and retry. 138 | if (*std::max_element(&depth[0], &depth[length]) <= tree_limit) { 139 | break; 140 | } 141 | } 142 | } 143 | 144 | } // namespace jxl 145 | -------------------------------------------------------------------------------- /encoder/enc_huffman_tree.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | // Library for creating Huffman codes from population counts. 7 | 8 | #ifndef ENCODER_ENC_HUFFMAN_TREE_H_ 9 | #define ENCODER_ENC_HUFFMAN_TREE_H_ 10 | 11 | #include 12 | #include 13 | 14 | namespace jxl { 15 | 16 | // This function will create a Huffman tree. 17 | // 18 | // The (data,length) contains the population counts. 19 | // The tree_limit is the maximum bit depth of the Huffman codes. 20 | // 21 | // The depth contains the tree, i.e., how many bits are used for 22 | // the symbol. 23 | // 24 | // See http://en.wikipedia.org/wiki/Huffman_coding 25 | void CreateHuffmanTree(const uint32_t* data, const size_t length, 26 | const int tree_limit, uint8_t* depth); 27 | 28 | } // namespace jxl 29 | #endif // ENCODER_ENC_HUFFMAN_TREE_H_ 30 | -------------------------------------------------------------------------------- /encoder/enc_xyb.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #include "encoder/enc_xyb.h" 8 | 9 | #undef HWY_TARGET_INCLUDE 10 | #define HWY_TARGET_INCLUDE "encoder/enc_xyb.cc" 11 | #include 12 | #include 13 | 14 | #include "encoder/base/compiler_specific.h" 15 | #include "encoder/fast_math-inl.h" 16 | #include "encoder/image.h" 17 | 18 | HWY_BEFORE_NAMESPACE(); 19 | namespace jxl { 20 | namespace HWY_NAMESPACE { 21 | 22 | // These templates are not found via ADL. 23 | using hwy::HWY_NAMESPACE::Add; 24 | using hwy::HWY_NAMESPACE::Mul; 25 | using hwy::HWY_NAMESPACE::MulAdd; 26 | using hwy::HWY_NAMESPACE::Sub; 27 | using hwy::HWY_NAMESPACE::ZeroIfNegative; 28 | 29 | // Parameters for opsin absorbance. 30 | static const float kM02 = 0.078f; 31 | static const float kM00 = 0.30f; 32 | static const float kM01 = 1.0f - kM02 - kM00; 33 | static const float kM12 = 0.078f; 34 | static const float kM10 = 0.23f; 35 | static const float kM11 = 1.0f - kM12 - kM10; 36 | static const float kM20 = 0.24342268924547819f; 37 | static const float kM21 = 0.20476744424496821f; 38 | static const float kM22 = 1.0f - kM20 - kM21; 39 | static const float kOpsinAbsorbanceBias = 0.0037930732552754493f; 40 | static constexpr float kNegBiasCbrt = -0.15595420054f; 41 | 42 | // This is different from Butteraugli's OpsinDynamicsImage() in the sense that 43 | // it does not contain a sensitivity multiplier based on the blurred image. 44 | void ToXYB(Image3F* image) { 45 | const HWY_FULL(float) d; 46 | // Pre-broadcasted constants 47 | const auto half = Set(d, 0.5f); 48 | const auto bias = Set(d, kOpsinAbsorbanceBias); 49 | const auto neg_bias_cbrt = Set(d, kNegBiasCbrt); 50 | const auto m00 = Set(d, kM00); 51 | const auto m01 = Set(d, kM01); 52 | const auto m02 = Set(d, kM02); 53 | const auto m10 = Set(d, kM10); 54 | const auto m11 = Set(d, kM11); 55 | const auto m12 = Set(d, kM12); 56 | const auto m20 = Set(d, kM20); 57 | const auto m21 = Set(d, kM21); 58 | const auto m22 = Set(d, kM22); 59 | const size_t xsize = image->xsize(); 60 | const size_t ysize = image->ysize(); 61 | for (size_t y = 0; y < ysize; ++y) { 62 | float* JXL_RESTRICT row0 = image->PlaneRow(0, y); 63 | float* JXL_RESTRICT row1 = image->PlaneRow(1, y); 64 | float* JXL_RESTRICT row2 = image->PlaneRow(2, y); 65 | for (size_t x = 0; x < xsize; x += Lanes(d)) { 66 | const auto r = Load(d, row0 + x); 67 | const auto g = Load(d, row1 + x); 68 | const auto b = Load(d, row2 + x); 69 | const auto mixed0 = MulAdd(m00, r, MulAdd(m01, g, MulAdd(m02, b, bias))); 70 | const auto mixed1 = MulAdd(m10, r, MulAdd(m11, g, MulAdd(m12, b, bias))); 71 | const auto mixed2 = MulAdd(m20, r, MulAdd(m21, g, MulAdd(m22, b, bias))); 72 | // mixed* should be non-negative even for wide-gamut, so clamp to zero. 73 | const auto tm0 = CubeRootAndAdd(ZeroIfNegative(mixed0), neg_bias_cbrt); 74 | const auto tm1 = CubeRootAndAdd(ZeroIfNegative(mixed1), neg_bias_cbrt); 75 | const auto tm2 = CubeRootAndAdd(ZeroIfNegative(mixed2), neg_bias_cbrt); 76 | Store(Mul(half, Sub(tm0, tm1)), d, row0 + x); 77 | Store(Mul(half, Add(tm0, tm1)), d, row1 + x); 78 | Store(tm2, d, row2 + x); 79 | } 80 | } 81 | } 82 | 83 | // NOLINTNEXTLINE(google-readability-namespace-comments) 84 | } // namespace HWY_NAMESPACE 85 | } // namespace jxl 86 | HWY_AFTER_NAMESPACE(); 87 | 88 | #if HWY_ONCE 89 | namespace jxl { 90 | HWY_EXPORT(ToXYB); 91 | void ToXYB(Image3F* image) { return HWY_DYNAMIC_DISPATCH(ToXYB)(image); } 92 | } // namespace jxl 93 | #endif // HWY_ONCE 94 | -------------------------------------------------------------------------------- /encoder/enc_xyb.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #ifndef ENCODER_ENC_XYB_H_ 8 | #define ENCODER_ENC_XYB_H_ 9 | 10 | #include "encoder/image.h" 11 | 12 | namespace jxl { 13 | 14 | // Converts linear SRGB to XYB in place. 15 | void ToXYB(Image3F* image); 16 | 17 | } // namespace jxl 18 | 19 | #endif // ENCODER_ENC_XYB_H_ 20 | -------------------------------------------------------------------------------- /encoder/entropy_code.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #ifndef ENCODER_ENTROPY_CODE_H_ 8 | #define ENCODER_ENTROPY_CODE_H_ 9 | 10 | #include 11 | 12 | #include 13 | 14 | namespace jxl { 15 | 16 | static constexpr size_t kAlphabetSize = 64; 17 | static constexpr uint8_t kMaxContexts = 128; 18 | 19 | struct PrefixCode { 20 | uint8_t depths[kAlphabetSize]; 21 | uint16_t bits[kAlphabetSize]; 22 | }; 23 | 24 | struct EntropyCode { 25 | EntropyCode(const uint8_t* static_context_map, size_t num_c, 26 | const PrefixCode* static_prefix_codes, size_t num_p) 27 | : context_map(static_context_map), 28 | num_contexts(num_c), 29 | prefix_codes(static_prefix_codes), 30 | num_prefix_codes(num_p) {} 31 | const uint8_t* context_map; 32 | size_t num_contexts; 33 | const PrefixCode* prefix_codes; 34 | size_t num_prefix_codes; 35 | // Data storage for the optimized entropy codes. 36 | std::vector context_map_storage; 37 | std::vector prefix_code_storage; 38 | // Original context map, in case the contexts were clustered. 39 | const uint8_t* orig_context_map = nullptr; 40 | size_t orig_num_contexts = 0; 41 | }; 42 | 43 | } // namespace jxl 44 | #endif // ENCODER_ENTROPY_CODE_H_ 45 | -------------------------------------------------------------------------------- /encoder/histogram.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #ifndef ENCODER_HISTOGRAM_H_ 8 | #define ENCODER_HISTOGRAM_H_ 9 | 10 | #include 11 | #include 12 | 13 | #include "encoder/entropy_code.h" 14 | 15 | namespace jxl { 16 | 17 | struct Histogram { 18 | Histogram() { Clear(); } 19 | void Clear() { 20 | memset(counts, 0, sizeof(counts)); 21 | total_count = 0; 22 | } 23 | void Add(uint32_t symbol) { 24 | ++counts[symbol]; 25 | ++total_count; 26 | } 27 | void AddHistogram(const Histogram& other) { 28 | for (size_t i = 0; i < kAlphabetSize; ++i) { 29 | counts[i] += other.counts[i]; 30 | } 31 | total_count += other.total_count; 32 | } 33 | uint32_t counts[kAlphabetSize]; 34 | size_t total_count; 35 | mutable size_t bit_cost; // WARNING: not kept up-to-date. 36 | }; 37 | 38 | } // namespace jxl 39 | #endif // ENCODER_HISTOGRAM_H_ 40 | -------------------------------------------------------------------------------- /encoder/image.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #include "encoder/image.h" 8 | 9 | #include // swap 10 | 11 | #undef HWY_TARGET_INCLUDE 12 | #define HWY_TARGET_INCLUDE "encoder/image.cc" 13 | #include 14 | #include 15 | 16 | #include "encoder/base/sanitizer_definitions.h" 17 | #include "encoder/common.h" 18 | 19 | HWY_BEFORE_NAMESPACE(); 20 | namespace jxl { 21 | 22 | namespace HWY_NAMESPACE { 23 | size_t GetVectorSize() { return HWY_LANES(uint8_t); } 24 | // NOLINTNEXTLINE(google-readability-namespace-comments) 25 | } // namespace HWY_NAMESPACE 26 | 27 | } // namespace jxl 28 | HWY_AFTER_NAMESPACE(); 29 | 30 | #if HWY_ONCE 31 | namespace jxl { 32 | namespace { 33 | 34 | HWY_EXPORT(GetVectorSize); // Local function. 35 | 36 | size_t VectorSize() { 37 | static size_t bytes = HWY_DYNAMIC_DISPATCH(GetVectorSize)(); 38 | return bytes; 39 | } 40 | 41 | // Returns distance [bytes] between the start of two consecutive rows, a 42 | // multiple of vector/cache line size but NOT CacheAligned::kAlias - see below. 43 | size_t BytesPerRow(const size_t xsize, const size_t sizeof_t) { 44 | const size_t vec_size = VectorSize(); 45 | size_t valid_bytes = xsize * sizeof_t; 46 | 47 | // Allow unaligned accesses starting at the last valid value - this may raise 48 | // msan errors. 49 | // Skip for the scalar case because no extra lanes will be loaded. 50 | if (vec_size != 0) { 51 | valid_bytes += vec_size - sizeof_t; 52 | } 53 | 54 | // Round up to vector and cache line size. 55 | const size_t align = std::max(vec_size, CacheAligned::kAlignment); 56 | size_t bytes_per_row = RoundUpTo(valid_bytes, align); 57 | 58 | // During the lengthy window before writes are committed to memory, CPUs 59 | // guard against read after write hazards by checking the address, but 60 | // only the lower 11 bits. We avoid a false dependency between writes to 61 | // consecutive rows by ensuring their sizes are not multiples of 2 KiB. 62 | // Avoid2K prevents the same problem for the planes of an Image3. 63 | if (bytes_per_row % CacheAligned::kAlias == 0) { 64 | bytes_per_row += align; 65 | } 66 | 67 | JXL_ASSERT(bytes_per_row % align == 0); 68 | return bytes_per_row; 69 | } 70 | 71 | } // namespace 72 | 73 | PlaneBase::PlaneBase(const size_t xsize, const size_t ysize, 74 | const size_t sizeof_t) 75 | : xsize_(static_cast(xsize)), 76 | ysize_(static_cast(ysize)), 77 | orig_xsize_(static_cast(xsize)), 78 | orig_ysize_(static_cast(ysize)) { 79 | JXL_CHECK(xsize == xsize_); 80 | JXL_CHECK(ysize == ysize_); 81 | 82 | JXL_ASSERT(sizeof_t == 1 || sizeof_t == 2 || sizeof_t == 4 || sizeof_t == 8); 83 | 84 | bytes_per_row_ = 0; 85 | // Dimensions can be zero, e.g. for lazily-allocated images. Only allocate 86 | // if nonzero, because "zero" bytes still have padding/bookkeeping overhead. 87 | if (xsize != 0 && ysize != 0) { 88 | bytes_per_row_ = BytesPerRow(xsize, sizeof_t); 89 | bytes_ = AllocateArray(bytes_per_row_ * ysize); 90 | JXL_CHECK(bytes_.get()); 91 | InitializePadding(sizeof_t, Padding::kRoundUp); 92 | } 93 | } 94 | 95 | void PlaneBase::InitializePadding(const size_t sizeof_t, Padding padding) { 96 | #if defined(MEMORY_SANITIZER) || HWY_IDE 97 | if (xsize_ == 0 || ysize_ == 0) return; 98 | 99 | const size_t vec_size = VectorSize(); 100 | if (vec_size == 0) return; // Scalar mode: no padding needed 101 | 102 | const size_t valid_size = xsize_ * sizeof_t; 103 | const size_t initialize_size = padding == Padding::kRoundUp 104 | ? RoundUpTo(valid_size, vec_size) 105 | : valid_size + vec_size - sizeof_t; 106 | if (valid_size == initialize_size) return; 107 | 108 | for (size_t y = 0; y < ysize_; ++y) { 109 | uint8_t* JXL_RESTRICT row = static_cast(VoidRow(y)); 110 | #if defined(__clang__) && (__clang_major__ <= 6) 111 | // There's a bug in msan in clang-6 when handling AVX2 operations. This 112 | // workaround allows tests to pass on msan, although it is slower and 113 | // prevents msan warnings from uninitialized images. 114 | std::fill(row, msan::kSanitizerSentinelByte, initialize_size); 115 | #else 116 | memset(row + valid_size, msan::kSanitizerSentinelByte, 117 | initialize_size - valid_size); 118 | #endif // clang6 119 | } 120 | #endif // MEMORY_SANITIZER 121 | } 122 | 123 | void PlaneBase::Swap(PlaneBase& other) { 124 | std::swap(xsize_, other.xsize_); 125 | std::swap(ysize_, other.ysize_); 126 | std::swap(orig_xsize_, other.orig_xsize_); 127 | std::swap(orig_ysize_, other.orig_ysize_); 128 | std::swap(bytes_per_row_, other.bytes_per_row_); 129 | std::swap(bytes_, other.bytes_); 130 | } 131 | 132 | constexpr inline size_t RoundUpToBlockDim(size_t dim) { 133 | return (dim + 7) & ~size_t(7); 134 | } 135 | 136 | } // namespace jxl 137 | #endif // HWY_ONCE 138 | -------------------------------------------------------------------------------- /encoder/quant_weights.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #ifndef ENCODER_QUANT_WEIGHTS_H_ 8 | #define ENCODER_QUANT_WEIGHTS_H_ 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include "encoder/ac_strategy.h" 16 | #include "encoder/base/cache_aligned.h" 17 | #include "encoder/base/compiler_specific.h" 18 | #include "encoder/base/status.h" 19 | 20 | namespace jxl { 21 | // Let's try to keep these 2**N for possible future simplicity. 22 | const float kInvDCQuant[3] = { 23 | 4096.0f, 24 | 512.0f, 25 | 256.0f, 26 | }; 27 | 28 | const float kDCQuant[3] = { 29 | 1.0f / kInvDCQuant[0], 30 | 1.0f / kInvDCQuant[1], 31 | 1.0f / kInvDCQuant[2], 32 | }; 33 | 34 | class DequantMatrices { 35 | public: 36 | DequantMatrices(); 37 | 38 | // Returns aligned memory. 39 | JXL_INLINE const float* Matrix(size_t quant_kind, size_t c) const { 40 | JXL_DASSERT(quant_kind < AcStrategy::kNumValidStrategies); 41 | return &table_[table_offsets_[quant_kind * 3 + c]]; 42 | } 43 | 44 | JXL_INLINE const float* InvMatrix(size_t quant_kind, size_t c) const { 45 | JXL_DASSERT(quant_kind < AcStrategy::kNumValidStrategies); 46 | return &inv_table_[table_offsets_[quant_kind * 3 + c]]; 47 | } 48 | 49 | private: 50 | hwy::AlignedFreeUniquePtr table_storage_; 51 | const float* table_; 52 | const float* inv_table_; 53 | size_t table_offsets_[AcStrategy::kNumValidStrategies * 3]; 54 | }; 55 | 56 | } // namespace jxl 57 | 58 | #endif // ENCODER_QUANT_WEIGHTS_H_ 59 | -------------------------------------------------------------------------------- /encoder/read_pfm.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #ifndef ENCODER_READ_PFM_H_ 8 | #define ENCODER_READ_PFM_H_ 9 | 10 | #include "encoder/image.h" 11 | 12 | namespace jxl { 13 | 14 | bool ReadPFM(const char* fn, jxl::Image3F* image); 15 | 16 | } // namespace jxl 17 | 18 | #endif // ENCODER_READ_PFM_H_ 19 | -------------------------------------------------------------------------------- /encoder/token.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) the JPEG XL Project Authors. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file or at 5 | // https://developers.google.com/open-source/licenses/bsd 6 | 7 | #ifndef ENCODER_TOKEN_H_ 8 | #define ENCODER_TOKEN_H_ 9 | 10 | #include 11 | 12 | #include "encoder/base/bits.h" 13 | 14 | namespace jxl { 15 | 16 | // Integer to be encoded by an entropy coder, either ANS or Huffman. 17 | struct Token { 18 | Token() {} 19 | Token(uint32_t c, uint32_t value) : context(c), value(value) {} 20 | uint32_t context; 21 | uint32_t value; 22 | }; 23 | 24 | // N = 0 - 15: (token=N, nbits=0, bits='') 25 | // N = 16 (10000): (token=16, nbits=2, bits='00') 26 | // N = 17 (10001): (token=16, nbits=2, bits='01') 27 | // N = 20 (10100): (token=17, nbits=2, bits='00') 28 | // N = 24 (11000): (token=18, nbits=2, bits='00') 29 | // N = 28 (11100): (token=19, nbits=2, bits='00') 30 | // N = 32 (100000): (token=20, nbits=3, bits='000') 31 | // N = 65535: (token=63, nbits=13, bits='1111111111111') 32 | struct UintCoder { 33 | JXL_INLINE void Encode(uint32_t value, uint32_t* JXL_RESTRICT token, 34 | uint32_t* JXL_RESTRICT nbits, 35 | uint32_t* JXL_RESTRICT bits) const { 36 | if (value < 16) { 37 | *token = value; 38 | *nbits = 0; 39 | *bits = 0; 40 | } else { 41 | uint32_t n = FloorLog2Nonzero(value); 42 | uint32_t m = value - (1 << n); 43 | *token = (n << 2) + (m >> (n - 2)); 44 | *nbits = n - 2; 45 | *bits = value & ((1UL << *nbits) - 1); 46 | } 47 | } 48 | }; 49 | 50 | } // namespace jxl 51 | #endif // ENCODER_TOKEN_H_ 52 | -------------------------------------------------------------------------------- /third_party/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) the JPEG XL Project 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | if((SANITIZER STREQUAL "asan") OR (SANITIZER STREQUAL "msan")) 16 | set(BUILD_TESTING OFF) 17 | endif() 18 | 19 | # Highway 20 | set(HWY_SYSTEM_GTEST ON CACHE INTERNAL "") 21 | set(HWY_FORCE_STATIC_LIBS ON CACHE INTERNAL "") 22 | set(HWY_ENABLE_CONTRIB OFF CACHE INTERNAL "") 23 | set(HWY_ENABLE_EXAMPLES OFF CACHE INTERNAL "") 24 | if((SANITIZER STREQUAL "asan") OR (SANITIZER STREQUAL "msan")) 25 | set(HWY_ENABLE_INSTALL OFF CACHE INTERNAL "") 26 | endif() 27 | if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/highway/CMakeLists.txt" AND 28 | NOT JPEGXL_FORCE_SYSTEM_HWY) 29 | add_subdirectory(highway) 30 | configure_file("${CMAKE_CURRENT_SOURCE_DIR}/highway/LICENSE" 31 | ${PROJECT_BINARY_DIR}/LICENSE.highway COPYONLY) 32 | else() 33 | find_package(HWY 0.15.0) 34 | if (NOT HWY_FOUND) 35 | message(FATAL_ERROR 36 | "Highway library (hwy) not found. Install libhwy-dev or download it " 37 | "to third_party/highway from https://github.com/google/highway . " 38 | "Highway is required to build JPEG XL. You can run " 39 | "${PROJECT_SOURCE_DIR}/deps.sh to download this dependency.") 40 | endif() 41 | if(JPEGXL_DEP_LICENSE_DIR) 42 | configure_file("${JPEGXL_DEP_LICENSE_DIR}/libhwy-dev/copyright" 43 | ${PROJECT_BINARY_DIR}/LICENSE.highway COPYONLY) 44 | endif() # JPEGXL_DEP_LICENSE_DIR 45 | endif() 46 | 47 | -------------------------------------------------------------------------------- /third_party/testing.cmake: -------------------------------------------------------------------------------- 1 | # Copyright (c) the JPEG XL Project 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Enable tests in third_party/ as well. 16 | enable_testing() 17 | include(CTest) 18 | 19 | set(SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party") 20 | 21 | if(BUILD_TESTING) 22 | # Add GTest from source and alias it to what the find_package(GTest) workflow 23 | # defines. Omitting googletest/ directory would require it to be available in 24 | # the base system instead, but it would work just fine. This makes packages 25 | # using GTest and calling find_package(GTest) actually work. 26 | if (EXISTS "${SOURCE_DIR}/googletest/CMakeLists.txt" AND 27 | NOT JPEGXL_FORCE_SYSTEM_GTEST) 28 | add_subdirectory(third_party/googletest EXCLUDE_FROM_ALL) 29 | 30 | set(GTEST_ROOT "${SOURCE_DIR}/googletest/googletest") 31 | set(GTEST_INCLUDE_DIR "$" 32 | CACHE STRING "") 33 | set(GMOCK_INCLUDE_DIR "$") 34 | set(GTEST_LIBRARY "$") 35 | set(GTEST_MAIN_LIBRARY "$") 36 | add_library(GTest::GTest ALIAS gtest) 37 | add_library(GTest::Main ALIAS gtest_main) 38 | 39 | set_target_properties(gtest PROPERTIES POSITION_INDEPENDENT_CODE TRUE) 40 | set_target_properties(gmock PROPERTIES POSITION_INDEPENDENT_CODE TRUE) 41 | set_target_properties(gtest_main PROPERTIES POSITION_INDEPENDENT_CODE TRUE) 42 | set_target_properties(gmock_main PROPERTIES POSITION_INDEPENDENT_CODE TRUE) 43 | 44 | # googletest doesn't compile clean with clang-cl (-Wundef) 45 | if (WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang") 46 | set_target_properties(gtest PROPERTIES COMPILE_FLAGS "-Wno-error") 47 | set_target_properties(gmock PROPERTIES COMPILE_FLAGS "-Wno-error") 48 | set_target_properties(gtest_main PROPERTIES COMPILE_FLAGS "-Wno-error") 49 | set_target_properties(gmock_main PROPERTIES COMPILE_FLAGS "-Wno-error") 50 | endif () 51 | configure_file("${SOURCE_DIR}/googletest/LICENSE" 52 | ${PROJECT_BINARY_DIR}/LICENSE.googletest COPYONLY) 53 | else() 54 | if(JPEGXL_DEP_LICENSE_DIR) 55 | configure_file("${JPEGXL_DEP_LICENSE_DIR}/googletest/copyright" 56 | ${PROJECT_BINARY_DIR}/LICENSE.googletest COPYONLY) 57 | endif() # JPEGXL_DEP_LICENSE_DIR 58 | endif() 59 | find_package(GTest) 60 | if (NOT GTEST_FOUND) 61 | set(BUILD_TESTING OFF CACHE BOOL "Build tests" FORCE) 62 | message(SEND_ERROR "GTest not found. Install googletest package " 63 | "(libgtest-dev) in the system or download googletest to " 64 | "third_party/googletest from https://github.com/google/googletest ." 65 | "To disable tests instead re-run cmake with -DBUILD_TESTING=OFF.") 66 | endif() # NOT GTEST_FOUND 67 | 68 | # Look for gmock in the system too. 69 | if (NOT DEFINED GMOCK_INCLUDE_DIR) 70 | find_path( 71 | GMOCK_INCLUDE_DIR "gmock/gmock.h" 72 | HINTS ${GTEST_INCLUDE_DIRS}) 73 | if (NOT GMOCK_INCLUDE_DIR) 74 | set(BUILD_TESTING OFF CACHE BOOL "Build tests" FORCE) 75 | message(SEND_ERROR "GMock not found. Install googletest package " 76 | "(libgmock-dev) in the system or download googletest to " 77 | "third_party/googletest from https://github.com/google/googletest ." 78 | "To disable tests instead re-run cmake with -DBUILD_TESTING=OFF.") 79 | else() 80 | message(STATUS "Found GMock: ${GMOCK_INCLUDE_DIR}") 81 | endif() # NOT GMOCK_INCLUDE_DIR 82 | endif() # NOT DEFINED GMOCK_INCLUDE_DIR 83 | endif() # BUILD_TESTING 84 | -------------------------------------------------------------------------------- /tools/check_author.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (c) the JPEG XL Project Authors. 4 | # 5 | # Use of this source code is governed by a BSD-style 6 | # license that can be found in the LICENSE file or at 7 | # https://developers.google.com/open-source/licenses/bsd 8 | 9 | 10 | """check_author.py: Check that a given author is listed in the AUTHORS file.""" 11 | 12 | import argparse 13 | import fnmatch 14 | import os 15 | import re 16 | import sys 17 | 18 | 19 | def IsAuthorInFile(email, name, filename): 20 | """Return whether we find the name/email in the authors filename""" 21 | # Organization emails have emails listed as <*@domain.com>. This matches those 22 | # patterns. 23 | email_pattern_regex = re.compile(r'.*<([^>]+)>') 24 | 25 | with open(filename, 'r') as f: 26 | for line in f: 27 | line = line.strip() 28 | if line.startswith('#') or not line: 29 | continue 30 | # Exact match for a line without an email is OK. 31 | if line == name: 32 | return True 33 | # Exact email address match is OK, even if the name is different. 34 | if fnmatch.fnmatch(line, '* <%s>' % email): 35 | print( 36 | "User %s <%s> matched with different name %s" % (name, email, line), 37 | file=sys.stderr) 38 | return True 39 | # Organizations often have *@domain.com email patterns which don't match 40 | # the name. 41 | if '*' in line: 42 | m = email_pattern_regex.match(line) 43 | if m and fnmatch.fnmatch(email, m.group(1)): 44 | print("User %s <%s> matched pattern %s" % (name, email, line), 45 | file=sys.stderr) 46 | return True 47 | return False 48 | 49 | def IndividualsInAlphabeticOrder(filename): 50 | """Checks if the names are in alphabetic order""" 51 | with open(filename, 'r') as f: 52 | lines = f.readlines() 53 | individual_header = '# Individuals:\n' 54 | if individual_header in lines: 55 | individual_authors = lines[lines.index(individual_header) + 1:] 56 | sorted_authors = sorted(individual_authors, key=str.casefold) 57 | if sorted_authors == individual_authors: 58 | print("Individual authors are sorted alphabetically.") 59 | return True 60 | else: 61 | print("Individual authors are not sorted alphabetically." 62 | " The expected order is:") 63 | print(''.join(sorted_authors)) 64 | return False 65 | else: 66 | print("Cannot find line '# Individuals:' in file.") 67 | return False 68 | 69 | 70 | def CheckAuthor(args): 71 | authors_path = os.path.join(args.source_dir, 'AUTHORS') 72 | author_in_file = IsAuthorInFile( 73 | args.email, args.name, authors_path) 74 | if not author_in_file: 75 | print("User %s <%s> not found, please add yourself to the AUTHORS file" % ( 76 | args.name, args.email), 77 | file=sys.stderr) 78 | 79 | sorted_alphabetically = IndividualsInAlphabeticOrder(authors_path) 80 | if not sorted_alphabetically: 81 | print("Authors not in alphabetical order, please sort them.", file=sys.stderr) 82 | if not author_in_file or not sorted_alphabetically: 83 | if not args.dry_run: 84 | sys.exit(1) 85 | 86 | 87 | def main(): 88 | parser = argparse.ArgumentParser(description=__doc__) 89 | parser.add_argument('email', type=str, 90 | help='email of the commit author to check') 91 | parser.add_argument('name', type=str, 92 | help='name of the commit author to check') 93 | parser.add_argument( 94 | '--source-dir', 95 | default=os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 96 | help='path to the source directory where the AUTHORS file is located') 97 | parser.add_argument('--dry-run', default=False, action='store_true', 98 | help='Don\'t return an exit code in case of failure') 99 | args = parser.parse_args() 100 | CheckAuthor(args) 101 | 102 | 103 | if __name__ == '__main__': 104 | main() 105 | --------------------------------------------------------------------------------