Bug 1880922 - Update libjxl to ab47708dcf002fae0164555b370aa36487df0f5d r=saschanaz

Differential Revision: https://phabricator.services.mozilla.com/D202184
This commit is contained in:
Updatebot 2024-02-20 14:09:59 +00:00
Родитель a7fea0f06a
Коммит c265adb0a2
192 изменённых файлов: 3559 добавлений и 2861 удалений

Просмотреть файл

@ -50,6 +50,7 @@ SOURCES += [
"/third_party/jpeg-xl/lib/jxl/image.cc",
"/third_party/jpeg-xl/lib/jxl/image_bundle.cc",
"/third_party/jpeg-xl/lib/jxl/image_metadata.cc",
"/third_party/jpeg-xl/lib/jxl/image_ops.cc",
"/third_party/jpeg-xl/lib/jxl/loop_filter.cc",
"/third_party/jpeg-xl/lib/jxl/luminance.cc",
"/third_party/jpeg-xl/lib/jxl/memory_manager_internal.cc",

Просмотреть файл

@ -10,9 +10,9 @@ origin:
url: https://github.com/libjxl/libjxl
release: 07203da045f6b41f9b3b5b86023fd70b075137f6 (2024-01-29T17:41:05Z).
release: ab47708dcf002fae0164555b370aa36487df0f5d (2024-02-19T19:38:30Z).
revision: 07203da045f6b41f9b3b5b86023fd70b075137f6
revision: ab47708dcf002fae0164555b370aa36487df0f5d
license: Apache-2.0

3
third_party/jpeg-xl/AUTHORS поставляемый
Просмотреть файл

@ -32,6 +32,7 @@ Zoltan Szabadka <szabadka@google.com>
# Individuals:
a-shvedov
Aditya Patadia <adityapatadia@users.noreply.github.com>
Ahmad Amsyar Asyadiq Bin Syaiful Bahri <27284123+Ahmad-Amsyar@users.noreply.github.com>
Alex Xu (Hello71) <alex_y_xu@yahoo.ca>
Alexander Sago <cagelight@gmail.com>
Alistair Barrow
@ -74,6 +75,7 @@ Misaki Kasumi <misakikasumi@outlook.com>
Moonchild Straver <moonchild@palemoon.org>
Nicholas Hayes <0xC0000054@users.noreply.github.com>
Nigel Tao <nigeltao@golang.org>
oupson <oupson1er@gmail.com>
Petr Diblík
Pieter Wuille
roland-rollo
@ -93,4 +95,3 @@ xiota
Yonatan Nebenzhal <yonatan.nebenzhl@gmail.com>
Ziemowit Zabawa <ziemek.zabawa@outlook.com>
源文雨 <41315874+fumiama@users.noreply.github.com>
oupson <oupson1er@gmail.com>

26
third_party/jpeg-xl/CHANGELOG.md поставляемый
Просмотреть файл

@ -8,11 +8,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
### Added
- decoder API: added `JxlDecoderGetBoxSizeContents` for getting the size of the
content of a box without the headers.
### Removed
### Changed / clarified
## [0.9.2] - 2024-02-07
### Fixed
- bugs in the gdk-pixbuf plugin
- some build issues
## [0.9.1] - 2024-01-08
### Fixed
- multiple build issues
## [0.9.0] - 2023-12-22
### Added
@ -57,6 +69,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- fixed how large boxes are decoded (#2958)
- fixed encoding files with unreadable patches (#3042, #3046)
## [0.8.2] - 2023-06-14
### Changed
- Security: Fix an integer underflow bug in patch decoding (#2551- CVE-2023-35790).
## [0.8.1] - 2023-02-03
### Changed
- Allow fast-lossless for 16-bit float input (#2093)
- Fix bug in palette (#2120)
- Security: Fix OOB read in exif.h (#2101 - [CVE-2023-0645](https://www.cve.org/cverecord?id=CVE-2023-0645))
## [0.8.0] - 2023-01-18
### Added

2
third_party/jpeg-xl/CMakeLists.txt поставляемый
Просмотреть файл

@ -161,7 +161,7 @@ set(JPEGXL_ENABLE_AVX512_SPR false CACHE BOOL
set(JPEGXL_ENABLE_AVX512_ZEN4 false CACHE BOOL
"Build with Zen4-optimized AVX512 support (faster on CPUs that support it, but larger binary size).")
set(JPEGXL_ENABLE_WASM_TRHEADS true CACHE BOOL
"Builds WASM modules with threads suppurt")
"Builds WASM modules with threads support")
# Force system dependencies.
set(JPEGXL_FORCE_SYSTEM_BROTLI false CACHE BOOL

Просмотреть файл

@ -1,3 +1,2 @@
usr/lib/*/gdk-pixbuf-*/*/loaders/*
usr/share/mime/packages/image-jxl.xml
usr/share/thumbnailers/jxl.thumbnailer

2
third_party/jpeg-xl/deps.sh поставляемый
Просмотреть файл

@ -15,7 +15,7 @@ MYDIR=$(dirname $(realpath "$0"))
# update a git submodule.
TESTDATA="873045a9c42ed60721756e26e2a6b32e17415205"
THIRD_PARTY_BROTLI="36533a866ed1ca4b75cf049f4521e4ec5fe24727"
THIRD_PARTY_HIGHWAY="ba0900a4957b929390ab73827235557959234fea"
THIRD_PARTY_HIGHWAY="58b52a717469e62b2d9b8eaa2f5dddb44d4a4cbf"
THIRD_PARTY_SKCMS="42030a771244ba67f86b1c1c76a6493f873c5f91"
THIRD_PARTY_SJPEG="e5ab13008bb214deb66d5f3e17ca2f8dbff150bf"
THIRD_PARTY_ZLIB="51b7f2abdade71cd9bb0e7a373ef2610ec6f9daf" # v1.3.1

10
third_party/jpeg-xl/examples/CMakeLists.txt поставляемый
Просмотреть файл

@ -11,17 +11,15 @@ project(SAMPLE_LIBJXL LANGUAGES C CXX)
# Use pkg-config to find libjxl.
find_package(PkgConfig)
pkg_check_modules(Jxl REQUIRED IMPORTED_TARGET libjxl)
pkg_check_modules(JxlCms REQUIRED IMPORTED_TARGET libjxl_cms)
pkg_check_modules(JxlThreads REQUIRED IMPORTED_TARGET libjxl_threads)
pkg_check_modules(Jxl REQUIRED IMPORTED_TARGET libjxl libjxl_cms libjxl_threads)
# Build the example encoder/decoder binaries using the default shared libraries
# installed.
add_executable(decode_oneshot decode_oneshot.cc)
target_link_libraries(decode_oneshot PkgConfig::Jxl PkgConfig::JxlCms PkgConfig::JxlThreads)
target_link_libraries(decode_oneshot PkgConfig::Jxl)
add_executable(decode_progressive decode_progressive.cc)
target_link_libraries(decode_progressive PkgConfig::Jxl PkgConfig::JxlCms PkgConfig::JxlThreads)
target_link_libraries(decode_progressive PkgConfig::Jxl)
add_executable(encode_oneshot encode_oneshot.cc)
target_link_libraries(encode_oneshot PkgConfig::Jxl PkgConfig::JxlCms PkgConfig::JxlThreads)
target_link_libraries(encode_oneshot PkgConfig::Jxl)

10
third_party/jpeg-xl/lib/CMakeLists.txt поставляемый
Просмотреть файл

@ -149,6 +149,16 @@ else()
set(PKGCONFIG_TARGET_LIBS "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
endif()
include(CheckCXXSymbolExists)
set(PKGCONFIG_CXX_LIB "")
check_cxx_symbol_exists(__GLIBCXX__ iostream LIBSTDCXX)
check_cxx_symbol_exists(_LIBCPP_VERSION iostream LIBCXX)
if(LIBSTDCXX)
set(PKGCONFIG_CXX_LIB "-lstdc++")
elseif(LIBCXX)
set(PKGCONFIG_CXX_LIB "-lc++")
endif()
# The jxl_cms library definition.
include(jxl_cms.cmake)
# The jxl library definition.

3
third_party/jpeg-xl/lib/extras/dec/apng.cc поставляемый
Просмотреть файл

@ -813,6 +813,8 @@ Status DecodeImageAPNG(const Span<const uint8_t> bytes,
have_cicp = true;
have_color = true;
ppf->icc.clear();
ppf->primary_color_representation =
PackedPixelFile::kColorEncodingIsPrimary;
}
} else if (!have_cicp && id == kId_iCCP) {
if (processing_data(png_ptr, info_ptr, chunk.data(), chunk.size())) {
@ -830,6 +832,7 @@ Status DecodeImageAPNG(const Span<const uint8_t> bytes,
&profile, &proflen);
if (ok && proflen) {
ppf->icc.assign(profile, profile + proflen);
ppf->primary_color_representation = PackedPixelFile::kIccIsPrimary;
have_color = true;
have_iccp = true;
} else {

Просмотреть файл

@ -43,20 +43,21 @@ Status ApplyColorHints(const ColorHints& color_hints,
} else if (key == "icc") {
const uint8_t* data = reinterpret_cast<const uint8_t*>(value.data());
std::vector<uint8_t> icc(data, data + value.size());
ppf->icc.swap(icc);
ppf->icc = std::move(icc);
ppf->primary_color_representation = PackedPixelFile::kIccIsPrimary;
got_color_space = true;
} else if (key == "exif") {
const uint8_t* data = reinterpret_cast<const uint8_t*>(value.data());
std::vector<uint8_t> blob(data, data + value.size());
ppf->metadata.exif.swap(blob);
ppf->metadata.exif = std::move(blob);
} else if (key == "xmp") {
const uint8_t* data = reinterpret_cast<const uint8_t*>(value.data());
std::vector<uint8_t> blob(data, data + value.size());
ppf->metadata.xmp.swap(blob);
ppf->metadata.xmp = std::move(blob);
} else if (key == "jumbf") {
const uint8_t* data = reinterpret_cast<const uint8_t*>(value.data());
std::vector<uint8_t> blob(data, data + value.size());
ppf->metadata.jumbf.swap(blob);
ppf->metadata.jumbf = std::move(blob);
} else {
JXL_WARNING("Ignoring %s hint", key.c_str());
}

Просмотреть файл

@ -188,7 +188,11 @@ Status DecodeJpeg(const std::vector<uint8_t>& compressed,
} else if (dparams.force_grayscale) {
cinfo.out_color_space = JCS_GRAYSCALE;
}
if (!ReadICCProfile(&cinfo, &ppf->icc)) {
if (ReadICCProfile(&cinfo, &ppf->icc)) {
ppf->primary_color_representation = PackedPixelFile::kIccIsPrimary;
} else {
ppf->primary_color_representation =
PackedPixelFile::kColorEncodingIsPrimary;
ppf->icc.clear();
// Default to SRGB
ppf->color_encoding.color_space =
@ -227,7 +231,7 @@ Status DecodeJpeg(const std::vector<uint8_t>& compressed,
if (dparams.num_colors > 0) {
cinfo.quantize_colors = TRUE;
cinfo.desired_number_of_colors = dparams.num_colors;
cinfo.two_pass_quantize = dparams.two_pass_quant;
cinfo.two_pass_quantize = static_cast<boolean>(dparams.two_pass_quant);
cinfo.dither_mode = (J_DITHER_MODE)dparams.dither_mode;
}

8
third_party/jpeg-xl/lib/extras/dec/jpg.cc поставляемый
Просмотреть файл

@ -242,7 +242,11 @@ Status DecodeImageJPG(const Span<const uint8_t> bytes,
if (nbcomp != 1 && nbcomp != 3) {
return failure("unsupported number of components in JPEG");
}
if (!ReadICCProfile(&cinfo, &ppf->icc)) {
if (ReadICCProfile(&cinfo, &ppf->icc)) {
ppf->primary_color_representation = PackedPixelFile::kIccIsPrimary;
} else {
ppf->primary_color_representation =
PackedPixelFile::kColorEncodingIsPrimary;
ppf->icc.clear();
// Default to SRGB
// Actually, (cinfo.output_components == nbcomp) will be checked after
@ -278,7 +282,7 @@ Status DecodeImageJPG(const Span<const uint8_t> bytes,
if (dparams && dparams->num_colors > 0) {
cinfo.quantize_colors = TRUE;
cinfo.desired_number_of_colors = dparams->num_colors;
cinfo.two_pass_quantize = dparams->two_pass_quant;
cinfo.two_pass_quantize = static_cast<boolean>(dparams->two_pass_quant);
cinfo.dither_mode = (J_DITHER_MODE)dparams->dither_mode;
}

34
third_party/jpeg-xl/lib/extras/dec/jxl.cc поставляемый
Просмотреть файл

@ -351,24 +351,26 @@ bool DecodeImageJXL(const uint8_t* bytes, size_t bytes_size,
}
size_t icc_size = 0;
JxlColorProfileTarget target = JXL_COLOR_PROFILE_TARGET_DATA;
ppf->color_encoding.color_space = JXL_COLOR_SPACE_UNKNOWN;
if (JXL_DEC_SUCCESS != JxlDecoderGetColorAsEncodedProfile(
dec, target, &ppf->color_encoding) ||
dparams.need_icc) {
// only get ICC if it is not an Enum color encoding
if (JXL_DEC_SUCCESS !=
JxlDecoderGetICCProfileSize(dec, target, &icc_size)) {
fprintf(stderr, "JxlDecoderGetICCProfileSize failed\n");
}
if (icc_size != 0) {
ppf->icc.resize(icc_size);
if (JXL_DEC_SUCCESS != JxlDecoderGetColorAsICCProfile(
dec, target, ppf->icc.data(), icc_size)) {
fprintf(stderr, "JxlDecoderGetColorAsICCProfile failed\n");
return false;
}
if (JXL_DEC_SUCCESS !=
JxlDecoderGetICCProfileSize(dec, target, &icc_size)) {
fprintf(stderr, "JxlDecoderGetICCProfileSize failed\n");
}
if (icc_size != 0) {
ppf->primary_color_representation = PackedPixelFile::kIccIsPrimary;
ppf->icc.resize(icc_size);
if (JXL_DEC_SUCCESS != JxlDecoderGetColorAsICCProfile(
dec, target, ppf->icc.data(), icc_size)) {
fprintf(stderr, "JxlDecoderGetColorAsICCProfile failed\n");
return false;
}
}
if (JXL_DEC_SUCCESS == JxlDecoderGetColorAsEncodedProfile(
dec, target, &ppf->color_encoding)) {
ppf->primary_color_representation =
PackedPixelFile::kColorEncodingIsPrimary;
} else {
ppf->color_encoding.color_space = JXL_COLOR_SPACE_UNKNOWN;
}
icc_size = 0;
target = JXL_COLOR_PROFILE_TARGET_ORIGINAL;
if (JXL_DEC_SUCCESS !=

4
third_party/jpeg-xl/lib/extras/dec/jxl.h поставляемый
Просмотреть файл

@ -41,10 +41,6 @@ struct JXLDecompressParams {
// Whether truncated input should be treated as an error.
bool allow_partial_input = false;
// Set to true if an ICC profile has to be synthesized for Enum color
// encodings
bool need_icc = false;
// How many passes to decode at most. By default, decode everything.
uint32_t max_passes = std::numeric_limits<uint32_t>::max();

10
third_party/jpeg-xl/lib/extras/enc/apng.cc поставляемый
Просмотреть файл

@ -344,11 +344,13 @@ Status APNGEncoder::EncodePackedPixelFileToAPNG(
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
PNG_FILTER_TYPE_BASE);
if (count == 0) {
if (!ppf.icc.empty()) {
png_set_benign_errors(png_ptr, 1);
png_set_iCCP(png_ptr, info_ptr, "1", 0, ppf.icc.data(), ppf.icc.size());
} else if (!MaybeAddSRGB(ppf.color_encoding, png_ptr, info_ptr)) {
if (!MaybeAddSRGB(ppf.color_encoding, png_ptr, info_ptr)) {
MaybeAddCICP(ppf.color_encoding, png_ptr, info_ptr);
if (!ppf.icc.empty()) {
png_set_benign_errors(png_ptr, 1);
png_set_iCCP(png_ptr, info_ptr, "1", 0, ppf.icc.data(),
ppf.icc.size());
}
MaybeAddCHRM(ppf.color_encoding, png_ptr, info_ptr);
MaybeAddGAMA(ppf.color_encoding, png_ptr, info_ptr);
}

Просмотреть файл

@ -34,6 +34,7 @@
#include "lib/jxl/color_encoding_internal.h"
#include "lib/jxl/enc_xyb.h"
#include "lib/jxl/image.h"
#include "lib/jxl/simd_util.h"
namespace jxl {
namespace extras {
@ -71,7 +72,7 @@ Status VerifyInput(const PackedPixelFile& ppf) {
Status GetColorEncoding(const PackedPixelFile& ppf,
ColorEncoding* color_encoding) {
if (!ppf.icc.empty()) {
if (ppf.primary_color_representation == PackedPixelFile::kIccIsPrimary) {
IccBytes icc = ppf.icc;
JXL_RETURN_IF_ERROR(
color_encoding->SetICC(std::move(icc), JxlGetDefaultCms()));
@ -374,11 +375,11 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings,
unsigned char* output_buffer = nullptr;
unsigned long output_size = 0;
std::vector<uint8_t> row_bytes;
size_t rowlen = RoundUpTo(ppf.info.xsize, VectorSize());
size_t rowlen = RoundUpTo(ppf.info.xsize, MaxVectorSize());
hwy::AlignedFreeUniquePtr<float[]> xyb_tmp =
hwy::AllocateAligned<float>(6 * rowlen);
hwy::AlignedFreeUniquePtr<float[]> premul_absorb =
hwy::AllocateAligned<float>(VectorSize() * 12);
hwy::AllocateAligned<float>(MaxVectorSize() * 12);
ComputePremulAbsorb(255.0f, premul_absorb.get());
jpeg_compress_struct cinfo;

2
third_party/jpeg-xl/lib/extras/enc/jpg.cc поставляемый
Просмотреть файл

@ -284,7 +284,7 @@ Status EncodeWithLibJpeg(const PackedImage& image, const JxlBasicInfo& info,
cinfo.input_components = info.num_color_channels;
cinfo.in_color_space = info.num_color_channels == 1 ? JCS_GRAYSCALE : JCS_RGB;
jpeg_set_defaults(&cinfo);
cinfo.optimize_coding = params.optimize_coding;
cinfo.optimize_coding = static_cast<boolean>(params.optimize_coding);
if (cinfo.input_components == 3) {
JXL_RETURN_IF_ERROR(
SetChromaSubsampling(params.chroma_subsampling, &cinfo));

12
third_party/jpeg-xl/lib/extras/enc/jxl.cc поставляемый
Просмотреть файл

@ -167,6 +167,16 @@ bool EncodeImageJXL(const JXLCompressParams& params, const PackedPixelFile& ppf,
fprintf(stderr, "Storing JPEG metadata failed.\n");
return false;
}
if (params.jpeg_store_metadata && params.jpeg_strip_exif) {
fprintf(stderr,
"Cannot store metadata and strip exif at the same time.\n");
return false;
}
if (params.jpeg_store_metadata && params.jpeg_strip_xmp) {
fprintf(stderr,
"Cannot store metadata and strip xmp at the same time.\n");
return false;
}
if (!params.jpeg_store_metadata && params.jpeg_strip_exif) {
JxlEncoderFrameSettingsSetOption(settings,
JXL_ENC_FRAME_SETTING_JPEG_KEEP_EXIF, 0);
@ -248,7 +258,7 @@ bool EncodeImageJXL(const JXLCompressParams& params, const PackedPixelFile& ppf,
fprintf(stderr, "JxlEncoderSetFrameLossless() failed.\n");
return false;
}
if (!ppf.icc.empty()) {
if (ppf.primary_color_representation == PackedPixelFile::kIccIsPrimary) {
if (JXL_ENC_SUCCESS !=
JxlEncoderSetICCProfile(enc, ppf.icc.data(), ppf.icc.size())) {
fprintf(stderr, "JxlEncoderSetICCProfile() failed.\n");

2
third_party/jpeg-xl/lib/extras/enc/jxl.h поставляемый
Просмотреть файл

@ -38,7 +38,7 @@ struct JXLCompressParams {
std::vector<JXLOption> options;
// Target butteraugli distance, 0.0 means lossless.
float distance = 1.0f;
float alpha_distance = 1.0f;
float alpha_distance = 0.0f;
// If set to true, forces container mode.
bool use_container = false;
// Whether to enable/disable byte-exact jpeg reconstruction for jpeg inputs.

5
third_party/jpeg-xl/lib/extras/mmap.cc поставляемый
Просмотреть файл

@ -10,7 +10,8 @@
#include "lib/jxl/base/common.h"
#if __unix__
#if defined(__unix__) || defined(__unix) || \
defined(__APPLE__) && defined(__MACH__)
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
@ -97,6 +98,8 @@ struct MemoryMappedFileImpl {
return f;
}
~MemoryMappedFileImpl() { UnmapViewOfFile(ptr); }
const uint8_t* data() const { return reinterpret_cast<const uint8_t*>(ptr); }
size_t size() const { return fsize.QuadPart; }

16
third_party/jpeg-xl/lib/extras/packed_image.h поставляемый
Просмотреть файл

@ -244,9 +244,21 @@ class PackedPixelFile {
std::vector<PackedExtraChannel> extra_channels_info;
// Color information of the decoded pixels.
// If the icc is empty, the JxlColorEncoding should be used instead.
std::vector<uint8_t> icc;
// `primary_color_representation` indicates whether `color_encoding` or `icc`
// is the “authoritative” encoding of the colorspace, as opposed to a fallback
// encoding. For example, if `color_encoding` is the primary one, as would
// occur when decoding a jxl file with such a representation, then `enc/jxl`
// will use it and ignore the ICC profile, whereas `enc/png` will include the
// ICC profile for compatibility.
// If `icc` is the primary representation, `enc/jxl` will preserve it when
// compressing losslessly, but *may* encode it as a color_encoding when
// compressing lossily.
enum {
kColorEncodingIsPrimary,
kIccIsPrimary
} primary_color_representation = kColorEncodingIsPrimary;
JxlColorEncoding color_encoding = {};
std::vector<uint8_t> icc;
// The icc profile of the original image.
std::vector<uint8_t> orig_icc;

Просмотреть файл

@ -64,7 +64,8 @@ Status ConvertPackedFrameToImageBundle(const JxlBasicInfo& info,
bundle->extra_channels().resize(io.metadata.m.extra_channel_info.size());
for (size_t i = 0; i < frame.extra_channels.size(); i++) {
const auto& ppf_ec = frame.extra_channels[i];
bundle->extra_channels()[i] = ImageF(ppf_ec.xsize, ppf_ec.ysize);
JXL_ASSIGN_OR_RETURN(bundle->extra_channels()[i],
ImageF::Create(ppf_ec.xsize, ppf_ec.ysize));
JXL_CHECK(BufferToImageF(ppf_ec.format, ppf_ec.xsize, ppf_ec.ysize,
ppf_ec.pixels(), ppf_ec.pixels_size, pool,
&bundle->extra_channels()[i]));
@ -113,7 +114,7 @@ Status ConvertPackedPixelFileToCodecInOut(const PackedPixelFile& ppf,
io->metadata.m.animation.num_loops = ppf.info.animation.num_loops;
// Convert the color encoding.
if (!ppf.icc.empty()) {
if (ppf.primary_color_representation == PackedPixelFile::kIccIsPrimary) {
IccBytes icc = ppf.icc;
if (!io->metadata.m.color_encoding.SetICC(std::move(icc),
JxlGetDefaultCms())) {
@ -274,6 +275,9 @@ Status ConvertCodecInOutToPackedPixelFile(const CodecInOut& io,
// Convert the color encoding
ppf->icc.assign(c_desired.ICC().begin(), c_desired.ICC().end());
ppf->primary_color_representation =
c_desired.WantICC() ? PackedPixelFile::kIccIsPrimary
: PackedPixelFile::kColorEncodingIsPrimary;
ppf->color_encoding = c_desired.ToExternal();
// Convert the extra blobs
@ -304,7 +308,7 @@ Status ConvertCodecInOutToPackedPixelFile(const CodecInOut& io,
packed_frame.name = frame.name;
packed_frame.frame_info.name_length = frame.name.size();
// Color transform
ImageBundle ib = frame.Copy();
JXL_ASSIGN_OR_RETURN(ImageBundle ib, frame.Copy());
const ImageBundle* to_color_transform = &ib;
ImageMetadata metadata = io.metadata.m;
ImageBundle store(&metadata);

Просмотреть файл

@ -10,7 +10,7 @@
namespace jxl {
static void BM_ToneMapping(benchmark::State& state) {
Image3F color(2268, 1512);
JXL_ASSIGN_OR_DIE(Image3F color, Image3F::Create(2268, 1512));
FillImage(0.5f, &color);
// Use linear Rec. 2020 so that `ToneMapTo` doesn't have to convert to it and
@ -25,7 +25,8 @@ static void BM_ToneMapping(benchmark::State& state) {
for (auto _ : state) {
state.PauseTiming();
CodecInOut tone_mapping_input;
Image3F color2(color.xsize(), color.ysize());
JXL_ASSIGN_OR_DIE(Image3F color2,
Image3F::Create(color.xsize(), color.ysize()));
CopyImageTo(color, &color2);
tone_mapping_input.SetFromImage(std::move(color2), linear_rec2020);
tone_mapping_input.metadata.m.SetIntensityTarget(255);

Просмотреть файл

@ -29,10 +29,10 @@ extern "C" {
/** Parses an ICC profile and populates @p c and @p cmyk with the data.
*
* @param user_data JxlCmsInterface::set_fields_data passed as-is.
* @param user_data @ref JxlCmsInterface::set_fields_data passed as-is.
* @param icc_data the ICC data to parse.
* @param icc_size how many bytes of icc_data are valid.
* @param c a JxlColorEncoding to populate if applicable.
* @param c a @ref JxlColorEncoding to populate if applicable.
* @param cmyk a boolean to set to whether the colorspace is a CMYK colorspace.
* @return Whether the relevant fields in @p c were successfully populated.
*/
@ -66,22 +66,23 @@ typedef struct {
/** Allocates and returns the data needed for @p num_threads parallel transforms
* from the @p input colorspace to @p output, with up to @p pixels_per_thread
* pixels to transform per call to JxlCmsInterface::run. @p init_data comes
* directly from the JxlCmsInterface instance. Since @c run only receives the
* data returned by @c init, a reference to @p init_data should be kept there
* if access to it is desired in @c run. Likewise for JxlCmsInterface::destroy.
* pixels to transform per call to @ref JxlCmsInterface::run. @p init_data comes
* directly from the @ref JxlCmsInterface instance. Since @c run only receives
* the data returned by @c init, a reference to @p init_data should be kept
* there if access to it is desired in @c run. Likewise for @ref
* JxlCmsInterface::destroy.
*
* The ICC data in @p input and @p output is guaranteed to outlive the @c init /
* @c run / @c destroy cycle.
*
* @param init_data JxlCmsInterface::init_data passed as-is.
* @param init_data @ref JxlCmsInterface::init_data passed as-is.
* @param num_threads the maximum number of threads from which
* JxlCmsInterface::run will be called.
* @ref JxlCmsInterface::run will be called.
* @param pixels_per_thread the maximum number of pixels that each call to
* JxlCmsInterface::run will have to transform.
* @ref JxlCmsInterface::run will have to transform.
* @param input_profile the input colorspace for the transform.
* @param output_profile the colorspace to which JxlCmsInterface::run should
* convert the input data.
* @param output_profile the colorspace to which @ref JxlCmsInterface::run
* should convert the input data.
* @param intensity_target for colorspaces where luminance is relative
* (essentially: not PQ), indicates the luminance at which (1, 1, 1) will
* be displayed. This is useful for conversions between PQ and a relative
@ -135,7 +136,7 @@ typedef float* (*jpegxl_cms_get_buffer_func)(void* user_data, size_t thread);
* @param output_buffer the buffer receiving the transformed pixel data.
* @param num_pixels the number of pixels to transform from @p input to
* @p output.
* @return JXL_TRUE on success, JXL_FALSE on failure.
* @return ::JXL_TRUE on success, ::JXL_FALSE on failure.
*/
typedef JXL_BOOL (*jpegxl_cms_run_func)(void* user_data, size_t thread,
const float* input_buffer,
@ -226,7 +227,7 @@ typedef void (*jpegxl_cms_destroy_func)(void*);
typedef struct {
/** CMS-specific data that will be passed to @ref set_fields_from_icc. */
void* set_fields_data;
/** Populates a JxlColorEncoding from an ICC profile. */
/** Populates a @ref JxlColorEncoding from an ICC profile. */
jpegxl_cms_set_fields_from_icc_func set_fields_from_icc;
/** CMS-specific data that will be passed to @ref init. */

Просмотреть файл

@ -71,7 +71,7 @@ typedef struct {
} JxlPreviewHeader;
/** The codestream animation header, optionally present in the beginning of
* the codestream, and if it is it applies to all animation frames, unlike
* the codestream, and if it is it applies to all animation frames, unlike @ref
* JxlFrameHeader which applies to an individual frame.
*/
typedef struct {
@ -166,12 +166,12 @@ typedef struct {
* it to to the original color profile. The decoder also does not convert to
* the target display color profile. To convert the pixel data produced by
* the decoder to the original color profile, one of the JxlDecoderGetColor*
* functions needs to be called with @ref JXL_COLOR_PROFILE_TARGET_DATA to get
* the color profile of the decoder output, and then an external CMS can be
* used for conversion.
* Note that for lossy compression, this should be set to false for most use
* cases, and if needed, the image should be converted to the original color
* profile after decoding, as described above.
* functions needs to be called with
* ::JXL_COLOR_PROFILE_TARGET_DATA to get the color profile of the decoder
* output, and then an external CMS can be used for conversion. Note that for
* lossy compression, this should be set to false for most use cases, and if
* needed, the image should be converted to the original color profile after
* decoding, as described above.
*/
JXL_BOOL uses_original_profile;
@ -194,17 +194,19 @@ typedef struct {
* grayscale data, or 3 for colored data. This count does not include
* the alpha channel or other extra channels. To check presence of an alpha
* channel, such as in the case of RGBA color, check alpha_bits != 0.
* If and only if this is 1, the JxlColorSpace in the JxlColorEncoding is
* JXL_COLOR_SPACE_GRAY.
* If and only if this is 1, the @ref JxlColorSpace in the @ref
* JxlColorEncoding is
* ::JXL_COLOR_SPACE_GRAY.
*/
uint32_t num_color_channels;
/** Number of additional image channels. This includes the main alpha channel,
* but can also include additional channels such as depth, additional alpha
* channels, spot colors, and so on. Information about the extra channels
* can be queried with JxlDecoderGetExtraChannelInfo. The main alpha channel,
* if it exists, also has its information available in the alpha_bits,
* alpha_exponent_bits and alpha_premultiplied fields in this JxlBasicInfo.
* can be queried with @ref JxlDecoderGetExtraChannelInfo. The main alpha
* channel, if it exists, also has its information available in the
* alpha_bits, alpha_exponent_bits and alpha_premultiplied fields in this @ref
* JxlBasicInfo.
*/
uint32_t num_extra_channels;
@ -388,7 +390,8 @@ typedef struct {
/** The header of one displayed frame or non-coalesced layer. */
typedef struct {
/** How long to wait after rendering in ticks. The duration in seconds of a
* tick is given by tps_numerator and tps_denominator in JxlAnimationHeader.
* tick is given by tps_numerator and tps_denominator in @ref
* JxlAnimationHeader.
*/
uint32_t duration;
@ -396,9 +399,9 @@ typedef struct {
* interpreted from most-significant to least-significant as hour, minute,
* second, and frame. If timecode is nonzero, it is strictly larger than that
* of a previous frame with nonzero duration. These values are only available
* if have_timecodes in JxlAnimationHeader is JXL_TRUE.
* This value is only used if have_timecodes in JxlAnimationHeader is
* JXL_TRUE.
* if have_timecodes in @ref JxlAnimationHeader is ::JXL_TRUE.
* This value is only used if have_timecodes in @ref JxlAnimationHeader is
* ::JXL_TRUE.
*/
uint32_t timecode;

Просмотреть файл

@ -24,9 +24,9 @@ extern "C" {
typedef enum {
/** Tristimulus RGB */
JXL_COLOR_SPACE_RGB,
/** Luminance based, the primaries in JxlColorEncoding must be ignored. This
* value implies that num_color_channels in JxlBasicInfo is 1, any other value
* implies num_color_channels is 3. */
/** Luminance based, the primaries in @ref JxlColorEncoding must be ignored.
* This value implies that num_color_channels in @ref JxlBasicInfo is 1, any
* other value implies num_color_channels is 3. */
JXL_COLOR_SPACE_GRAY,
/** XYB (opsin) color space */
JXL_COLOR_SPACE_XYB,
@ -35,18 +35,18 @@ typedef enum {
} JxlColorSpace;
/** Built-in whitepoints for color encoding. When decoding, the numerical xy
* whitepoint value can be read from the JxlColorEncoding white_point field
* whitepoint value can be read from the @ref JxlColorEncoding white_point field
* regardless of the enum value. When encoding, enum values except
* JXL_WHITE_POINT_CUSTOM override the numerical fields. Some enum values match
* a subset of CICP (Rec. ITU-T H.273 | ISO/IEC 23091-2:2019(E)), however the
* white point and RGB primaries are separate enums here.
* ::JXL_WHITE_POINT_CUSTOM override the numerical fields. Some enum values
* match a subset of CICP (Rec. ITU-T H.273 | ISO/IEC 23091-2:2019(E)), however
* the white point and RGB primaries are separate enums here.
*/
typedef enum {
/** CIE Standard Illuminant D65: 0.3127, 0.3290 */
JXL_WHITE_POINT_D65 = 1,
/** White point must be read from the JxlColorEncoding white_point field, or
* as ICC profile. This enum value is not an exact match of the corresponding
* CICP value. */
/** White point must be read from the @ref JxlColorEncoding white_point field,
* or as ICC profile. This enum value is not an exact match of the
* corresponding CICP value. */
JXL_WHITE_POINT_CUSTOM = 2,
/** CIE Standard Illuminant E (equal-energy): 1/3, 1/3 */
JXL_WHITE_POINT_E = 10,
@ -55,10 +55,10 @@ typedef enum {
} JxlWhitePoint;
/** Built-in primaries for color encoding. When decoding, the primaries can be
* read from the JxlColorEncoding primaries_red_xy, primaries_green_xy and
* read from the @ref JxlColorEncoding primaries_red_xy, primaries_green_xy and
* primaries_blue_xy fields regardless of the enum value. When encoding, the
* enum values except JXL_PRIMARIES_CUSTOM override the numerical fields. Some
* enum values match a subset of CICP (Rec. ITU-T H.273 | ISO/IEC
* enum values except ::JXL_PRIMARIES_CUSTOM override the numerical fields.
* Some enum values match a subset of CICP (Rec. ITU-T H.273 | ISO/IEC
* 23091-2:2019(E)), however the white point and RGB primaries are separate
* enums here.
*/
@ -66,7 +66,7 @@ typedef enum {
/** The CIE xy values of the red, green and blue primaries are: 0.639998686,
0.330010138; 0.300003784, 0.600003357; 0.150002046, 0.059997204 */
JXL_PRIMARIES_SRGB = 1,
/** Primaries must be read from the JxlColorEncoding primaries_red_xy,
/** Primaries must be read from the @ref JxlColorEncoding primaries_red_xy,
* primaries_green_xy and primaries_blue_xy fields, or as ICC profile. This
* enum value is not an exact match of the corresponding CICP value. */
JXL_PRIMARIES_CUSTOM = 2,
@ -94,7 +94,7 @@ typedef enum {
JXL_TRANSFER_FUNCTION_DCI = 17,
/** As specified in Rec. ITU-R BT.2100-1 (HLG) */
JXL_TRANSFER_FUNCTION_HLG = 18,
/** Transfer function follows power law given by the gamma value in
/** Transfer function follows power law given by the gamma value in @ref
JxlColorEncoding. Not a CICP value. */
JXL_TRANSFER_FUNCTION_GAMMA = 65535,
} JxlTransferFunction;
@ -118,7 +118,7 @@ typedef struct {
*/
JxlColorSpace color_space;
/** Built-in white point. If this value is JXL_WHITE_POINT_CUSTOM, must
/** Built-in white point. If this value is ::JXL_WHITE_POINT_CUSTOM, must
* use the numerical whitepoint values from white_point_xy.
*/
JxlWhitePoint white_point;
@ -126,10 +126,10 @@ typedef struct {
/** Numerical whitepoint values in CIE xy space. */
double white_point_xy[2];
/** Built-in RGB primaries. If this value is JXL_PRIMARIES_CUSTOM, must
/** Built-in RGB primaries. If this value is ::JXL_PRIMARIES_CUSTOM, must
* use the numerical primaries values below. This field and the custom values
* below are unused and must be ignored if the color space is
* JXL_COLOR_SPACE_GRAY or JXL_COLOR_SPACE_XYB.
* ::JXL_COLOR_SPACE_GRAY or ::JXL_COLOR_SPACE_XYB.
*/
JxlPrimaries primaries;
@ -145,7 +145,8 @@ typedef struct {
/** Transfer function if have_gamma is 0 */
JxlTransferFunction transfer_function;
/** Gamma value used when transfer_function is JXL_TRANSFER_FUNCTION_GAMMA
/** Gamma value used when transfer_function is @ref
* JXL_TRANSFER_FUNCTION_GAMMA
*/
double gamma;

411
third_party/jpeg-xl/lib/include/jxl/decode.h поставляемый
Просмотреть файл

@ -66,12 +66,12 @@ typedef enum {
* @p size doesn't need to be a full image, only the beginning of the file.
*
* @return a flag indicating if a JPEG XL signature was found and what type.
* - @ref JXL_SIG_NOT_ENOUGH_BYTES if not enough bytes were passed to
* - ::JXL_SIG_NOT_ENOUGH_BYTES if not enough bytes were passed to
* determine if a valid signature is there.
* - @ref JXL_SIG_INVALID if no valid signature found for JPEG XL decoding.
* - @ref JXL_SIG_CODESTREAM if a valid JPEG XL codestream signature was
* - ::JXL_SIG_INVALID if no valid signature found for JPEG XL decoding.
* - ::JXL_SIG_CODESTREAM if a valid JPEG XL codestream signature was
* found.
* - @ref JXL_SIG_CONTAINER if a valid JPEG XL container signature was found.
* - ::JXL_SIG_CONTAINER if a valid JPEG XL container signature was found.
*/
JXL_EXPORT JxlSignature JxlSignatureCheck(const uint8_t* buf, size_t len);
@ -115,7 +115,7 @@ JXL_EXPORT void JxlDecoderDestroy(JxlDecoder* dec);
/**
* Return value for @ref JxlDecoderProcessInput.
* The values from @ref JXL_DEC_BASIC_INFO onwards are optional informative
* The values from ::JXL_DEC_BASIC_INFO onwards are optional informative
* events that can be subscribed to, they are never returned if they
* have not been registered with @ref JxlDecoderSubscribeEvents.
*/
@ -123,12 +123,12 @@ typedef enum {
/** Function call finished successfully, or decoding is finished and there is
* nothing more to be done.
*
* Note that @ref JxlDecoderProcessInput will return JXL_DEC_SUCCESS if all
* events that were registered with @ref JxlDecoderSubscribeEvents were
* Note that @ref JxlDecoderProcessInput will return ::JXL_DEC_SUCCESS if
* all events that were registered with @ref JxlDecoderSubscribeEvents were
* processed, even before the end of the JPEG XL codestream.
*
* In this case, the return value @ref JxlDecoderReleaseInput will be the same
* as it was at the last signaled event. E.g. if JXL_DEC_FULL_IMAGE was
* as it was at the last signaled event. E.g. if ::JXL_DEC_FULL_IMAGE was
* subscribed to, then all bytes from the end of the JPEG XL codestream
* (including possible boxes needed for jpeg reconstruction) will be returned
* as unprocessed.
@ -151,14 +151,14 @@ typedef enum {
* In most cases, @ref JxlDecoderReleaseInput will return no unprocessed bytes
* at this event, the only exceptions are if the previously set input ended
* within (a) the raw codestream signature, (b) the signature box, (c) a box
* header, or (d) the first 4 bytes of a brob, ftyp, or jxlp box. In any of
* these cases the number of unprocessed bytes is less than 20.
* header, or (d) the first 4 bytes of a `brob`, `ftyp`, or `jxlp` box. In any
* of these cases the number of unprocessed bytes is less than 20.
*/
JXL_DEC_NEED_MORE_INPUT = 2,
/** The decoder is able to decode a preview image and requests setting a
* preview output buffer using @ref JxlDecoderSetPreviewOutBuffer. This occurs
* if @ref JXL_DEC_PREVIEW_IMAGE is requested and it is possible to decode a
* if ::JXL_DEC_PREVIEW_IMAGE is requested and it is possible to decode a
* preview image from the codestream and the preview out buffer was not yet
* set. There is maximum one preview image in a codestream.
* In this case, @ref JxlDecoderReleaseInput will return all bytes from the
@ -179,13 +179,13 @@ typedef enum {
/** The JPEG reconstruction buffer is too small for reconstructed JPEG
* codestream to fit. @ref JxlDecoderSetJPEGBuffer must be called again to
* make room for remaining bytes. This event may occur multiple times
* after @ref JXL_DEC_JPEG_RECONSTRUCTION.
* after ::JXL_DEC_JPEG_RECONSTRUCTION.
*/
JXL_DEC_JPEG_NEED_MORE_OUTPUT = 6,
/** The box contents output buffer is too small. @ref JxlDecoderSetBoxBuffer
* must be called again to make room for remaining bytes. This event may occur
* multiple times after @ref JXL_DEC_BOX.
* multiple times after ::JXL_DEC_BOX.
*/
JXL_DEC_BOX_NEED_MORE_OUTPUT = 7,
@ -201,7 +201,7 @@ typedef enum {
/** Informative event by @ref JxlDecoderProcessInput
* "JxlDecoderProcessInput": Color encoding or ICC profile from the
* codestream header. This event occurs max once per image and always later
* than @ref JXL_DEC_BASIC_INFO and earlier than any pixel data.
* than ::JXL_DEC_BASIC_INFO and earlier than any pixel data.
* In this case, @ref JxlDecoderReleaseInput will return all bytes from the
* end of the image header (which is the start of the first frame) as
* unprocessed.
@ -212,7 +212,7 @@ typedef enum {
* "JxlDecoderProcessInput": Preview image, a small frame, decoded. This
* event can only happen if the image has a preview frame encoded. This event
* occurs max once for the codestream and always later than @ref
* JXL_DEC_COLOR_ENCODING and before @ref JXL_DEC_FRAME.
* JXL_DEC_COLOR_ENCODING and before ::JXL_DEC_FRAME.
* In this case, @ref JxlDecoderReleaseInput will return all bytes from the
* end of the preview frame as unprocessed.
*/
@ -223,19 +223,19 @@ typedef enum {
* JxlDecoderGetFrameHeader can be used at this point. A note on frames:
* a JPEG XL image can have internal frames that are not intended to be
* displayed (e.g. used for compositing a final frame), but this only returns
* displayed frames, unless @ref JxlDecoderSetCoalescing was set to JXL_FALSE:
* in that case, the individual layers are returned, without blending. Note
* that even when coalescing is disabled, only frames of type kRegularFrame
* are returned; frames of type kReferenceOnly and kLfFrame are always for
* internal purposes only and cannot be accessed. A displayed frame either has
* an animation duration or is the only or last frame in the image. This event
* occurs max once per displayed frame, always later than @ref
* JXL_DEC_COLOR_ENCODING, and always earlier than any pixel data. While
* JPEG XL supports encoding a single frame as the composition of multiple
* internal sub-frames also called frames, this event is not indicated for the
* internal frames.
* In this case, @ref JxlDecoderReleaseInput will return all bytes from the
* end of the frame header (including ToC) as unprocessed.
* displayed frames, unless @ref JxlDecoderSetCoalescing was set to @ref
* JXL_FALSE "JXL_FALSE": in that case, the individual layers are returned,
* without blending. Note that even when coalescing is disabled, only frames
* of type kRegularFrame are returned; frames of type kReferenceOnly
* and kLfFrame are always for internal purposes only and cannot be accessed.
* A displayed frame either has an animation duration or is the only or last
* frame in the image. This event occurs max once per displayed frame, always
* later than ::JXL_DEC_COLOR_ENCODING, and always earlier than any pixel
* data. While JPEG XL supports encoding a single frame as the composition of
* multiple internal sub-frames also called frames, this event is not
* indicated for the internal frames. In this case, @ref
* JxlDecoderReleaseInput will return all bytes from the end of the frame
* header (including ToC) as unprocessed.
*/
JXL_DEC_FRAME = 0x400,
@ -246,7 +246,7 @@ typedef enum {
* not this return status only indicates we're past this point in the
* codestream. This event occurs max once per frame.
* In this case, @ref JxlDecoderReleaseInput will return all bytes from the
* end of the frame (or if @ref JXL_DEC_JPEG_RECONSTRUCTION is subscribed to,
* end of the frame (or if ::JXL_DEC_JPEG_RECONSTRUCTION is subscribed to,
* from the end of the last box that is needed for jpeg reconstruction) as
* unprocessed.
*/
@ -259,9 +259,9 @@ typedef enum {
* is set a byte stream identical to the JPEG codestream used to encode the
* image will be written to the JPEG reconstruction buffer instead of pixels
* to the image out buffer. This event occurs max once per image and always
* before @ref JXL_DEC_FULL_IMAGE.
* before ::JXL_DEC_FULL_IMAGE.
* In this case, @ref JxlDecoderReleaseInput will return all bytes from the
* end of the 'jbrd' box as unprocessed.
* end of the `jbrd` box as unprocessed.
*/
JXL_DEC_JPEG_RECONSTRUCTION = 0x2000,
@ -290,8 +290,8 @@ typedef enum {
*
* The buffer set with @ref JxlDecoderSetBoxBuffer must be set again for each
* next box to be obtained, or can be left unset to skip outputting this box.
* The output buffer contains the full box data when the next @ref JXL_DEC_BOX
* event or @ref JXL_DEC_SUCCESS occurs. @ref JXL_DEC_BOX occurs for all
* The output buffer contains the full box data when the next ::JXL_DEC_BOX
* event or ::JXL_DEC_SUCCESS occurs. ::JXL_DEC_BOX occurs for all
* boxes, including non-metadata boxes such as the signature box or codestream
* boxes. To check whether the box is a metadata type for respectively EXIF,
* XMP or JUMBF, use @ref JxlDecoderGetBoxType and check for types "Exif",
@ -324,26 +324,40 @@ typedef enum {
* Setting a progressive detail with value N implies all progressive details
* with smaller or equal value. Currently only the following level of
* progressive detail is implemented:
* - kDC (which implies kFrames)
* - kLastPasses (which implies kDC and kFrames)
* - kPasses (which implies kLastPasses, kDC and kFrames)
* - @ref kDC (which implies kFrames)
* - @ref kLastPasses (which implies @ref kDC and @ref kFrames)
* - @ref kPasses (which implies @ref kLastPasses, kDC and @ref kFrames)
*/
typedef enum {
// after completed kRegularFrames
/**
* after completed kRegularFrames
*/
kFrames = 0,
// after completed DC (1:8)
/**
* after completed DC (1:8)
*/
kDC = 1,
// after completed AC passes that are the last pass for their resolution
// target.
/**
* after completed AC passes that are the last pass for their resolution
* target.
*/
kLastPasses = 2,
// after completed AC passes that are not the last pass for their resolution
// target.
/**
* after completed AC passes that are not the last pass for their resolution
* target.
*/
kPasses = 3,
// during DC frame when lower resolution are completed (1:32, 1:16)
/**
* during DC frame when lower resolution are completed (1:32, 1:16)
*/
kDCProgressive = 4,
// after completed groups
/**
* after completed groups
*/
kDCGroups = 5,
// after completed groups
/**
* after completed groups
*/
kGroups = 6,
} JxlProgressiveDetail;
@ -354,8 +368,8 @@ typedef enum {
* more efficiently with @ref JxlDecoderSkipFrames. Settings such as parallel
* runner or subscribed events are kept. After rewind, @ref
* JxlDecoderSubscribeEvents can be used again, and it is feasible to leave out
* events that were already handled before, such as @ref JXL_DEC_BASIC_INFO
* and @ref JXL_DEC_COLOR_ENCODING, since they will provide the same information
* events that were already handled before, such as ::JXL_DEC_BASIC_INFO
* and ::JXL_DEC_COLOR_ENCODING, since they will provide the same information
* as before.
* The difference to @ref JxlDecoderReset is that some state is kept, namely
* settings set by a call to
@ -376,14 +390,14 @@ JXL_EXPORT void JxlDecoderRewind(JxlDecoder* dec);
* the input, but will not output the frame events. It can be more efficient
* when skipping frames, and even more so when using this after @ref
* JxlDecoderRewind. If the decoder is already processing a frame (could
* have emitted @ref JXL_DEC_FRAME but not yet @ref JXL_DEC_FULL_IMAGE), it
* have emitted ::JXL_DEC_FRAME but not yet ::JXL_DEC_FULL_IMAGE), it
* starts skipping from the next frame. If the amount is larger than the amount
* of frames remaining in the image, all remaining frames are skipped. Calling
* this function multiple times adds the amount to skip to the already existing
* amount.
*
* A frame here is defined as a frame that without skipping emits events such
* as @ref JXL_DEC_FRAME and @ref JXL_DEC_FULL_IMAGE, frames that are internal
* as ::JXL_DEC_FRAME and ::JXL_DEC_FULL_IMAGE, frames that are internal
* to the file format but are not rendered as part of an animation, or are not
* the final still frame of a still image, are not counted.
*
@ -394,14 +408,14 @@ JXL_EXPORT void JxlDecoderSkipFrames(JxlDecoder* dec, size_t amount);
/**
* Skips processing the current frame. Can be called after frame processing
* already started, signaled by a @ref JXL_DEC_NEED_IMAGE_OUT_BUFFER event,
* but before the corresponding @ref JXL_DEC_FULL_IMAGE event. The next signaled
* event will be another @ref JXL_DEC_FRAME, or @ref JXL_DEC_SUCCESS if there
* already started, signaled by a ::JXL_DEC_NEED_IMAGE_OUT_BUFFER event,
* but before the corresponding ::JXL_DEC_FULL_IMAGE event. The next signaled
* event will be another ::JXL_DEC_FRAME, or ::JXL_DEC_SUCCESS if there
* are no more frames. If pixel data is required from the already processed part
* of the frame, @ref JxlDecoderFlushImage must be called before this.
*
* @param dec decoder object
* @return @ref JXL_DEC_SUCCESS if there is a frame to skip, and @ref
* @return ::JXL_DEC_SUCCESS if there is a frame to skip, and @ref
* JXL_DEC_ERROR if the function was not called during frame processing.
*/
JXL_EXPORT JxlDecoderStatus JxlDecoderSkipCurrentFrame(JxlDecoder* dec);
@ -415,7 +429,7 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderSkipCurrentFrame(JxlDecoder* dec);
* be NULL to use the default, single-threaded, runner. A multithreaded
* runner should be set to reach fast performance.
* @param parallel_runner_opaque opaque pointer for parallel_runner.
* @return @ref JXL_DEC_SUCCESS if the runner was set, @ref JXL_DEC_ERROR
* @return ::JXL_DEC_SUCCESS if the runner was set, ::JXL_DEC_ERROR
* otherwise (the previous runner remains set).
*/
JXL_EXPORT JxlDecoderStatus
@ -439,7 +453,7 @@ JxlDecoderSetParallelRunner(JxlDecoder* dec, JxlParallelRunner parallel_runner,
*/
JXL_EXPORT size_t JxlDecoderSizeHintBasicInfo(const JxlDecoder* dec);
/** Select for which informative events, i.e. @ref JXL_DEC_BASIC_INFO, etc., the
/** Select for which informative events, i.e. ::JXL_DEC_BASIC_INFO, etc., the
* decoder should return with a status. It is not required to subscribe to any
* events, data can still be requested from the decoder as soon as it available.
* By default, the decoder is subscribed to no events (events_wanted == 0), and
@ -449,7 +463,7 @@ JXL_EXPORT size_t JxlDecoderSizeHintBasicInfo(const JxlDecoder* dec);
*
* @param dec decoder object
* @param events_wanted bitfield of desired events.
* @return @ref JXL_DEC_SUCCESS if no error, @ref JXL_DEC_ERROR otherwise.
* @return ::JXL_DEC_SUCCESS if no error, ::JXL_DEC_ERROR otherwise.
*/
JXL_EXPORT JxlDecoderStatus JxlDecoderSubscribeEvents(JxlDecoder* dec,
int events_wanted);
@ -459,14 +473,14 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderSubscribeEvents(JxlDecoder* dec,
* indicating that the decoder must perform a rotation and/or
* mirroring to the encoded image data.
*
* - If skip_reorientation is JXL_FALSE (the default): the decoder
* - If skip_reorientation is ::JXL_FALSE (the default): the decoder
* will apply the transformation from the orientation setting, hence
* rendering the image according to its specified intent. When
* producing a JxlBasicInfo, the decoder will always set the
* producing a @ref JxlBasicInfo, the decoder will always set the
* orientation field to JXL_ORIENT_IDENTITY (matching the returned
* pixel data) and also align xsize and ysize so that they correspond
* to the width and the height of the returned pixel data.
* - If skip_reorientation is JXL_TRUE: the decoder will skip
* - If skip_reorientation is ::JXL_TRUE "JXL_TRUE": the decoder will skip
* applying the transformation from the orientation setting, returning
* the image in the as-in-bitstream pixeldata orientation.
* This may be faster to decode since the decoder doesn't have to apply the
@ -483,17 +497,18 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderSubscribeEvents(JxlDecoder* dec,
*
* @param dec decoder object
* @param skip_reorientation JXL_TRUE to enable, JXL_FALSE to disable.
* @return @ref JXL_DEC_SUCCESS if no error, @ref JXL_DEC_ERROR otherwise.
* @return ::JXL_DEC_SUCCESS if no error, ::JXL_DEC_ERROR otherwise.
*/
JXL_EXPORT JxlDecoderStatus
JxlDecoderSetKeepOrientation(JxlDecoder* dec, JXL_BOOL skip_reorientation);
/**
* Enables or disables preserving of associated alpha channels. If
* unpremul_alpha is set to JXL_FALSE then for associated alpha channel, the
* pixel data is returned with premultiplied colors. If it is set to JXL_TRUE,
* The colors will be unpremultiplied based on the alpha channel. This function
* has no effect if the image does not have an associated alpha channel.
* unpremul_alpha is set to ::JXL_FALSE then for associated alpha channel,
* the pixel data is returned with premultiplied colors. If it is set to @ref
* JXL_TRUE, The colors will be unpremultiplied based on the alpha channel. This
* function has no effect if the image does not have an associated alpha
* channel.
*
* By default, this option is disabled, and the returned pixel data "as is".
*
@ -501,20 +516,20 @@ JxlDecoderSetKeepOrientation(JxlDecoder* dec, JXL_BOOL skip_reorientation);
*
* @param dec decoder object
* @param unpremul_alpha JXL_TRUE to enable, JXL_FALSE to disable.
* @return @ref JXL_DEC_SUCCESS if no error, @ref JXL_DEC_ERROR otherwise.
* @return ::JXL_DEC_SUCCESS if no error, ::JXL_DEC_ERROR otherwise.
*/
JXL_EXPORT JxlDecoderStatus
JxlDecoderSetUnpremultiplyAlpha(JxlDecoder* dec, JXL_BOOL unpremul_alpha);
/** Enables or disables rendering spot colors. By default, spot colors
* are rendered, which is OK for viewing the decoded image. If render_spotcolors
* is JXL_FALSE, then spot colors are not rendered, and have to be retrieved
* separately using @ref JxlDecoderSetExtraChannelBuffer. This is useful for
* e.g. printing applications.
* is ::JXL_FALSE, then spot colors are not rendered, and have to be
* retrieved separately using @ref JxlDecoderSetExtraChannelBuffer. This is
* useful for e.g. printing applications.
*
* @param dec decoder object
* @param render_spotcolors JXL_TRUE to enable (default), JXL_FALSE to disable.
* @return @ref JXL_DEC_SUCCESS if no error, @ref JXL_DEC_ERROR otherwise.
* @return ::JXL_DEC_SUCCESS if no error, ::JXL_DEC_ERROR otherwise.
*/
JXL_EXPORT JxlDecoderStatus
JxlDecoderSetRenderSpotcolors(JxlDecoder* dec, JXL_BOOL render_spotcolors);
@ -530,7 +545,7 @@ JxlDecoderSetRenderSpotcolors(JxlDecoder* dec, JXL_BOOL render_spotcolors);
* @param dec decoder object
* @param coalescing JXL_TRUE to enable coalescing (default), JXL_FALSE to
* disable it.
* @return @ref JXL_DEC_SUCCESS if no error, @ref JXL_DEC_ERROR otherwise.
* @return ::JXL_DEC_SUCCESS if no error, ::JXL_DEC_ERROR otherwise.
*/
JXL_EXPORT JxlDecoderStatus JxlDecoderSetCoalescing(JxlDecoder* dec,
JXL_BOOL coalescing);
@ -547,32 +562,32 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderSetCoalescing(JxlDecoder* dec,
*
* The returned status indicates whether the decoder needs more input bytes, or
* more output buffer for a certain type of output data. No matter what the
* returned status is (other than @ref JXL_DEC_ERROR), new information, such
* returned status is (other than ::JXL_DEC_ERROR), new information, such
* as @ref JxlDecoderGetBasicInfo, may have become available after this call.
* When the return value is not @ref JXL_DEC_ERROR or @ref JXL_DEC_SUCCESS, the
* When the return value is not ::JXL_DEC_ERROR or ::JXL_DEC_SUCCESS, the
* decoding requires more @ref JxlDecoderProcessInput calls to continue.
*
* @param dec decoder object
* @return @ref JXL_DEC_SUCCESS when decoding finished and all events handled.
* @return ::JXL_DEC_SUCCESS when decoding finished and all events handled.
* If you still have more unprocessed input data anyway, then you can still
* continue by using @ref JxlDecoderSetInput and calling @ref
* JxlDecoderProcessInput again, similar to handling @ref
* JXL_DEC_NEED_MORE_INPUT. @ref JXL_DEC_SUCCESS can occur instead of @ref
* JXL_DEC_NEED_MORE_INPUT. ::JXL_DEC_SUCCESS can occur instead of @ref
* JXL_DEC_NEED_MORE_INPUT when, for example, the input data ended right at
* the boundary of a box of the container format, all essential codestream
* boxes were already decoded, but extra metadata boxes are still present in
* the next data. @ref JxlDecoderProcessInput cannot return success if all
* codestream boxes have not been seen yet.
* @return @ref JXL_DEC_ERROR when decoding failed, e.g. invalid codestream.
* @return ::JXL_DEC_ERROR when decoding failed, e.g. invalid codestream.
* TODO(lode): document the input data mechanism
* @return @ref JXL_DEC_NEED_MORE_INPUT when more input data is necessary.
* @return @ref JXL_DEC_BASIC_INFO when basic info such as image dimensions is
* @return ::JXL_DEC_NEED_MORE_INPUT when more input data is necessary.
* @return ::JXL_DEC_BASIC_INFO when basic info such as image dimensions is
* available and this informative event is subscribed to.
* @return @ref JXL_DEC_COLOR_ENCODING when color profile information is
* @return ::JXL_DEC_COLOR_ENCODING when color profile information is
* available and this informative event is subscribed to.
* @return @ref JXL_DEC_PREVIEW_IMAGE when preview pixel information is
* @return ::JXL_DEC_PREVIEW_IMAGE when preview pixel information is
* available and output in the preview buffer.
* @return @ref JXL_DEC_FULL_IMAGE when all pixel information at highest detail
* @return ::JXL_DEC_FULL_IMAGE when all pixel information at highest detail
* is available and has been output in the pixel buffer.
*/
JXL_EXPORT JxlDecoderStatus JxlDecoderProcessInput(JxlDecoder* dec);
@ -588,8 +603,8 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderProcessInput(JxlDecoder* dec);
* @param dec decoder object
* @param data pointer to next bytes to read from
* @param size amount of bytes available starting from data
* @return @ref JXL_DEC_ERROR if input was already set without releasing or @ref
* JxlDecoderCloseInput was already called, @ref JXL_DEC_SUCCESS otherwise.
* @return ::JXL_DEC_ERROR if input was already set without releasing or @ref
* JxlDecoderCloseInput was already called, ::JXL_DEC_SUCCESS otherwise.
*/
JXL_EXPORT JxlDecoderStatus JxlDecoderSetInput(JxlDecoder* dec,
const uint8_t* data,
@ -602,17 +617,17 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderSetInput(JxlDecoder* dec,
* whenever any input is already set and new input needs to be added with @ref
* JxlDecoderSetInput, but is not required before @ref JxlDecoderDestroy or @ref
* JxlDecoderReset. Calling @ref JxlDecoderReleaseInput when no input is set is
* not an error and returns 0.
* not an error and returns `0`.
*
* @param dec decoder object
* @return The amount of bytes the decoder has not yet processed that are still
* remaining in the data set by @ref JxlDecoderSetInput, or 0 if no input is
* set or @ref JxlDecoderReleaseInput was already called. For a next call
* to @ref JxlDecoderProcessInput, the buffer must start with these
* unprocessed bytes. From this value it is possible to infer the position
* of certain JPEG XL codestream elements (e.g. end of headers, frame
* start/end). See the documentation of individual values of @ref
* JxlDecoderStatus for more information.
* remaining in the data set by @ref JxlDecoderSetInput, or `0` if no input
* is set or @ref JxlDecoderReleaseInput was already called. For a next call to
* @ref JxlDecoderProcessInput, the buffer must start with these unprocessed
* bytes. From this value it is possible to infer the position of certain JPEG
* XL codestream elements (e.g. end of headers, frame start/end). See the
* documentation of individual values of @ref JxlDecoderStatus for more
* information.
*/
JXL_EXPORT size_t JxlDecoderReleaseInput(JxlDecoder* dec);
@ -621,9 +636,9 @@ JXL_EXPORT size_t JxlDecoderReleaseInput(JxlDecoder* dec);
* will be called. This function allows the decoder to determine correctly if it
* should return success, need more input or error in certain cases. For
* backwards compatibility with a previous version of the API, using this
* function is optional when not using the @ref JXL_DEC_BOX event (the decoder
* function is optional when not using the ::JXL_DEC_BOX event (the decoder
* is able to determine the end of the image frames without marking the end),
* but using this function is required when using @ref JXL_DEC_BOX for getting
* but using this function is required when using ::JXL_DEC_BOX for getting
* metadata box contents. This function does not replace @ref
* JxlDecoderReleaseInput, that function should still be called if its return
* value is needed.
@ -643,8 +658,8 @@ JXL_EXPORT void JxlDecoderCloseInput(JxlDecoder* dec);
* @param dec decoder object
* @param info struct to copy the information into, or NULL to only check
* whether the information is available through the return value.
* @return @ref JXL_DEC_SUCCESS if the value is available, @ref
* JXL_DEC_NEED_MORE_INPUT if not yet available, @ref JXL_DEC_ERROR
* @return ::JXL_DEC_SUCCESS if the value is available, @ref
* JXL_DEC_NEED_MORE_INPUT if not yet available, ::JXL_DEC_ERROR
* in case of other error conditions.
*/
JXL_EXPORT JxlDecoderStatus JxlDecoderGetBasicInfo(const JxlDecoder* dec,
@ -652,14 +667,14 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderGetBasicInfo(const JxlDecoder* dec,
/**
* Outputs information for extra channel at the given index. The index must be
* smaller than num_extra_channels in the associated JxlBasicInfo.
* smaller than num_extra_channels in the associated @ref JxlBasicInfo.
*
* @param dec decoder object
* @param index index of the extra channel to query.
* @param info struct to copy the information into, or NULL to only check
* whether the information is available through the return value.
* @return @ref JXL_DEC_SUCCESS if the value is available, @ref
* JXL_DEC_NEED_MORE_INPUT if not yet available, @ref JXL_DEC_ERROR
* @return ::JXL_DEC_SUCCESS if the value is available, @ref
* JXL_DEC_NEED_MORE_INPUT if not yet available, ::JXL_DEC_ERROR
* in case of other error conditions.
*/
JXL_EXPORT JxlDecoderStatus JxlDecoderGetExtraChannelInfo(
@ -667,16 +682,16 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderGetExtraChannelInfo(
/**
* Outputs name for extra channel at the given index in UTF-8. The index must be
* smaller than num_extra_channels in the associated JxlBasicInfo. The buffer
* for name must have at least name_length + 1 bytes allocated, gotten from
* the associated JxlExtraChannelInfo.
* smaller than `num_extra_channels` in the associated @ref JxlBasicInfo. The
* buffer for name must have at least `name_length + 1` bytes allocated, gotten
* from the associated @ref JxlExtraChannelInfo.
*
* @param dec decoder object
* @param index index of the extra channel to query.
* @param name buffer to copy the name into
* @param size size of the name buffer in bytes
* @return @ref JXL_DEC_SUCCESS if the value is available, @ref
* JXL_DEC_NEED_MORE_INPUT if not yet available, @ref JXL_DEC_ERROR
* @return ::JXL_DEC_SUCCESS if the value is available, @ref
* JXL_DEC_NEED_MORE_INPUT if not yet available, ::JXL_DEC_ERROR
* in case of other error conditions.
*/
JXL_EXPORT JxlDecoderStatus JxlDecoderGetExtraChannelName(const JxlDecoder* dec,
@ -719,7 +734,7 @@ typedef enum {
* problematic, in that: while ICC profiles can encode a transfer function
* that happens to approximate those of PQ and HLG (HLG for only one given
* system gamma at a time, and necessitating a 3D LUT if gamma is to be
* different from 1), they cannot (before ICCv4.4) semantically signal that
* different from `1`), they cannot (before ICCv4.4) semantically signal that
* this is the color space that they represent. Therefore, they will
* typically not actually be interpreted as representing an HDR color space.
* This is especially detrimental to PQ which will then be interpreted as if
@ -741,8 +756,8 @@ typedef enum {
* or the color profile of the decoded pixels.
* @param color_encoding struct to copy the information into, or NULL to only
* check whether the information is available through the return value.
* @return @ref JXL_DEC_SUCCESS if the data is available and returned, @ref
* JXL_DEC_NEED_MORE_INPUT if not yet available, @ref JXL_DEC_ERROR in
* @return ::JXL_DEC_SUCCESS if the data is available and returned, @ref
* JXL_DEC_NEED_MORE_INPUT if not yet available, ::JXL_DEC_ERROR in
* case the encoded structured color profile does not exist in the
* codestream.
*/
@ -766,10 +781,10 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderGetColorAsEncodedProfile(
* or the color profile of the decoded pixels.
* @param size variable to output the size into, or NULL to only check the
* return status.
* @return @ref JXL_DEC_SUCCESS if the ICC profile is available, @ref
* @return ::JXL_DEC_SUCCESS if the ICC profile is available, @ref
* JXL_DEC_NEED_MORE_INPUT if the decoder has not yet received enough
* input data to determine whether an ICC profile is available or what its
* size is, @ref JXL_DEC_ERROR in case the ICC profile is not available and
* size is, ::JXL_DEC_ERROR in case the ICC profile is not available and
* cannot be generated.
*/
JXL_EXPORT JxlDecoderStatus JxlDecoderGetICCProfileSize(
@ -785,8 +800,8 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderGetICCProfileSize(
* or the color profile of the decoded pixels.
* @param icc_profile buffer to copy the ICC profile into
* @param size size of the icc_profile buffer in bytes
* @return @ref JXL_DEC_SUCCESS if the profile was successfully returned is
* available, @ref JXL_DEC_NEED_MORE_INPUT if not yet available, @ref
* @return ::JXL_DEC_SUCCESS if the profile was successfully returned is
* available, ::JXL_DEC_NEED_MORE_INPUT if not yet available, @ref
* JXL_DEC_ERROR if the profile doesn't exist or the output size is not
* large enough.
*/
@ -801,7 +816,7 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderGetColorAsICCProfile(
*
* @param dec decoder object
* @param color_encoding the default color encoding to set
* @return @ref JXL_DEC_SUCCESS if the preference was set successfully, @ref
* @return ::JXL_DEC_SUCCESS if the preference was set successfully, @ref
* JXL_DEC_ERROR otherwise.
*/
JXL_EXPORT JxlDecoderStatus JxlDecoderSetPreferredColorProfile(
@ -814,7 +829,7 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderSetPreferredColorProfile(
* change from version to version.
* @param dec decoder object
* @param desired_intensity_target the intended target peak luminance
* @return @ref JXL_DEC_SUCCESS if the preference was set successfully, @ref
* @return ::JXL_DEC_SUCCESS if the preference was set successfully, @ref
* JXL_DEC_ERROR otherwise.
*/
JXL_EXPORT JxlDecoderStatus JxlDecoderSetDesiredIntensityTarget(
@ -823,7 +838,7 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderSetDesiredIntensityTarget(
/**
* Sets the desired output color profile of the decoded image either from a
* color encoding or an ICC profile. Valid calls of this function have either @c
* color_encoding or @c icc_data set to NULL and @c icc_size must be 0 if and
* color_encoding or @c icc_data set to NULL and @c icc_size must be `0` if and
* only if @c icc_data is NULL.
*
* Depending on whether a color management system (CMS) has been set the
@ -848,17 +863,17 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderSetDesiredIntensityTarget(
* If called with an ICC profile (after a call to @ref JxlDecoderSetCms), the
* ICC profile has to be a valid RGB or grayscale color profile.
*
* Can only be set after the @ref JXL_DEC_COLOR_ENCODING event occurred and
* Can only be set after the ::JXL_DEC_COLOR_ENCODING event occurred and
* before any other event occurred, and should be used before getting
* JXL_COLOR_PROFILE_TARGET_DATA.
* ::JXL_COLOR_PROFILE_TARGET_DATA.
*
* This function must not be called before JxlDecoderSetCms.
* This function must not be called before @ref JxlDecoderSetCms.
*
* @param dec decoder orbject
* @param color_encoding the output color encoding
* @param icc_data bytes of the icc profile
* @param icc_size size of the icc profile in bytes
* @return @ref JXL_DEC_SUCCESS if the color profile was set successfully, @ref
* @return ::JXL_DEC_SUCCESS if the color profile was set successfully, @ref
* JXL_DEC_ERROR otherwise.
*/
JXL_EXPORT JxlDecoderStatus JxlDecoderSetOutputColorProfile(
@ -891,7 +906,7 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderSetCms(JxlDecoder* dec,
* @param dec decoder object
* @param format format of pixels
* @param size output value, buffer size in bytes
* @return @ref JXL_DEC_SUCCESS on success, @ref JXL_DEC_ERROR on error, such as
* @return ::JXL_DEC_SUCCESS on success, ::JXL_DEC_ERROR on error, such as
* information not available yet.
*/
JXL_EXPORT JxlDecoderStatus JxlDecoderPreviewOutBufferSize(
@ -901,15 +916,15 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderPreviewOutBufferSize(
* Sets the buffer to write the small resolution preview image
* to. The size of the buffer must be at least as large as given by @ref
* JxlDecoderPreviewOutBufferSize. The buffer follows the format described
* by JxlPixelFormat. The preview image dimensions are given by the
* JxlPreviewHeader. The buffer is owned by the caller.
* by @ref JxlPixelFormat. The preview image dimensions are given by the
* @ref JxlPreviewHeader. The buffer is owned by the caller.
*
* @param dec decoder object
* @param format format of pixels. Object owned by user and its contents are
* copied internally.
* @param buffer buffer type to output the pixel data to
* @param size size of buffer in bytes
* @return @ref JXL_DEC_SUCCESS on success, @ref JXL_DEC_ERROR on error, such as
* @return ::JXL_DEC_SUCCESS on success, ::JXL_DEC_ERROR on error, such as
* size too small.
*/
JXL_EXPORT JxlDecoderStatus JxlDecoderSetPreviewOutBuffer(
@ -917,14 +932,14 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderSetPreviewOutBuffer(
/**
* Outputs the information from the frame, such as duration when have_animation.
* This function can be called when @ref JXL_DEC_FRAME occurred for the current
* This function can be called when ::JXL_DEC_FRAME occurred for the current
* frame, even when have_animation in the JxlBasicInfo is JXL_FALSE.
*
* @param dec decoder object
* @param header struct to copy the information into, or NULL to only check
* whether the information is available through the return value.
* @return @ref JXL_DEC_SUCCESS if the value is available, @ref
* JXL_DEC_NEED_MORE_INPUT if not yet available, @ref JXL_DEC_ERROR in
* @return ::JXL_DEC_SUCCESS if the value is available, @ref
* JXL_DEC_NEED_MORE_INPUT if not yet available, ::JXL_DEC_ERROR in
* case of other error conditions.
*/
JXL_EXPORT JxlDecoderStatus JxlDecoderGetFrameHeader(const JxlDecoder* dec,
@ -932,14 +947,14 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderGetFrameHeader(const JxlDecoder* dec,
/**
* Outputs name for the current frame. The buffer for name must have at least
* name_length + 1 bytes allocated, gotten from the associated JxlFrameHeader.
* `name_length + 1` bytes allocated, gotten from the associated JxlFrameHeader.
*
* @param dec decoder object
* @param name buffer to copy the name into
* @param size size of the name buffer in bytes, including zero termination
* character, so this must be at least JxlFrameHeader.name_length + 1.
* @return @ref JXL_DEC_SUCCESS if the value is available, @ref
* JXL_DEC_NEED_MORE_INPUT if not yet available, @ref JXL_DEC_ERROR in
* character, so this must be at least @ref JxlFrameHeader.name_length + 1.
* @return ::JXL_DEC_SUCCESS if the value is available, @ref
* JXL_DEC_NEED_MORE_INPUT if not yet available, ::JXL_DEC_ERROR in
* case of other error conditions.
*/
JXL_EXPORT JxlDecoderStatus JxlDecoderGetFrameName(const JxlDecoder* dec,
@ -947,15 +962,15 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderGetFrameName(const JxlDecoder* dec,
/**
* Outputs the blend information for the current frame for a specific extra
* channel. This function can be called when @ref JXL_DEC_FRAME occurred for the
* current frame, even when have_animation in the JxlBasicInfo is JXL_FALSE.
* This information is only useful if coalescing is disabled; otherwise the
* decoder will have performed blending already.
* channel. This function can be called when ::JXL_DEC_FRAME occurred for the
* current frame, even when have_animation in the @ref JxlBasicInfo is @ref
* JXL_FALSE. This information is only useful if coalescing is disabled;
* otherwise the decoder will have performed blending already.
*
* @param dec decoder object
* @param index the index of the extra channel
* @param blend_info struct to copy the information into
* @return @ref JXL_DEC_SUCCESS on success, @ref JXL_DEC_ERROR on error
* @return ::JXL_DEC_SUCCESS on success, ::JXL_DEC_ERROR on error
*/
JXL_EXPORT JxlDecoderStatus JxlDecoderGetExtraChannelBlendInfo(
const JxlDecoder* dec, size_t index, JxlBlendInfo* blend_info);
@ -965,14 +980,14 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderGetExtraChannelBlendInfo(
* given format. This is the buffer for @ref JxlDecoderSetImageOutBuffer.
* Requires that the basic image information is available in the decoder in the
* case of coalescing enabled (default). In case coalescing is disabled, this
* can only be called after the @ref JXL_DEC_FRAME event occurs. In that case,
* can only be called after the ::JXL_DEC_FRAME event occurs. In that case,
* it will return the size required to store the possibly cropped frame (which
* can be larger or smaller than the image dimensions).
*
* @param dec decoder object
* @param format format of the pixels.
* @param size output value, buffer size in bytes
* @return @ref JXL_DEC_SUCCESS on success, @ref JXL_DEC_ERROR on error, such as
* @return ::JXL_DEC_SUCCESS on success, ::JXL_DEC_ERROR on error, such as
* information not available yet.
*/
JXL_EXPORT JxlDecoderStatus JxlDecoderImageOutBufferSize(
@ -980,18 +995,18 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderImageOutBufferSize(
/**
* Sets the buffer to write the full resolution image to. This can be set when
* the @ref JXL_DEC_FRAME event occurs, must be set when the @ref
* the ::JXL_DEC_FRAME event occurs, must be set when the @ref
* JXL_DEC_NEED_IMAGE_OUT_BUFFER event occurs, and applies only for the
* current frame. The size of the buffer must be at least as large as given
* by @ref JxlDecoderImageOutBufferSize. The buffer follows the format described
* by JxlPixelFormat. The buffer is owned by the caller.
* by @ref JxlPixelFormat. The buffer is owned by the caller.
*
* @param dec decoder object
* @param format format of the pixels. Object owned by user and its contents
* are copied internally.
* @param buffer buffer type to output the pixel data to
* @param size size of buffer in bytes
* @return @ref JXL_DEC_SUCCESS on success, @ref JXL_DEC_ERROR on error, such as
* @return ::JXL_DEC_SUCCESS on success, ::JXL_DEC_ERROR on error, such as
* size too small.
*/
JXL_EXPORT JxlDecoderStatus JxlDecoderSetImageOutBuffer(
@ -1062,15 +1077,15 @@ typedef void (*JxlImageOutDestroyCallback)(void* run_opaque);
/**
* Sets pixel output callback. This is an alternative to @ref
* JxlDecoderSetImageOutBuffer. This can be set when the @ref JXL_DEC_FRAME
* event occurs, must be set when the @ref JXL_DEC_NEED_IMAGE_OUT_BUFFER event
* JxlDecoderSetImageOutBuffer. This can be set when the ::JXL_DEC_FRAME
* event occurs, must be set when the ::JXL_DEC_NEED_IMAGE_OUT_BUFFER event
* occurs, and applies only for the current frame. Only one of @ref
* JxlDecoderSetImageOutBuffer or @ref JxlDecoderSetImageOutCallback may be used
* for the same frame, not both at the same time.
*
* The callback will be called multiple times, to receive the image
* data in small chunks. The callback receives a horizontal stripe of pixel
* data, 1 pixel high, xsize pixels wide, called a scanline. The xsize here is
* data, `1` pixel high, xsize pixels wide, called a scanline. The xsize here is
* not the same as the full image width, the scanline may be a partial section,
* and xsize may differ between calls. The user can then process and/or copy the
* partial scanline to an image buffer. The callback may be called
@ -1099,7 +1114,7 @@ typedef void (*JxlImageOutDestroyCallback)(void* run_opaque);
* data.
* @param opaque optional user data, which will be passed on to the callback,
* may be NULL.
* @return @ref JXL_DEC_SUCCESS on success, @ref JXL_DEC_ERROR on error, such
* @return ::JXL_DEC_SUCCESS on success, ::JXL_DEC_ERROR on error, such
* as @ref JxlDecoderSetImageOutBuffer already set.
*/
JXL_EXPORT JxlDecoderStatus
@ -1122,7 +1137,7 @@ JxlDecoderSetImageOutCallback(JxlDecoder* dec, const JxlPixelFormat* format,
* @param init_opaque optional user data passed to @c init_callback, may be NULL
* (unlike the return value from @c init_callback which may only be NULL if
* initialization failed).
* @return @ref JXL_DEC_SUCCESS on success, @ref JXL_DEC_ERROR on error, such
* @return ::JXL_DEC_SUCCESS on success, ::JXL_DEC_ERROR on error, such
* as @ref JxlDecoderSetImageOutBuffer having already been called.
*/
JXL_EXPORT JxlDecoderStatus JxlDecoderSetMultithreadedImageOutCallback(
@ -1137,12 +1152,12 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderSetMultithreadedImageOutCallback(
*
* @param dec decoder object
* @param format format of the pixels. The num_channels value is ignored and is
* always treated to be 1.
* always treated to be `1`.
* @param size output value, buffer size in bytes
* @param index which extra channel to get, matching the index used in @ref
* JxlDecoderGetExtraChannelInfo. Must be smaller than num_extra_channels in
* the associated JxlBasicInfo.
* @return @ref JXL_DEC_SUCCESS on success, @ref JXL_DEC_ERROR on error, such as
* the associated @ref JxlBasicInfo.
* @return ::JXL_DEC_SUCCESS on success, ::JXL_DEC_ERROR on error, such as
* information not available yet or invalid index.
*/
JXL_EXPORT JxlDecoderStatus JxlDecoderExtraChannelBufferSize(
@ -1151,13 +1166,13 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderExtraChannelBufferSize(
/**
* Sets the buffer to write an extra channel to. This can be set when
* the @ref JXL_DEC_FRAME or @ref JXL_DEC_NEED_IMAGE_OUT_BUFFER event occurs,
* the ::JXL_DEC_FRAME or ::JXL_DEC_NEED_IMAGE_OUT_BUFFER event occurs,
* and applies only for the current frame. The size of the buffer must be at
* least as large as given by @ref JxlDecoderExtraChannelBufferSize. The buffer
* follows the format described by JxlPixelFormat, but where num_channels is 1.
* The buffer is owned by the caller. The amount of extra channels is given by
* the num_extra_channels field in the associated JxlBasicInfo, and the
* information of individual extra channels can be queried with @ref
* follows the format described by @ref JxlPixelFormat, but where num_channels
* is `1`. The buffer is owned by the caller. The amount of extra channels is
* given by the num_extra_channels field in the associated @ref JxlBasicInfo,
* and the information of individual extra channels can be queried with @ref
* JxlDecoderGetExtraChannelInfo. To get multiple extra channels, this function
* must be called multiple times, once for each wanted index. Not all images
* have extra channels. The alpha channel is an extra channel and can be gotten
@ -1170,13 +1185,13 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderExtraChannelBufferSize(
* @param dec decoder object
* @param format format of the pixels. Object owned by user and its contents
* are copied internally. The num_channels value is ignored and is always
* treated to be 1.
* treated to be `1`.
* @param buffer buffer type to output the pixel data to
* @param size size of buffer in bytes
* @param index which extra channel to get, matching the index used in @ref
* JxlDecoderGetExtraChannelInfo. Must be smaller than num_extra_channels in
* the associated JxlBasicInfo.
* @return @ref JXL_DEC_SUCCESS on success, @ref JXL_DEC_ERROR on error, such as
* the associated @ref JxlBasicInfo.
* @return ::JXL_DEC_SUCCESS on success, ::JXL_DEC_ERROR on error, such as
* size too small or invalid index.
*/
JXL_EXPORT JxlDecoderStatus
@ -1197,8 +1212,8 @@ JxlDecoderSetExtraChannelBuffer(JxlDecoder* dec, const JxlPixelFormat* format,
* @param dec decoder object
* @param data pointer to next bytes to write to
* @param size amount of bytes available starting from data
* @return @ref JXL_DEC_ERROR if output buffer was already set and @ref
* JxlDecoderReleaseJPEGBuffer was not called on it, @ref JXL_DEC_SUCCESS
* @return ::JXL_DEC_ERROR if output buffer was already set and @ref
* JxlDecoderReleaseJPEGBuffer was not called on it, ::JXL_DEC_SUCCESS
* otherwise
*/
JXL_EXPORT JxlDecoderStatus JxlDecoderSetJPEGBuffer(JxlDecoder* dec,
@ -1213,11 +1228,11 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderSetJPEGBuffer(JxlDecoder* dec,
* JxlDecoderDestroy or @ref JxlDecoderReset.
*
* Calling @ref JxlDecoderReleaseJPEGBuffer when no buffer is set is
* not an error and returns 0.
* not an error and returns `0`.
*
* @param dec decoder object
* @return the amount of bytes the decoder has not yet written to of the data
* set by @ref JxlDecoderSetJPEGBuffer, or 0 if no buffer is set or @ref
* set by @ref JxlDecoderSetJPEGBuffer, or `0` if no buffer is set or @ref
* JxlDecoderReleaseJPEGBuffer was already called.
*/
JXL_EXPORT size_t JxlDecoderReleaseJPEGBuffer(JxlDecoder* dec);
@ -1233,15 +1248,15 @@ JXL_EXPORT size_t JxlDecoderReleaseJPEGBuffer(JxlDecoder* dec);
* JxlDecoderReleaseBoxBuffer, bytes that the decoder has already output
* should not be included, only the remaining bytes output must be set.
*
* The @ref JxlDecoderReleaseBoxBuffer must be used at the next @ref JXL_DEC_BOX
* event or final @ref JXL_DEC_SUCCESS event to compute the size of the output
* The @ref JxlDecoderReleaseBoxBuffer must be used at the next ::JXL_DEC_BOX
* event or final ::JXL_DEC_SUCCESS event to compute the size of the output
* box bytes.
*
* @param dec decoder object
* @param data pointer to next bytes to write to
* @param size amount of bytes available starting from data
* @return @ref JXL_DEC_ERROR if output buffer was already set and @ref
* JxlDecoderReleaseBoxBuffer was not called on it, @ref JXL_DEC_SUCCESS
* @return ::JXL_DEC_ERROR if output buffer was already set and @ref
* JxlDecoderReleaseBoxBuffer was not called on it, ::JXL_DEC_SUCCESS
* otherwise
*/
JXL_EXPORT JxlDecoderStatus JxlDecoderSetBoxBuffer(JxlDecoder* dec,
@ -1256,11 +1271,11 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderSetBoxBuffer(JxlDecoder* dec,
* JxlDecoderDestroy or @ref JxlDecoderReset.
*
* Calling @ref JxlDecoderReleaseBoxBuffer when no buffer is set is
* not an error and returns 0.
* not an error and returns `0`.
*
* @param dec decoder object
* @return the amount of bytes the decoder has not yet written to of the data
* set by @ref JxlDecoderSetBoxBuffer, or 0 if no buffer is set or @ref
* set by @ref JxlDecoderSetBoxBuffer, or `0` if no buffer is set or @ref
* JxlDecoderReleaseBoxBuffer was already called.
*/
JXL_EXPORT size_t JxlDecoderReleaseBoxBuffer(JxlDecoder* dec);
@ -1274,23 +1289,23 @@ JXL_EXPORT size_t JxlDecoderReleaseBoxBuffer(JxlDecoder* dec);
* finished.
*
* The default mode is raw. This setting can only be changed before decoding, or
* directly after a @ref JXL_DEC_BOX event, and is remembered until the decoder
* directly after a ::JXL_DEC_BOX event, and is remembered until the decoder
* is reset or destroyed.
*
* Enabling decompressed mode requires Brotli support from the library.
*
* @param dec decoder object
* @param decompress JXL_TRUE to transparently decompress, JXL_FALSE to get
* boxes in raw mode.
* @return @ref JXL_DEC_ERROR if decompressed mode is set and Brotli is not
* available, @ref JXL_DEC_SUCCESS otherwise.
* @param decompress ::JXL_TRUE to transparently decompress, ::JXL_FALSE
* to get boxes in raw mode.
* @return ::JXL_DEC_ERROR if decompressed mode is set and Brotli is not
* available, ::JXL_DEC_SUCCESS otherwise.
*/
JXL_EXPORT JxlDecoderStatus JxlDecoderSetDecompressBoxes(JxlDecoder* dec,
JXL_BOOL decompress);
/**
* Outputs the type of the current box, after a @ref JXL_DEC_BOX event occurred,
* as 4 characters without null termination character. In case of a compressed
* Outputs the type of the current box, after a ::JXL_DEC_BOX event occurred,
* as `4` characters without null termination character. In case of a compressed
* "brob" box, this will return "brob" if the decompressed argument is
* JXL_FALSE, or the underlying box type if the decompressed argument is
* JXL_TRUE.
@ -1306,15 +1321,15 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderSetDecompressBoxes(JxlDecoder* dec,
* - "xml ": a box with XML data, in particular XMP metadata.
* - "jumb": a JUMBF superbox (JPEG Universal Metadata Box Format, ISO/IEC
* 19566-5).
* - "JXL ": mandatory signature box, must come first, 12 bytes long including
* the box header
* - "ftyp": a second mandatory signature box, must come second, 20 bytes long
* including the box header
* - "jxll": a JXL level box. This indicates if the codestream is level 5 or
* level 10 compatible. If not present, it is level 5. Level 10 allows more
* features such as very high image resolution and bit-depths above 16 bits
* per channel. Added automatically by the encoder when
* JxlEncoderSetCodestreamLevel is used
* - "JXL ": mandatory signature box, must come first, `12` bytes long
* including the box header
* - "ftyp": a second mandatory signature box, must come second, `20` bytes
* long including the box header
* - "jxll": a JXL level box. This indicates if the codestream is level `5` or
* level `10` compatible. If not present, it is level `5`. Level `10` allows
* more features such as very high image resolution and bit-depths above `16`
* bits per channel. Added automatically by the encoder when
* @ref JxlEncoderSetCodestreamLevel is used
* - "jxlc": a box with the image codestream, in case the codestream is not
* split across multiple boxes. The codestream contains the JPEG XL image
* itself, including the basic info such as image dimensions, ICC color
@ -1350,7 +1365,7 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderSetDecompressBoxes(JxlDecoder* dec,
* @param type buffer to copy the type into
* @param decompressed which box type to get: JXL_FALSE to get the raw box type,
* which can be "brob", JXL_TRUE, get the underlying box type.
* @return @ref JXL_DEC_SUCCESS if the value is available, @ref JXL_DEC_ERROR if
* @return ::JXL_DEC_SUCCESS if the value is available, ::JXL_DEC_ERROR if
* not, for example the JXL file does not use the container format.
*/
JXL_EXPORT JxlDecoderStatus JxlDecoderGetBoxType(JxlDecoder* dec,
@ -1363,12 +1378,28 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderGetBoxType(JxlDecoder* dec,
*
* @param dec decoder object
* @param size raw size of the box in bytes
* @return @ref JXL_DEC_ERROR if no box size is available, @ref JXL_DEC_SUCCESS
* @return ::JXL_DEC_ERROR if no box size is available, ::JXL_DEC_SUCCESS
* otherwise.
*/
JXL_EXPORT JxlDecoderStatus JxlDecoderGetBoxSizeRaw(const JxlDecoder* dec,
uint64_t* size);
/**
* Returns the size of the contents of a box, after the @ref
* JXL_DEC_BOX event. This does not include any of the headers of the box. For
* compressed "brob" boxes, this is the size of the compressed content. Even
* when @ref JxlDecoderSetDecompressBoxes is enabled, the return value of
* function does not change, and the decompressed size is not known before it
* has already been decompressed and output.
*
* @param dec decoder object
* @param size size of the payload of the box in bytes
* @return @ref JXL_DEC_ERROR if no box size is available, @ref JXL_DEC_SUCCESS
* otherwise.
*/
JXL_EXPORT JxlDecoderStatus JxlDecoderGetBoxSizeContents(const JxlDecoder* dec,
uint64_t* size);
/**
* Configures at which progressive steps in frame decoding these @ref
* JXL_DEC_FRAME_PROGRESSION event occurs. The default value for the level
@ -1377,7 +1408,7 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderGetBoxSizeRaw(const JxlDecoder* dec,
* @param dec decoder object
* @param detail at which level of detail to trigger @ref
* JXL_DEC_FRAME_PROGRESSION
* @return @ref JXL_DEC_SUCCESS on success, @ref JXL_DEC_ERROR on error, such as
* @return ::JXL_DEC_SUCCESS on success, ::JXL_DEC_ERROR on error, such as
* an invalid value for the progressive detail.
*/
JXL_EXPORT JxlDecoderStatus
@ -1385,11 +1416,11 @@ JxlDecoderSetProgressiveDetail(JxlDecoder* dec, JxlProgressiveDetail detail);
/**
* Returns the intended downsampling ratio for the progressive frame produced
* by @ref JxlDecoderFlushImage after the latest @ref JXL_DEC_FRAME_PROGRESSION
* by @ref JxlDecoderFlushImage after the latest ::JXL_DEC_FRAME_PROGRESSION
* event.
*
* @param dec decoder object
* @return The intended downsampling ratio, can be 1, 2, 4 or 8.
* @return The intended downsampling ratio, can be `1`, `2`, `4` or `8`.
*/
JXL_EXPORT size_t JxlDecoderGetIntendedDownsamplingRatio(JxlDecoder* dec);
@ -1399,12 +1430,12 @@ JXL_EXPORT size_t JxlDecoderGetIntendedDownsamplingRatio(JxlDecoder* dec);
* JxlDecoderSetImageOutBuffer will contain partial image data.
*
* Can be called when @ref JxlDecoderProcessInput returns @ref
* JXL_DEC_NEED_MORE_INPUT, after the @ref JXL_DEC_FRAME event already occurred
* and before the @ref JXL_DEC_FULL_IMAGE event occurred for a frame.
* JXL_DEC_NEED_MORE_INPUT, after the ::JXL_DEC_FRAME event already occurred
* and before the ::JXL_DEC_FULL_IMAGE event occurred for a frame.
*
* @param dec decoder object
* @return @ref JXL_DEC_SUCCESS if image data was flushed to the output buffer,
* or @ref JXL_DEC_ERROR when no flush was done, e.g. if not enough image
* @return ::JXL_DEC_SUCCESS if image data was flushed to the output buffer,
* or ::JXL_DEC_ERROR when no flush was done, e.g. if not enough image
* data was available yet even for flush, or no output buffer was set yet.
* This error is not fatal, it only indicates no flushed image is available
* right now. Regular decoding can still be performed.
@ -1416,11 +1447,11 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderFlushImage(JxlDecoder* dec);
*
* Can be called after @ref JxlDecoderSetImageOutBuffer or @ref
* JxlDecoderSetImageOutCallback. For float pixel data types, only the default
* @ref JXL_BIT_DEPTH_FROM_PIXEL_FORMAT setting is supported.
* ::JXL_BIT_DEPTH_FROM_PIXEL_FORMAT setting is supported.
*
* @param dec decoder object
* @param bit_depth the bit depth setting of the pixel output
* @return @ref JXL_DEC_SUCCESS on success, @ref JXL_DEC_ERROR on error, such as
* @return ::JXL_DEC_SUCCESS on success, ::JXL_DEC_ERROR on error, such as
* incompatible custom bit depth and pixel data type.
*/
JXL_EXPORT JxlDecoderStatus

397
third_party/jpeg-xl/lib/include/jxl/encode.h поставляемый
Просмотреть файл

@ -41,8 +41,8 @@ JXL_EXPORT uint32_t JxlEncoderVersion(void);
/**
* Opaque structure that holds the JPEG XL encoder.
*
* Allocated and initialized with JxlEncoderCreate().
* Cleaned up and deallocated with JxlEncoderDestroy().
* Allocated and initialized with @ref JxlEncoderCreate().
* Cleaned up and deallocated with @ref JxlEncoderDestroy().
*/
typedef struct JxlEncoderStruct JxlEncoder;
@ -50,9 +50,9 @@ typedef struct JxlEncoderStruct JxlEncoder;
* Settings and metadata for a single image frame. This includes encoder options
* for a frame such as compression quality and speed.
*
* Allocated and initialized with JxlEncoderFrameSettingsCreate().
* Allocated and initialized with @ref JxlEncoderFrameSettingsCreate().
* Cleaned up and deallocated when the encoder is destroyed with
* JxlEncoderDestroy().
* @ref JxlEncoderDestroy().
*/
typedef struct JxlEncoderFrameSettingsStruct JxlEncoderFrameSettings;
@ -145,7 +145,7 @@ typedef enum {
*/
JXL_ENC_FRAME_SETTING_RESAMPLING = 2,
/** Similar to JXL_ENC_FRAME_SETTING_RESAMPLING, but for extra channels.
/** Similar to ::JXL_ENC_FRAME_SETTING_RESAMPLING, but for extra channels.
* Integer option, use -1 for the default behavior (depends on encoder
* implementation), 1 for no downsampling (1x1), 2 for 2x2 downsampling, 4 for
* 4x4 downsampling, 8 for 8x8 downsampling.
@ -158,7 +158,7 @@ typedef enum {
* downsampled resolution, not the full image resolution. The downsampled
* resolution is given by ceil(xsize / resampling), ceil(ysize / resampling)
* with xsize and ysize the dimensions given in the basic info, and resampling
* the factor set with @ref JXL_ENC_FRAME_SETTING_RESAMPLING.
* the factor set with ::JXL_ENC_FRAME_SETTING_RESAMPLING.
* Use 0 to disable, 1 to enable. Default value is 0.
*/
JXL_ENC_FRAME_SETTING_ALREADY_DOWNSAMPLED = 4,
@ -171,8 +171,8 @@ typedef enum {
JXL_ENC_FRAME_SETTING_PHOTON_NOISE = 5,
/** Enables adaptive noise generation. This setting is not recommended for
* use, please use JXL_ENC_FRAME_SETTING_PHOTON_NOISE instead. Use -1 for the
* default (encoder chooses), 0 to disable, 1 to enable.
* use, please use ::JXL_ENC_FRAME_SETTING_PHOTON_NOISE instead. Use -1 for
* the default (encoder chooses), 0 to disable, 1 to enable.
*/
JXL_ENC_FRAME_SETTING_NOISE = 6,
@ -320,27 +320,28 @@ typedef enum {
* 1 = index this frame within the Frame Index Box.
* If any frames are indexed, the first frame needs to
* be indexed, too. If the first frame is not indexed, and
* a later frame is attempted to be indexed, JXL_ENC_ERROR will occur.
* a later frame is attempted to be indexed, ::JXL_ENC_ERROR will occur.
* If non-keyframes, i.e., frames with cropping, blending or patches are
* attempted to be indexed, JXL_ENC_ERROR will occur.
* attempted to be indexed, ::JXL_ENC_ERROR will occur.
*/
JXL_ENC_FRAME_INDEX_BOX = 31,
/** Sets brotli encode effort for use in JPEG recompression and compressed
* metadata boxes (brob). Can be -1 (default) or 0 (fastest) to 11 (slowest).
* Default is based on the general encode effort in case of JPEG
/** Sets brotli encode effort for use in JPEG recompression and
* compressed metadata boxes (brob). Can be -1 (default) or 0 (fastest) to 11
* (slowest). Default is based on the general encode effort in case of JPEG
* recompression, and 4 for brob boxes.
*/
JXL_ENC_FRAME_SETTING_BROTLI_EFFORT = 32,
/** Enables or disables brotli compression of metadata boxes derived from
* a JPEG frame when using JxlEncoderAddJPEGFrame. This has no effect on boxes
* added using JxlEncoderAddBox.
* -1 = default, 0 = disable compression, 1 = enable compression.
* a JPEG frame when using @ref JxlEncoderAddJPEGFrame. This has no effect on
* boxes added using @ref JxlEncoderAddBox. -1 = default, 0 = disable
* compression, 1 = enable compression.
*/
JXL_ENC_FRAME_SETTING_JPEG_COMPRESS_BOXES = 33,
/** Control what kind of buffering is used, when using chunked image frames.
* -1 = default (let the encoder decide)
* 0 = buffers everything, basically the same as non-streamed code path
(mainly for testing)
* 1 = buffers everything for images that are smaller than 2048 x 2048, and
@ -351,30 +352,30 @@ typedef enum {
*
* When using streaming input and output the encoder minimizes memory usage at
* the cost of compression density. Also note that images produced with
* streaming mode might can not be decoded progressively.
* streaming mode might not be progressively decodeable.
*/
JXL_ENC_FRAME_SETTING_BUFFERING = 34,
/** Keep or discard Exif metadata boxes derived from a JPEG frame when using
* JxlEncoderAddJPEGFrame. This has no effect on boxes added using
* JxlEncoderAddBox. When JxlEncoderStoreJPEGMetadata is set to 1, this option
* cannot be set to 0. Even when Exif metadata is discarded, the orientation
* will still be applied. 0 = discard Exif metadata, 1 = keep Exif metadata
* (default).
* @ref JxlEncoderAddJPEGFrame. This has no effect on boxes added using
* @ref JxlEncoderAddBox. When @ref JxlEncoderStoreJPEGMetadata is set to 1,
* this option cannot be set to 0. Even when Exif metadata is discarded, the
* orientation will still be applied. 0 = discard Exif metadata, 1 = keep Exif
* metadata (default).
*/
JXL_ENC_FRAME_SETTING_JPEG_KEEP_EXIF = 35,
/** Keep or discard XMP metadata boxes derived from a JPEG frame when using
* JxlEncoderAddJPEGFrame. This has no effect on boxes added using
* JxlEncoderAddBox. When JxlEncoderStoreJPEGMetadata is set to 1, this option
* cannot be set to 0. 0 = discard XMP metadata, 1 = keep XMP metadata
* (default).
* @ref JxlEncoderAddJPEGFrame. This has no effect on boxes added using
* @ref JxlEncoderAddBox. When @ref JxlEncoderStoreJPEGMetadata is set to 1,
* this option cannot be set to 0. 0 = discard XMP metadata, 1 = keep XMP
* metadata (default).
*/
JXL_ENC_FRAME_SETTING_JPEG_KEEP_XMP = 36,
/** Keep or discard JUMBF metadata boxes derived from a JPEG frame when using
* JxlEncoderAddJPEGFrame. This has no effect on boxes added using
* JxlEncoderAddBox. 0 = discard JUMBF metadata, 1 = keep JUMBF metadata
* @ref JxlEncoderAddJPEGFrame. This has no effect on boxes added using
* @ref JxlEncoderAddBox. 0 = discard JUMBF metadata, 1 = keep JUMBF metadata
* (default).
*/
JXL_ENC_FRAME_SETTING_JPEG_KEEP_JUMBF = 37,
@ -395,7 +396,7 @@ typedef enum {
} JxlEncoderFrameSettingId;
/**
* Creates an instance of JxlEncoder and initializes it.
* Creates an instance of @ref JxlEncoder and initializes it.
*
* @p memory_manager will be used for all the library dynamic allocations made
* from this instance. The parameter may be NULL, in which case the default
@ -404,21 +405,21 @@ typedef enum {
* @param memory_manager custom allocator function. It may be NULL. The memory
* manager will be copied internally.
* @return @c NULL if the instance can not be allocated or initialized
* @return pointer to initialized JxlEncoder otherwise
* @return pointer to initialized @ref JxlEncoder otherwise
*/
JXL_EXPORT JxlEncoder* JxlEncoderCreate(const JxlMemoryManager* memory_manager);
/**
* Re-initializes a JxlEncoder instance, so it can be re-used for encoding
* Re-initializes a @ref JxlEncoder instance, so it can be re-used for encoding
* another image. All state and settings are reset as if the object was
* newly created with JxlEncoderCreate, but the memory manager is kept.
* newly created with @ref JxlEncoderCreate, but the memory manager is kept.
*
* @param enc instance to be re-initialized.
*/
JXL_EXPORT void JxlEncoderReset(JxlEncoder* enc);
/**
* Deinitializes and frees JxlEncoder instance.
* Deinitializes and frees a @ref JxlEncoder instance.
*
* @param enc instance to be cleaned up and deallocated.
*/
@ -430,8 +431,8 @@ JXL_EXPORT void JxlEncoderDestroy(JxlEncoder* enc);
* left unset, the default CMS implementation will be used.
*
* @param enc encoder object.
* @param cms structure representing a CMS implementation. See JxlCmsInterface
* for more details.
* @param cms structure representing a CMS implementation. See @ref
* JxlCmsInterface for more details.
*/
JXL_EXPORT void JxlEncoderSetCms(JxlEncoder* enc, JxlCmsInterface cms);
@ -444,7 +445,7 @@ JXL_EXPORT void JxlEncoderSetCms(JxlEncoder* enc, JxlCmsInterface cms);
* be NULL to use the default, single-threaded, runner. A multithreaded
* runner should be set to reach fast performance.
* @param parallel_runner_opaque opaque pointer for parallel_runner.
* @return JXL_ENC_SUCCESS if the runner was set, JXL_ENC_ERROR
* @return ::JXL_ENC_SUCCESS if the runner was set, ::JXL_ENC_ERROR
* otherwise (the previous runner remains set).
*/
JXL_EXPORT JxlEncoderStatus
@ -452,16 +453,16 @@ JxlEncoderSetParallelRunner(JxlEncoder* enc, JxlParallelRunner parallel_runner,
void* parallel_runner_opaque);
/**
* Get the (last) error code in case JXL_ENC_ERROR was returned.
* Get the (last) error code in case ::JXL_ENC_ERROR was returned.
*
* @param enc encoder object.
* @return the JxlEncoderError that caused the (last) JXL_ENC_ERROR to be
* returned.
* @return the @ref JxlEncoderError that caused the (last) ::JXL_ENC_ERROR to
* be returned.
*/
JXL_EXPORT JxlEncoderError JxlEncoderGetError(JxlEncoder* enc);
/**
* Encodes JPEG XL file using the available bytes. @p *avail_out indicates how
* Encodes a JPEG XL file using the available bytes. @p *avail_out indicates how
* many output bytes are available, and @p *next_out points to the input bytes.
* *avail_out will be decremented by the amount of bytes that have been
* processed by the encoder and *next_out will be incremented by the same
@ -469,12 +470,12 @@ JXL_EXPORT JxlEncoderError JxlEncoderGetError(JxlEncoder* enc);
* bytes.
*
* The returned status indicates whether the encoder needs more output bytes.
* When the return value is not JXL_ENC_ERROR or JXL_ENC_SUCCESS, the encoding
* requires more JxlEncoderProcessOutput calls to continue.
* When the return value is not ::JXL_ENC_ERROR or ::JXL_ENC_SUCCESS, the
* encoding requires more @ref JxlEncoderProcessOutput calls to continue.
*
* The caller must guarantee that *avail_out >= 32 when calling
* JxlEncoderProcessOutput; otherwise, JXL_ENC_NEED_MORE_OUTPUT will be
* returned. It is guaranteed that, if *avail_out >= 32, at least one byte of
* @ref JxlEncoderProcessOutput; otherwise, ::JXL_ENC_NEED_MORE_OUTPUT will
* be returned. It is guaranteed that, if *avail_out >= 32, at least one byte of
* output will be written.
*
* This encodes the frames and/or boxes added so far. If the last frame or last
@ -486,9 +487,9 @@ JXL_EXPORT JxlEncoderError JxlEncoderGetError(JxlEncoder* enc);
* @param enc encoder object.
* @param next_out pointer to next bytes to write to.
* @param avail_out amount of bytes available starting from *next_out.
* @return JXL_ENC_SUCCESS when encoding finished and all events handled.
* @return JXL_ENC_ERROR when encoding failed, e.g. invalid input.
* @return JXL_ENC_NEED_MORE_OUTPUT more output buffer is necessary.
* @return ::JXL_ENC_SUCCESS when encoding finished and all events handled.
* @return ::JXL_ENC_ERROR when encoding failed, e.g. invalid input.
* @return ::JXL_ENC_NEED_MORE_OUTPUT more output buffer is necessary.
*/
JXL_EXPORT JxlEncoderStatus JxlEncoderProcessOutput(JxlEncoder* enc,
uint8_t** next_out,
@ -509,13 +510,14 @@ JXL_EXPORT JxlEncoderStatus JxlEncoderProcessOutput(JxlEncoder* enc,
* time duration of 0, making them form a composite still. See @ref
* JxlFrameHeader for more information.
*
* This information is stored in the JxlEncoderFrameSettings and so is used for
* any frame encoded with these JxlEncoderFrameSettings. It is ok to change
* between @ref JxlEncoderAddImageFrame calls, each added image frame will have
* the frame header that was set in the options at the time of calling
* JxlEncoderAddImageFrame.
* This information is stored in the @ref JxlEncoderFrameSettings and so is used
* for any frame encoded with these @ref JxlEncoderFrameSettings. It is ok to
* change between @ref JxlEncoderAddImageFrame calls, each added image frame
* will have the frame header that was set in the options at the time of calling
* @ref JxlEncoderAddImageFrame.
*
* The is_last and name_length fields of the JxlFrameHeader are ignored, use
* The is_last and name_length fields of the @ref JxlFrameHeader are ignored,
* use
* @ref JxlEncoderCloseFrames to indicate last frame, and @ref
* JxlEncoderSetFrameName to indicate the name and its length instead.
* Calling this function will clear any name that was previously set with @ref
@ -525,7 +527,7 @@ JXL_EXPORT JxlEncoderStatus JxlEncoderProcessOutput(JxlEncoder* enc,
* includes reference to the encoder object.
* @param frame_header frame header data to set. Object owned by the caller and
* does not need to be kept in memory, its information is copied internally.
* @return JXL_ENC_SUCCESS on success, JXL_ENC_ERROR on error
* @return ::JXL_ENC_SUCCESS on success, ::JXL_ENC_ERROR on error
*/
JXL_EXPORT JxlEncoderStatus
JxlEncoderSetFrameHeader(JxlEncoderFrameSettings* frame_settings,
@ -540,7 +542,7 @@ JxlEncoderSetFrameHeader(JxlEncoderFrameSettings* frame_settings,
* includes reference to the encoder object.
* @param index index of the extra channel to use.
* @param blend_info blend info to set for the extra channel
* @return JXL_ENC_SUCCESS on success, JXL_ENC_ERROR on error
* @return ::JXL_ENC_SUCCESS on success, ::JXL_ENC_ERROR on error
*/
JXL_EXPORT JxlEncoderStatus JxlEncoderSetExtraChannelBlendInfo(
JxlEncoderFrameSettings* frame_settings, size_t index,
@ -550,8 +552,9 @@ JXL_EXPORT JxlEncoderStatus JxlEncoderSetExtraChannelBlendInfo(
* Sets the name of the animation frame. This function is optional, frames are
* not required to have a name. This setting is a part of the frame header, and
* the same principles as for @ref JxlEncoderSetFrameHeader apply. The
* name_length field of JxlFrameHeader is ignored by the encoder, this function
* determines the name length instead as the length in bytes of the C string.
* name_length field of @ref JxlFrameHeader is ignored by the encoder, this
* function determines the name length instead as the length in bytes of the C
* string.
*
* The maximum possible name length is 1071 bytes (excluding terminating null
* character).
@ -563,7 +566,7 @@ JXL_EXPORT JxlEncoderStatus JxlEncoderSetExtraChannelBlendInfo(
* includes reference to the encoder object.
* @param frame_name name of the next frame to be encoded, as a UTF-8 encoded C
* string (zero terminated). Owned by the caller, and copied internally.
* @return JXL_ENC_SUCCESS on success, JXL_ENC_ERROR on error
* @return ::JXL_ENC_SUCCESS on success, ::JXL_ENC_ERROR on error
*/
JXL_EXPORT JxlEncoderStatus JxlEncoderSetFrameName(
JxlEncoderFrameSettings* frame_settings, const char* frame_name);
@ -571,15 +574,17 @@ JXL_EXPORT JxlEncoderStatus JxlEncoderSetFrameName(
/**
* Sets the bit depth of the input buffer.
*
* For float pixel formats, only the default JXL_BIT_DEPTH_FROM_PIXEL_FORMAT
* For float pixel formats, only the default @ref
JXL_BIT_DEPTH_FROM_PIXEL_FORMAT
* setting is allowed, while for unsigned pixel formats,
* JXL_BIT_DEPTH_FROM_CODESTREAM setting is also allowed. See the comment on
* ::JXL_BIT_DEPTH_FROM_CODESTREAM setting is also allowed. See the comment
on
* @ref JxlEncoderAddImageFrame for the effects of the bit depth setting.
* @param frame_settings set of options and metadata for this frame. Also
* includes reference to the encoder object.
* @param bit_depth the bit depth setting of the pixel input
* @return JXL_ENC_SUCCESS on success, JXL_ENC_ERROR on error
* @return ::JXL_ENC_SUCCESS on success, ::JXL_ENC_ERROR on error
*/
JXL_EXPORT JxlEncoderStatus JxlEncoderSetFrameBitDepth(
JxlEncoderFrameSettings* frame_settings, const JxlBitDepth* bit_depth);
@ -587,13 +592,13 @@ JXL_EXPORT JxlEncoderStatus JxlEncoderSetFrameBitDepth(
/**
* Sets the buffer to read JPEG encoded bytes from for the next frame to encode.
*
* If JxlEncoderSetBasicInfo has not yet been called, calling
* JxlEncoderAddJPEGFrame will implicitly call it with the parameters of the
* added JPEG frame.
* If @ref JxlEncoderSetBasicInfo has not yet been called, calling
* @ref JxlEncoderAddJPEGFrame will implicitly call it with the parameters of
* the added JPEG frame.
*
* If JxlEncoderSetColorEncoding or JxlEncoderSetICCProfile has not yet been
* called, calling JxlEncoderAddJPEGFrame will implicitly call it with the
* parameters of the added JPEG frame.
* If @ref JxlEncoderSetColorEncoding or @ref JxlEncoderSetICCProfile has not
* yet been called, calling @ref JxlEncoderAddJPEGFrame will implicitly call it
* with the parameters of the added JPEG frame.
*
* If the encoder is set to store JPEG reconstruction metadata using @ref
* JxlEncoderStoreJPEGMetadata and a single JPEG frame is added, it will be
@ -603,12 +608,16 @@ JXL_EXPORT JxlEncoderStatus JxlEncoderSetFrameBitDepth(
* JxlEncoderCloseFrames must be called before the next
* @ref JxlEncoderProcessOutput call.
*
* Note, this can only be used to add JPEG frames for lossless compression. To
* encode with lossy compression, the JPEG must be decoded manually and a pixel
* buffer added using JxlEncoderAddImageFrame.
*
* @param frame_settings set of options and metadata for this frame. Also
* includes reference to the encoder object.
* @param buffer bytes to read JPEG from. Owned by the caller and its contents
* are copied internally.
* @param size size of buffer in bytes.
* @return JXL_ENC_SUCCESS on success, JXL_ENC_ERROR on error
* @return ::JXL_ENC_SUCCESS on success, ::JXL_ENC_ERROR on error
*/
JXL_EXPORT JxlEncoderStatus
JxlEncoderAddJPEGFrame(const JxlEncoderFrameSettings* frame_settings,
@ -616,33 +625,36 @@ JxlEncoderAddJPEGFrame(const JxlEncoderFrameSettings* frame_settings,
/**
* Sets the buffer to read pixels from for the next image to encode. Must call
* JxlEncoderSetBasicInfo before JxlEncoderAddImageFrame.
* @ref JxlEncoderSetBasicInfo before @ref JxlEncoderAddImageFrame.
*
* Currently only some data types for pixel formats are supported:
* - JXL_TYPE_UINT8, with range 0..255
* - JXL_TYPE_UINT16, with range 0..65535
* - JXL_TYPE_FLOAT16, with nominal range 0..1
* - JXL_TYPE_FLOAT, with nominal range 0..1
* - ::JXL_TYPE_UINT8, with range 0..255
* - ::JXL_TYPE_UINT16, with range 0..65535
* - ::JXL_TYPE_FLOAT16, with nominal range 0..1
* - ::JXL_TYPE_FLOAT, with nominal range 0..1
*
* Note: the sample data type in pixel_format is allowed to be different from
* what is described in the JxlBasicInfo. The type in pixel_format, together
* with an optional @ref JxlBitDepth parameter set by @ref
* what is described in the @ref JxlBasicInfo. The type in pixel_format,
* together with an optional @ref JxlBitDepth parameter set by @ref
* JxlEncoderSetFrameBitDepth describes the format of the uncompressed pixel
* buffer. The bits_per_sample and exponent_bits_per_sample in the JxlBasicInfo
* describes what will actually be encoded in the JPEG XL codestream.
* For example, to encode a 12-bit image, you would set bits_per_sample to 12,
* while the input frame buffer can be in the following formats:
* - if pixel format is in JXL_TYPE_UINT16 with default bit depth setting
* (i.e. JXL_BIT_DEPTH_FROM_PIXEL_FORMAT), input sample values are rescaled
* to 16-bit, i.e. multiplied by 65535/4095;
* - if pixel format is in JXL_TYPE_UINT16 with JXL_BIT_DEPTH_FROM_CODESTREAM
* bit depth setting, input sample values are provided unscaled;
* - if pixel format is in JXL_TYPE_FLOAT, input sample values are rescaled
* to 0..1, i.e. multiplied by 1.f/4095.f.
* While it is allowed, it is obviously not recommended to use a pixel_format
* with lower precision than what is specified in the JxlBasicInfo.
* buffer. The bits_per_sample and exponent_bits_per_sample in the @ref
* JxlBasicInfo describes what will actually be encoded in the JPEG XL
* codestream. For example, to encode a 12-bit image, you would set
* bits_per_sample to 12, while the input frame buffer can be in the following
* formats:
* - if pixel format is in ::JXL_TYPE_UINT16 with default bit depth setting
* (i.e. ::JXL_BIT_DEPTH_FROM_PIXEL_FORMAT), input sample values are
* rescaled to 16-bit, i.e. multiplied by 65535/4095;
* - if pixel format is in ::JXL_TYPE_UINT16 with @ref
* JXL_BIT_DEPTH_FROM_CODESTREAM bit depth setting, input sample values are
* provided unscaled;
* - if pixel format is in ::JXL_TYPE_FLOAT, input sample values are
* rescaled to 0..1, i.e. multiplied by 1.f/4095.f. While it is allowed, it is
* obviously not recommended to use a pixel_format with lower precision than
* what is specified in the @ref JxlBasicInfo.
*
* We support interleaved channels as described by the JxlPixelFormat:
* We support interleaved channels as described by the @ref JxlPixelFormat
* "JxlPixelFormat":
* - single-channel data, e.g. grayscale
* - single-channel + alpha
* - trichromatic, e.g. RGB
@ -654,10 +666,11 @@ JxlEncoderAddJPEGFrame(const JxlEncoderFrameSettings* frame_settings,
* set to all-opaque (an alpha value of 1.0 everywhere).
*
* The pixels are assumed to be encoded in the original profile that is set with
* JxlEncoderSetColorEncoding or JxlEncoderSetICCProfile. If none of these
* functions were used, the pixels are assumed to be nonlinear sRGB for integer
* data types (JXL_TYPE_UINT8, JXL_TYPE_UINT16), and linear sRGB for floating
* point data types (JXL_TYPE_FLOAT16, JXL_TYPE_FLOAT).
* @ref JxlEncoderSetColorEncoding or @ref JxlEncoderSetICCProfile. If none of
* these functions were used, the pixels are assumed to be nonlinear sRGB for
* integer data types (::JXL_TYPE_UINT8, ::JXL_TYPE_UINT16), and linear
* sRGB for floating point data types (::JXL_TYPE_FLOAT16, @ref
* JXL_TYPE_FLOAT).
*
* Sample values in floating-point pixel formats are allowed to be outside the
* nominal range, e.g. to represent out-of-sRGB-gamut colors in the
@ -676,14 +689,14 @@ JxlEncoderAddJPEGFrame(const JxlEncoderFrameSettings* frame_settings,
* and its contents are copied internally.
* @param size size of buffer in bytes. This size should match what is implied
* by the frame dimensions and the pixel format.
* @return JXL_ENC_SUCCESS on success, JXL_ENC_ERROR on error
* @return ::JXL_ENC_SUCCESS on success, ::JXL_ENC_ERROR on error
*/
JXL_EXPORT JxlEncoderStatus JxlEncoderAddImageFrame(
const JxlEncoderFrameSettings* frame_settings,
const JxlPixelFormat* pixel_format, const void* buffer, size_t size);
/**
* The JxlEncoderOutputProcessor structure provides an interface for the
* The @ref JxlEncoderOutputProcessor structure provides an interface for the
* encoder's output processing. Users of the library, who want to do streaming
* encoding, should implement the required callbacks for buffering, writing,
* seeking (if supported), and setting a finalized position during the encoding
@ -785,7 +798,7 @@ struct JxlEncoderOutputProcessor {
* @param enc encoder object.
* @param output_processor the struct containing the callbacks for managing
* output.
* @return JXL_ENC_SUCCESS on success, JXL_ENC_ERROR on error.
* @return ::JXL_ENC_SUCCESS on success, ::JXL_ENC_ERROR on error.
*/
JXL_EXPORT JxlEncoderStatus JxlEncoderSetOutputProcessor(
JxlEncoder* enc, struct JxlEncoderOutputProcessor output_processor);
@ -801,7 +814,7 @@ JXL_EXPORT JxlEncoderStatus JxlEncoderSetOutputProcessor(
* This should not be used when using @ref JxlEncoderProcessOutput.
*
* @param enc encoder object.
* @return JXL_ENC_SUCCESS on success, JXL_ENC_ERROR on error.
* @return ::JXL_ENC_SUCCESS on success, ::JXL_ENC_ERROR on error.
*/
JXL_EXPORT JxlEncoderStatus JxlEncoderFlushInput(JxlEncoder* enc);
@ -923,9 +936,9 @@ struct JxlChunkedFrameInputSource {
* chunked or streaming manner, which can be especially useful when dealing with
* large images that may not fit entirely in memory or when trying to optimize
* memory usage. The input data is provided through callbacks defined in the
* `JxlChunkedFrameInputSource` struct. Once the frame data has been completely
* retrieved, this function will flush the input and close it if it is the last
* frame.
* @ref JxlChunkedFrameInputSource struct. Once the frame data has been
* completely retrieved, this function will flush the input and close it if it
* is the last frame.
*
* @param frame_settings set of options and metadata for this frame. Also
* includes reference to the encoder object.
@ -943,7 +956,7 @@ JXL_EXPORT JxlEncoderStatus JxlEncoderAddChunkedFrame(
/**
* Sets the buffer to read pixels from for an extra channel at a given index.
* The index must be smaller than the num_extra_channels in the associated
* JxlBasicInfo. Must call @ref JxlEncoderSetExtraChannelInfo before
* @ref JxlBasicInfo. Must call @ref JxlEncoderSetExtraChannelInfo before @ref
* JxlEncoderSetExtraChannelBuffer.
*
* TODO(firsching): mention what data types in pixel formats are supported.
@ -961,15 +974,15 @@ JXL_EXPORT JxlEncoderStatus JxlEncoderAddChunkedFrame(
* @param size size of buffer in bytes. This size should match what is implied
* by the frame dimensions and the pixel format.
* @param index index of the extra channel to use.
* @return JXL_ENC_SUCCESS on success, JXL_ENC_ERROR on error
* @return ::JXL_ENC_SUCCESS on success, ::JXL_ENC_ERROR on error
*/
JXL_EXPORT JxlEncoderStatus JxlEncoderSetExtraChannelBuffer(
const JxlEncoderFrameSettings* frame_settings,
const JxlPixelFormat* pixel_format, const void* buffer, size_t size,
uint32_t index);
/** Adds a metadata box to the file format. JxlEncoderProcessOutput must be used
* to effectively write the box to the output. @ref JxlEncoderUseBoxes must
/** Adds a metadata box to the file format. @ref JxlEncoderProcessOutput must be
* used to effectively write the box to the output. @ref JxlEncoderUseBoxes must
* be enabled before using this function.
*
* Boxes allow inserting application-specific data and metadata (Exif, XML/XMP,
@ -996,10 +1009,10 @@ JXL_EXPORT JxlEncoderStatus JxlEncoderSetExtraChannelBuffer(
* the encoder encodes the size header itself. Most boxes are written
* automatically by the encoder as needed ("JXL ", "ftyp", "jxll", "jxlc",
* "jxlp", "jxli", "jbrd"), and this function only needs to be called to add
* optional metadata when encoding from pixels (using JxlEncoderAddImageFrame).
* When recompressing JPEG files (using JxlEncoderAddJPEGFrame), if the input
* JPEG contains EXIF, XMP or JUMBF metadata, the corresponding boxes are
* already added automatically.
* optional metadata when encoding from pixels (using @ref
* JxlEncoderAddImageFrame). When recompressing JPEG files (using @ref
* JxlEncoderAddJPEGFrame), if the input JPEG contains EXIF, XMP or JUMBF
* metadata, the corresponding boxes are already added automatically.
*
* Box types are given by 4 characters. The following boxes can be added with
* this function:
@ -1032,9 +1045,9 @@ JXL_EXPORT JxlEncoderStatus JxlEncoderSetExtraChannelBuffer(
* @param size size of the box contents.
* @param compress_box Whether to compress this box as a "brob" box. Requires
* Brotli support.
* @return JXL_ENC_SUCCESS on success, JXL_ENC_ERROR on error, such as when
* using this function without JxlEncoderUseContainer, or adding a box type
* that would result in an invalid file format.
* @return ::JXL_ENC_SUCCESS on success, ::JXL_ENC_ERROR on error, such as
* when using this function without @ref JxlEncoderUseContainer, or adding a box
* type that would result in an invalid file format.
*/
JXL_EXPORT JxlEncoderStatus JxlEncoderAddBox(JxlEncoder* enc,
const JxlBoxType type,
@ -1061,9 +1074,9 @@ JXL_EXPORT JxlEncoderStatus JxlEncoderUseBoxes(JxlEncoder* enc);
* the stream will be finished. It is not necessary to use this function if
* @ref JxlEncoderUseBoxes is not used. Further frames may still be added.
*
* Must be called between JxlEncoderAddBox of the last box
* and the next call to JxlEncoderProcessOutput, or @ref JxlEncoderProcessOutput
* won't output the last box correctly.
* Must be called between @ref JxlEncoderAddBox of the last box
* and the next call to @ref JxlEncoderProcessOutput, or @ref
* JxlEncoderProcessOutput won't output the last box correctly.
*
* NOTE: if you don't need to close frames and boxes at separate times, you can
* use @ref JxlEncoderCloseInput instead to close both at once.
@ -1087,10 +1100,10 @@ JXL_EXPORT void JxlEncoderCloseBoxes(JxlEncoder* enc);
JXL_EXPORT void JxlEncoderCloseFrames(JxlEncoder* enc);
/**
* Closes any input to the encoder, equivalent to calling JxlEncoderCloseFrames
* as well as calling JxlEncoderCloseBoxes if needed. No further input of any
* kind may be given to the encoder, but further @ref JxlEncoderProcessOutput
* calls should be done to create the final output.
* Closes any input to the encoder, equivalent to calling @ref
* JxlEncoderCloseFrames as well as calling @ref JxlEncoderCloseBoxes if needed.
* No further input of any kind may be given to the encoder, but further @ref
* JxlEncoderProcessOutput calls should be done to create the final output.
*
* The requirements of both @ref JxlEncoderCloseFrames and @ref
* JxlEncoderCloseBoxes apply to this function. Either this function or the
@ -1104,39 +1117,39 @@ JXL_EXPORT void JxlEncoderCloseInput(JxlEncoder* enc);
/**
* Sets the original color encoding of the image encoded by this encoder. This
* is an alternative to JxlEncoderSetICCProfile and only one of these two must
* be used. This one sets the color encoding as a @ref JxlColorEncoding, while
* the other sets it as ICC binary data.
* Must be called after JxlEncoderSetBasicInfo.
* is an alternative to @ref JxlEncoderSetICCProfile and only one of these two
* must be used. This one sets the color encoding as a @ref JxlColorEncoding,
* while the other sets it as ICC binary data. Must be called after @ref
* JxlEncoderSetBasicInfo.
*
* @param enc encoder object.
* @param color color encoding. Object owned by the caller and its contents are
* copied internally.
* @return JXL_ENC_SUCCESS if the operation was successful, JXL_ENC_ERROR or
* JXL_ENC_NOT_SUPPORTED otherwise
* @return ::JXL_ENC_SUCCESS if the operation was successful, @ref
* JXL_ENC_ERROR otherwise
*/
JXL_EXPORT JxlEncoderStatus
JxlEncoderSetColorEncoding(JxlEncoder* enc, const JxlColorEncoding* color);
/**
* Sets the original color encoding of the image encoded by this encoder as an
* ICC color profile. This is an alternative to JxlEncoderSetColorEncoding and
* only one of these two must be used. This one sets the color encoding as ICC
* binary data, while the other defines it as a @ref JxlColorEncoding.
* Must be called after JxlEncoderSetBasicInfo.
* ICC color profile. This is an alternative to @ref JxlEncoderSetColorEncoding
* and only one of these two must be used. This one sets the color encoding as
* ICC binary data, while the other defines it as a @ref JxlColorEncoding. Must
* be called after @ref JxlEncoderSetBasicInfo.
*
* @param enc encoder object.
* @param icc_profile bytes of the original ICC profile
* @param size size of the icc_profile buffer in bytes
* @return JXL_ENC_SUCCESS if the operation was successful, JXL_ENC_ERROR or
* JXL_ENC_NOT_SUPPORTED otherwise
* @return ::JXL_ENC_SUCCESS if the operation was successful, @ref
* JXL_ENC_ERROR otherwise
*/
JXL_EXPORT JxlEncoderStatus JxlEncoderSetICCProfile(JxlEncoder* enc,
const uint8_t* icc_profile,
size_t size);
/**
* Initializes a JxlBasicInfo struct to default values.
* Initializes a @ref JxlBasicInfo struct to default values.
* For forwards-compatibility, this function has to be called before values
* are assigned to the struct fields.
* The default values correspond to an 8-bit RGB image, no alpha or any
@ -1147,7 +1160,7 @@ JXL_EXPORT JxlEncoderStatus JxlEncoderSetICCProfile(JxlEncoder* enc,
JXL_EXPORT void JxlEncoderInitBasicInfo(JxlBasicInfo* info);
/**
* Initializes a JxlFrameHeader struct to default values.
* Initializes a @ref JxlFrameHeader struct to default values.
* For forwards-compatibility, this function has to be called before values
* are assigned to the struct fields.
* The default values correspond to a frame with no animation duration and the
@ -1159,7 +1172,7 @@ JXL_EXPORT void JxlEncoderInitBasicInfo(JxlBasicInfo* info);
JXL_EXPORT void JxlEncoderInitFrameHeader(JxlFrameHeader* frame_header);
/**
* Initializes a JxlBlendInfo struct to default values.
* Initializes a @ref JxlBlendInfo struct to default values.
* For forwards-compatibility, this function has to be called before values
* are assigned to the struct fields.
*
@ -1170,26 +1183,26 @@ JXL_EXPORT void JxlEncoderInitBlendInfo(JxlBlendInfo* blend_info);
/**
* Sets the global metadata of the image encoded by this encoder.
*
* If the JxlBasicInfo contains information of extra channels beyond an alpha
* channel, then @ref JxlEncoderSetExtraChannelInfo must be called between
* JxlEncoderSetBasicInfo and @ref JxlEncoderAddImageFrame. In order to indicate
* extra channels, the value of `info.num_extra_channels` should be set to the
* number of extra channels, also counting the alpha channel if present.
* If the @ref JxlBasicInfo contains information of extra channels beyond an
* alpha channel, then @ref JxlEncoderSetExtraChannelInfo must be called between
* @ref JxlEncoderSetBasicInfo and @ref JxlEncoderAddImageFrame. In order to
* indicate extra channels, the value of `info.num_extra_channels` should be set
* to the number of extra channels, also counting the alpha channel if present.
*
* @param enc encoder object.
* @param info global image metadata. Object owned by the caller and its
* contents are copied internally.
* @return JXL_ENC_SUCCESS if the operation was successful,
* JXL_ENC_ERROR or JXL_ENC_NOT_SUPPORTED otherwise
* @return ::JXL_ENC_SUCCESS if the operation was successful,
* ::JXL_ENC_ERROR otherwise
*/
JXL_EXPORT JxlEncoderStatus JxlEncoderSetBasicInfo(JxlEncoder* enc,
const JxlBasicInfo* info);
/**
* Sets the upsampling method the decoder will use in case there are frames
* with JXL_ENC_FRAME_SETTING_RESAMPLING set. This is useful in combination
* with the JXL_ENC_FRAME_SETTING_ALREADY_DOWNSAMPLED option, to control the
* type of upsampling that will be used.
* with ::JXL_ENC_FRAME_SETTING_RESAMPLING set. This is useful in combination
* with the ::JXL_ENC_FRAME_SETTING_ALREADY_DOWNSAMPLED option, to control
* the type of upsampling that will be used.
*
* @param enc encoder object.
* @param factor upsampling factor to configure (1, 2, 4 or 8; for 1 this
@ -1198,15 +1211,15 @@ JXL_EXPORT JxlEncoderStatus JxlEncoderSetBasicInfo(JxlEncoder* enc,
* -1: default (good for photographic images, no signaling overhead)
* 0: nearest neighbor (good for pixel art)
* 1: 'pixel dots' (same as NN for 2x, diamond-shaped 'pixel dots' for 4x/8x)
* @return JXL_ENC_SUCCESS if the operation was successful,
* JXL_ENC_ERROR or JXL_ENC_NOT_SUPPORTED otherwise
* @return ::JXL_ENC_SUCCESS if the operation was successful,
* ::JXL_ENC_ERROR otherwise
*/
JXL_EXPORT JxlEncoderStatus JxlEncoderSetUpsamplingMode(JxlEncoder* enc,
int64_t factor,
int64_t mode);
/**
* Initializes a JxlExtraChannelInfo struct to default values.
* Initializes a @ref JxlExtraChannelInfo struct to default values.
* For forwards-compatibility, this function has to be called before values
* are assigned to the struct fields.
* The default values correspond to an 8-bit channel of the provided type.
@ -1220,23 +1233,24 @@ JXL_EXPORT void JxlEncoderInitExtraChannelInfo(JxlExtraChannelType type,
/**
* Sets information for the extra channel at the given index. The index
* must be smaller than num_extra_channels in the associated JxlBasicInfo.
* must be smaller than num_extra_channels in the associated @ref JxlBasicInfo.
*
* @param enc encoder object
* @param index index of the extra channel to set.
* @param info global extra channel metadata. Object owned by the caller and its
* contents are copied internally.
* @return JXL_ENC_SUCCESS on success, JXL_ENC_ERROR on error
* @return ::JXL_ENC_SUCCESS on success, ::JXL_ENC_ERROR on error
*/
JXL_EXPORT JxlEncoderStatus JxlEncoderSetExtraChannelInfo(
JxlEncoder* enc, size_t index, const JxlExtraChannelInfo* info);
/**
* Sets the name for the extra channel at the given index in UTF-8. The index
* must be smaller than the num_extra_channels in the associated JxlBasicInfo.
* must be smaller than the num_extra_channels in the associated @ref
* JxlBasicInfo.
*
* TODO(lode): remove size parameter for consistency with
* JxlEncoderSetFrameName
* @ref JxlEncoderSetFrameName
*
* @param enc encoder object
* @param index index of the extra channel to set.
@ -1252,17 +1266,18 @@ JXL_EXPORT JxlEncoderStatus JxlEncoderSetExtraChannelName(JxlEncoder* enc,
/**
* Sets a frame-specific option of integer type to the encoder options.
* The JxlEncoderFrameSettingId argument determines which option is set.
* The @ref JxlEncoderFrameSettingId argument determines which option is set.
*
* @param frame_settings set of options and metadata for this frame. Also
* includes reference to the encoder object.
* @param option ID of the option to set.
* @param value Integer value to set for this option.
* @return JXL_ENC_SUCCESS if the operation was successful, JXL_ENC_ERROR in
* case of an error, such as invalid or unknown option id, or invalid integer
* value for the given option. If an error is returned, the state of the
* JxlEncoderFrameSettings object is still valid and is the same as before this
* function was called.
* @return ::JXL_ENC_SUCCESS if the operation was successful, @ref
* JXL_ENC_ERROR in case of an error, such as invalid or unknown option id, or
* invalid integer value for the given option. If an error is returned, the
* state of the
* @ref JxlEncoderFrameSettings object is still valid and is the same as before
* this function was called.
*/
JXL_EXPORT JxlEncoderStatus JxlEncoderFrameSettingsSetOption(
JxlEncoderFrameSettings* frame_settings, JxlEncoderFrameSettingId option,
@ -1270,17 +1285,18 @@ JXL_EXPORT JxlEncoderStatus JxlEncoderFrameSettingsSetOption(
/**
* Sets a frame-specific option of float type to the encoder options.
* The JxlEncoderFrameSettingId argument determines which option is set.
* The @ref JxlEncoderFrameSettingId argument determines which option is set.
*
* @param frame_settings set of options and metadata for this frame. Also
* includes reference to the encoder object.
* @param option ID of the option to set.
* @param value Float value to set for this option.
* @return JXL_ENC_SUCCESS if the operation was successful, JXL_ENC_ERROR in
* case of an error, such as invalid or unknown option id, or invalid integer
* value for the given option. If an error is returned, the state of the
* JxlEncoderFrameSettings object is still valid and is the same as before this
* function was called.
* @return ::JXL_ENC_SUCCESS if the operation was successful, @ref
* JXL_ENC_ERROR in case of an error, such as invalid or unknown option id, or
* invalid integer value for the given option. If an error is returned, the
* state of the
* @ref JxlEncoderFrameSettings object is still valid and is the same as before
* this function was called.
*/
JXL_EXPORT JxlEncoderStatus JxlEncoderFrameSettingsSetFloatOption(
JxlEncoderFrameSettings* frame_settings, JxlEncoderFrameSettingId option,
@ -1292,7 +1308,7 @@ JXL_EXPORT JxlEncoderStatus JxlEncoderFrameSettingsSetFloatOption(
* When using @ref JxlEncoderUseBoxes, @ref JxlEncoderStoreJPEGMetadata or @ref
* JxlEncoderSetCodestreamLevel with level 10, the encoder will automatically
* also use the container format, it is not necessary to use
* JxlEncoderUseContainer for those use cases.
* @ref JxlEncoderUseContainer for those use cases.
*
* By default this setting is disabled.
*
@ -1318,8 +1334,8 @@ JXL_EXPORT JxlEncoderStatus JxlEncoderUseContainer(JxlEncoder* enc,
*
* @param enc encoder object.
* @param store_jpeg_metadata true if the encoder should store JPEG metadata.
* @return JXL_ENC_SUCCESS if the operation was successful, JXL_ENC_ERROR
* otherwise.
* @return ::JXL_ENC_SUCCESS if the operation was successful, @ref
* JXL_ENC_ERROR otherwise.
*/
JXL_EXPORT JxlEncoderStatus
JxlEncoderStoreJPEGMetadata(JxlEncoder* enc, JXL_BOOL store_jpeg_metadata);
@ -1334,8 +1350,8 @@ JxlEncoderStoreJPEGMetadata(JxlEncoder* enc, JXL_BOOL store_jpeg_metadata);
* 268435456 pixels total with a maximum width or height of 262144 pixels,
* maximum 16-bit color channel depth, maximum 120 frames per second for
* animation, maximum ICC color profile size of 4 MiB, it allows all color
* models and extra channel types except CMYK and the JXL_CHANNEL_BLACK extra
* channel, and a maximum of 4 extra channels in addition to the 3 color
* models and extra channel types except CMYK and the JXL_CHANNEL_BLACK
* extra channel, and a maximum of 4 extra channels in addition to the 3 color
* channels. It also sets boundaries to certain internally used coding tools.
*
* Level 10: this level removes or increases the bounds of most of the level
@ -1355,8 +1371,8 @@ JxlEncoderStoreJPEGMetadata(JxlEncoder* enc, JXL_BOOL store_jpeg_metadata);
*
* @param enc encoder object.
* @param level the level value to set, must be -1, 5, or 10.
* @return JXL_ENC_SUCCESS if the operation was successful, JXL_ENC_ERROR
* otherwise.
* @return ::JXL_ENC_SUCCESS if the operation was successful, @ref
* JXL_ENC_ERROR otherwise.
*/
JXL_EXPORT JxlEncoderStatus JxlEncoderSetCodestreamLevel(JxlEncoder* enc,
int level);
@ -1370,9 +1386,10 @@ JXL_EXPORT JxlEncoderStatus JxlEncoderSetCodestreamLevel(JxlEncoder* enc,
* the JPEG XL file.
*
* If this returns 5, nothing needs to be done and the codestream can be
* compatible with any decoder. If this returns 10, JxlEncoderSetCodestreamLevel
* has to be used to set the codestream level to 10, or the encoder can be
* configured differently to allow using the more compatible level 5.
* compatible with any decoder. If this returns 10, @ref
* JxlEncoderSetCodestreamLevel has to be used to set the codestream level to
* 10, or the encoder can be configured differently to allow using the more
* compatible level 5.
*
* @param enc encoder object.
* @return -1 if no level can support the configuration (e.g. image dimensions
@ -1391,14 +1408,14 @@ JXL_EXPORT int JxlEncoderGetRequiredCodestreamLevel(const JxlEncoder* enc);
*
* When disabled, those options are not overridden, but since those options
* could still have been manually set to a combination that operates losslessly,
* using this function with lossless set to JXL_DEC_FALSE does not guarantee
* lossy encoding, though the default set of options is lossy.
* using this function with lossless set to ::JXL_FALSE does not
* guarantee lossy encoding, though the default set of options is lossy.
*
* @param frame_settings set of options and metadata for this frame. Also
* includes reference to the encoder object.
* @param lossless whether to override options for lossless mode
* @return JXL_ENC_SUCCESS if the operation was successful, JXL_ENC_ERROR
* otherwise.
* @return ::JXL_ENC_SUCCESS if the operation was successful, @ref
* JXL_ENC_ERROR otherwise.
*/
JXL_EXPORT JxlEncoderStatus JxlEncoderSetFrameLossless(
JxlEncoderFrameSettings* frame_settings, JXL_BOOL lossless);
@ -1406,7 +1423,7 @@ JXL_EXPORT JxlEncoderStatus JxlEncoderSetFrameLossless(
/**
* Sets the distance level for lossy compression: target max butteraugli
* distance, lower = higher quality. Range: 0 .. 25.
* 0.0 = mathematically lossless (however, use JxlEncoderSetFrameLossless
* 0.0 = mathematically lossless (however, use @ref JxlEncoderSetFrameLossless
* instead to use true lossless, as setting distance to 0 alone is not the only
* requirement). 1.0 = visually lossless. Recommended range: 0.5 .. 3.0. Default
* value: 1.0.
@ -1414,24 +1431,25 @@ JXL_EXPORT JxlEncoderStatus JxlEncoderSetFrameLossless(
* @param frame_settings set of options and metadata for this frame. Also
* includes reference to the encoder object.
* @param distance the distance value to set.
* @return JXL_ENC_SUCCESS if the operation was successful, JXL_ENC_ERROR
* otherwise.
* @return ::JXL_ENC_SUCCESS if the operation was successful, @ref
* JXL_ENC_ERROR otherwise.
*/
JXL_EXPORT JxlEncoderStatus JxlEncoderSetFrameDistance(
JxlEncoderFrameSettings* frame_settings, float distance);
/**
* Sets the distance level for lossy compression of extra channels.
* The distance is as in JxlEncoderSetFrameDistance (lower = higher quality).
* If not set, or if set to the special value -1, the distance that was set with
* JxlEncoderSetFrameDistance will be used.
* The distance is as in @ref JxlEncoderSetFrameDistance (lower = higher
* quality). If not set, or if set to the special value -1, the distance that
* was set with
* @ref JxlEncoderSetFrameDistance will be used.
*
* @param frame_settings set of options and metadata for this frame. Also
* includes reference to the encoder object.
* @param index index of the extra channel to set a distance value for.
* @param distance the distance value to set.
* @return JXL_ENC_SUCCESS if the operation was successful, JXL_ENC_ERROR
* otherwise.
* @return ::JXL_ENC_SUCCESS if the operation was successful, @ref
* JXL_ENC_ERROR otherwise.
*/
JXL_EXPORT JxlEncoderStatus JxlEncoderSetExtraChannelDistance(
JxlEncoderFrameSettings* frame_settings, size_t index, float distance);
@ -1441,8 +1459,7 @@ JXL_EXPORT JxlEncoderStatus JxlEncoderSetExtraChannelDistance(
*
* This function takes in input a JPEG-style quality factor `quality` and
* produces as output a `distance` value suitable to be used with @ref
* JxlEncoderSetFrameDistance and
* @ref JxlEncoderSetExtraChannelDistance.
* JxlEncoderSetFrameDistance and @ref JxlEncoderSetExtraChannelDistance.
*
* The `distance` value influences the level of compression, with lower values
* indicating higher quality:
@ -1479,10 +1496,10 @@ JXL_EXPORT float JxlEncoderDistanceFromQuality(float quality);
* the @p source options, or set to default if @p source is NULL.
*
* The returned pointer is an opaque struct tied to the encoder and it will be
* deallocated by the encoder when JxlEncoderDestroy() is called. For functions
* taking both a @ref JxlEncoder and a @ref JxlEncoderFrameSettings, only
* JxlEncoderFrameSettings created with this function for the same encoder
* instance can be used.
* deallocated by the encoder when @ref JxlEncoderDestroy() is called. For
* functions taking both a @ref JxlEncoder and a @ref JxlEncoderFrameSettings,
* only @ref JxlEncoderFrameSettings created with this function for the same
* encoder instance can be used.
*
* @param enc encoder object.
* @param source source options to copy initial values from, or NULL to get

Просмотреть файл

@ -46,39 +46,41 @@ extern "C" {
/** Return code used in the JxlParallel* functions as return value. A value
* of 0 means success and any other value means error. The special value
* JXL_PARALLEL_RET_RUNNER_ERROR can be used by the runner to indicate any
* ::JXL_PARALLEL_RET_RUNNER_ERROR can be used by the runner to indicate any
* other error.
*/
typedef int JxlParallelRetCode;
/**
* General error returned by the JxlParallelRunInit function to indicate
* General error returned by the @ref JxlParallelRunInit function to indicate
* an error.
*/
#define JXL_PARALLEL_RET_RUNNER_ERROR (-1)
/**
* Parallel run initialization callback. See JxlParallelRunner for details.
* Parallel run initialization callback. See @ref JxlParallelRunner for details.
*
* This function MUST be called by the JxlParallelRunner only once, on the
* same thread that called JxlParallelRunner, before any parallel execution.
* The purpose of this call is to provide the maximum number of threads that the
* JxlParallelRunner will use, which can be used by JPEG XL to allocate
* same thread that called @ref JxlParallelRunner, before any parallel
* execution. The purpose of this call is to provide the maximum number of
* threads that the
* @ref JxlParallelRunner will use, which can be used by JPEG XL to allocate
* per-thread storage if needed.
*
* @param jpegxl_opaque the @p jpegxl_opaque handle provided to
* JxlParallelRunner() must be passed here.
* @ref JxlParallelRunner() must be passed here.
* @param num_threads the maximum number of threads. This value must be
* positive.
* @return 0 if the initialization process was successful.
* @return an error code if there was an error, which should be returned by
* JxlParallelRunner().
* @ref JxlParallelRunner().
*/
typedef JxlParallelRetCode (*JxlParallelRunInit)(void* jpegxl_opaque,
size_t num_threads);
/**
* Parallel run data processing callback. See JxlParallelRunner for details.
* Parallel run data processing callback. See @ref JxlParallelRunner for
* details.
*
* This function MUST be called once for every number in the range [start_range,
* end_range) (including start_range but not including end_range) passing this
@ -86,11 +88,11 @@ typedef JxlParallelRetCode (*JxlParallelRunInit)(void* jpegxl_opaque,
* different threads in parallel.
*
* @param jpegxl_opaque the @p jpegxl_opaque handle provided to
* JxlParallelRunner() must be passed here.
* @ref JxlParallelRunner() must be passed here.
* @param value the number in the range [start_range, end_range) of the call.
* @param thread_id the thread number where this function is being called from.
* This must be lower than the @p num_threads value passed to
* JxlParallelRunInit.
* @ref JxlParallelRunInit.
*/
typedef void (*JxlParallelRunFunction)(void* jpegxl_opaque, uint32_t value,
size_t thread_id);
@ -103,11 +105,12 @@ typedef void (*JxlParallelRunFunction)(void* jpegxl_opaque, uint32_t value,
* number in the range [start_range, end_range) (including start_range but not
* including end_range) possibly from different multiple threads in parallel.
*
* The JxlParallelRunner function does not need to be re-entrant. This means
* that the same JxlParallelRunner function with the same runner_opaque
* provided parameter will not be called from the library from either @p init or
* The @ref JxlParallelRunner function does not need to be re-entrant. This
* means that the same @ref JxlParallelRunner function with the same
* runner_opaque provided parameter will not be called from the library from
* either @p init or
* @p func in the same decoder or encoder instance. However, a single decoding
* or encoding instance may call the provided JxlParallelRunner multiple
* or encoding instance may call the provided @ref JxlParallelRunner multiple
* times for different parts of the decoding or encoding process.
*
* @return 0 if the @p init call succeeded (returned 0) and no other error
@ -120,7 +123,7 @@ typedef JxlParallelRetCode (*JxlParallelRunner)(
void* runner_opaque, void* jpegxl_opaque, JxlParallelRunInit init,
JxlParallelRunFunction func, uint32_t start_range, uint32_t end_range);
/* The following is an example of a JxlParallelRunner that doesn't use any
/* The following is an example of a @ref JxlParallelRunner that doesn't use any
* multi-threading. Note that this implementation doesn't store any state
* between multiple calls of the ExampleSequentialRunner function, so the
* runner_opaque value is not used.

Просмотреть файл

@ -16,7 +16,7 @@
* created can be changed after creation of the thread pool; the threads
* (including the main thread) are re-used for every
* ResizableParallelRunner::Runner call. Only one concurrent
* JxlResizableParallelRunner call per instance is allowed at a time.
* @ref JxlResizableParallelRunner call per instance is allowed at a time.
*
* This is a scalable, lower-overhead thread pool runner, especially suitable
* for data-parallel computations in the fork-join model, where clients need to
@ -41,20 +41,20 @@
extern "C" {
#endif
/** Parallel runner internally using std::thread. Use as JxlParallelRunner.
/** Parallel runner internally using std::thread. Use as @ref JxlParallelRunner.
*/
JXL_THREADS_EXPORT JxlParallelRetCode JxlResizableParallelRunner(
void* runner_opaque, void* jpegxl_opaque, JxlParallelRunInit init,
JxlParallelRunFunction func, uint32_t start_range, uint32_t end_range);
/** Creates the runner for JxlResizableParallelRunner. Use as the opaque
/** Creates the runner for @ref JxlResizableParallelRunner. Use as the opaque
* runner. The runner will execute tasks on the calling thread until
* @ref JxlResizableParallelRunnerSetThreads is called.
*/
JXL_THREADS_EXPORT void* JxlResizableParallelRunnerCreate(
const JxlMemoryManager* memory_manager);
/** Changes the number of threads for JxlResizableParallelRunner.
/** Changes the number of threads for @ref JxlResizableParallelRunner.
*/
JXL_THREADS_EXPORT void JxlResizableParallelRunnerSetThreads(
void* runner_opaque, size_t num_threads);
@ -64,7 +64,7 @@ JXL_THREADS_EXPORT void JxlResizableParallelRunnerSetThreads(
JXL_THREADS_EXPORT uint32_t
JxlResizableParallelRunnerSuggestThreads(uint64_t xsize, uint64_t ysize);
/** Destroys the runner created by JxlResizableParallelRunnerCreate.
/** Destroys the runner created by @ref JxlResizableParallelRunnerCreate.
*/
JXL_THREADS_EXPORT void JxlResizableParallelRunnerDestroy(void* runner_opaque);

8
third_party/jpeg-xl/lib/include/jxl/stats.h поставляемый
Просмотреть файл

@ -23,15 +23,15 @@ extern "C" {
/**
* Opaque structure that holds the encoder statistics.
*
* Allocated and initialized with JxlEncoderStatsCreate().
* Cleaned up and deallocated with JxlEncoderStatsDestroy().
* Allocated and initialized with @ref JxlEncoderStatsCreate().
* Cleaned up and deallocated with @ref JxlEncoderStatsDestroy().
*/
typedef struct JxlEncoderStatsStruct JxlEncoderStats;
/**
* Creates an instance of JxlEncoderStats and initializes it.
*
* @return pointer to initialized JxlEncoderStats instance
* @return pointer to initialized @ref JxlEncoderStats instance
*/
JXL_EXPORT JxlEncoderStats* JxlEncoderStatsCreate(void);
@ -43,7 +43,7 @@ JXL_EXPORT JxlEncoderStats* JxlEncoderStatsCreate(void);
*/
JXL_EXPORT void JxlEncoderStatsDestroy(JxlEncoderStats* stats);
/** Data type for querying JxlEncoderStats object
/** Data type for querying @ref JxlEncoderStats object
*/
typedef enum {
JXL_ENC_STAT_HEADER_BITS,

Просмотреть файл

@ -41,24 +41,24 @@
extern "C" {
#endif
/** Parallel runner internally using std::thread. Use as JxlParallelRunner.
/** Parallel runner internally using std::thread. Use as @ref JxlParallelRunner.
*/
JXL_THREADS_EXPORT JxlParallelRetCode JxlThreadParallelRunner(
void* runner_opaque, void* jpegxl_opaque, JxlParallelRunInit init,
JxlParallelRunFunction func, uint32_t start_range, uint32_t end_range);
/** Creates the runner for JxlThreadParallelRunner. Use as the opaque
/** Creates the runner for @ref JxlThreadParallelRunner. Use as the opaque
* runner.
*/
JXL_THREADS_EXPORT void* JxlThreadParallelRunnerCreate(
const JxlMemoryManager* memory_manager, size_t num_worker_threads);
/** Destroys the runner created by JxlThreadParallelRunnerCreate.
/** Destroys the runner created by @ref JxlThreadParallelRunnerCreate.
*/
JXL_THREADS_EXPORT void JxlThreadParallelRunnerDestroy(void* runner_opaque);
/** Returns a default num_worker_threads value for
* JxlThreadParallelRunnerCreate.
* @ref JxlThreadParallelRunnerCreate.
*/
JXL_THREADS_EXPORT size_t JxlThreadParallelRunnerDefaultNumWorkerThreads(void);

8
third_party/jpeg-xl/lib/include/jxl/types.h поставляемый
Просмотреть файл

@ -13,7 +13,6 @@
#ifndef JXL_TYPES_H_
#define JXL_TYPES_H_
#include <jxl/jxl_export.h>
#include <stddef.h>
#include <stdint.h>
@ -32,7 +31,7 @@ extern "C" {
#define JXL_TRUE 1
/** Portable @c false replacement. */
#define JXL_FALSE 0
/** Converts of bool-like value to either JXL_TRUE or JXL_FALSE. */
/** Converts of bool-like value to either ::JXL_TRUE or ::JXL_FALSE. */
#define TO_JXL_BOOL(C) (!!(C) ? JXL_TRUE : JXL_FALSE)
/** Data type for the sample values per channel per pixel.
@ -40,7 +39,7 @@ extern "C" {
typedef enum {
/** Use 32-bit single-precision floating point values, with range 0.0-1.0
* (within gamut, may go outside this range for wide color gamut). Floating
* point output, either JXL_TYPE_FLOAT or JXL_TYPE_FLOAT16, is recommended
* point output, either ::JXL_TYPE_FLOAT or ::JXL_TYPE_FLOAT16, is recommended
* for HDR and wide gamut images when color profile conversion is required. */
JXL_TYPE_FLOAT = 0,
@ -92,8 +91,7 @@ typedef struct {
JxlDataType data_type;
/** Whether multi-byte data types are represented in big endian or little
* endian format. This applies to JXL_TYPE_UINT16, JXL_TYPE_UINT32
* and JXL_TYPE_FLOAT.
* endian format. This applies to ::JXL_TYPE_UINT16 and ::JXL_TYPE_FLOAT.
*/
JxlEndianness endianness;

Просмотреть файл

@ -113,7 +113,7 @@ void DecodeWithLibjpeg(const CompressParams& jparams,
jpeg_read_header(cinfo, /*require_image=*/TRUE));
if (!jparams.icc.empty()) {
uint8_t* icc_data = nullptr;
unsigned int icc_len;
unsigned int icc_len = 0; // "unpoison" via initialization
JXL_CHECK(jpeg_read_icc_profile(cinfo, &icc_data, &icc_len));
JXL_CHECK(icc_data);
jxl::msan::UnpoisonMemory(icc_data, icc_len);

4
third_party/jpeg-xl/lib/jxl.cmake поставляемый
Просмотреть файл

@ -60,7 +60,7 @@ include(GenerateExportHeader)
# CMake does not allow generate_export_header for INTERFACE library, so we
# add this stub library just for file generation.
add_library(jxl_export OBJECT ${JPEGXL_INTERNAL_PUBLIC_HEADERS})
add_library(jxl_export OBJECT ${JPEGXL_INTERNAL_PUBLIC_HEADERS} nothing.cc)
set_target_properties(jxl_export PROPERTIES
CXX_VISIBILITY_PRESET hidden
VISIBILITY_INLINES_HIDDEN 1
@ -269,8 +269,10 @@ set(JPEGXL_LIBRARY_REQUIRES
if (BUILD_SHARED_LIBS)
set(JPEGXL_REQUIRES_TYPE "Requires.private")
set(JPEGXL_PRIVATE_LIBS "-lm ${PKGCONFIG_CXX_LIB}")
else()
set(JPEGXL_REQUIRES_TYPE "Requires")
set(JPEGXL_PUBLIC_LIBS "-lm ${PKGCONFIG_CXX_LIB}")
endif()
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/jxl/libjxl.pc.in"

13
third_party/jpeg-xl/lib/jxl/ac_strategy.cc поставляемый
Просмотреть файл

@ -8,12 +8,9 @@
#include <string.h>
#include <algorithm>
#include <numeric> // iota
#include <type_traits>
#include <utility>
#include "lib/jxl/base/bits.h"
#include "lib/jxl/image_ops.h"
namespace jxl {
@ -86,10 +83,12 @@ constexpr size_t AcStrategy::kMaxCoeffBlocks;
constexpr size_t AcStrategy::kMaxBlockDim;
constexpr size_t AcStrategy::kMaxCoeffArea;
AcStrategyImage::AcStrategyImage(size_t xsize, size_t ysize)
: layers_(xsize, ysize) {
row_ = layers_.Row(0);
stride_ = layers_.PixelsPerRow();
StatusOr<AcStrategyImage> AcStrategyImage::Create(size_t xsize, size_t ysize) {
AcStrategyImage img;
JXL_ASSIGN_OR_RETURN(img.layers_, ImageB::Create(xsize, ysize));
img.row_ = img.layers_.Row(0);
img.stride_ = img.layers_.PixelsPerRow();
return img;
}
size_t AcStrategyImage::CountBlocks(AcStrategy::Type type) const {

3
third_party/jpeg-xl/lib/jxl/ac_strategy.h поставляемый
Просмотреть файл

@ -191,7 +191,8 @@ class AcStrategyRow {
class AcStrategyImage {
public:
AcStrategyImage() = default;
AcStrategyImage(size_t xsize, size_t ysize);
static StatusOr<AcStrategyImage> Create(size_t xsize, size_t ysize);
AcStrategyImage(AcStrategyImage&&) = default;
AcStrategyImage& operator=(AcStrategyImage&&) = default;

3
third_party/jpeg-xl/lib/jxl/base/common.h поставляемый
Просмотреть файл

@ -90,6 +90,9 @@ std::string ToString(T n) {
return data;
}
#define JXL_JOIN(x, y) JXL_DO_JOIN(x, y)
#define JXL_DO_JOIN(x, y) x##y
} // namespace jxl
#endif // LIB_JXL_BASE_COMMON_H_

15
third_party/jpeg-xl/lib/jxl/base/status.h поставляемый
Просмотреть файл

@ -16,6 +16,7 @@
#include <type_traits>
#include <utility>
#include "lib/jxl/base/common.h"
#include "lib/jxl/base/compiler_specific.h"
#include "lib/jxl/base/sanitizer_definitions.h"
@ -442,7 +443,7 @@ class JXL_MUST_USE_RESULT StatusOr {
#define JXL_ASSIGN_OR_RETURN(lhs, statusor) \
PRIVATE_JXL_ASSIGN_OR_RETURN_IMPL( \
assign_or_return_temporary_variable##__LINE__, lhs, statusor)
JXL_JOIN(assign_or_return_temporary_variable, __LINE__), lhs, statusor)
// NOLINTBEGIN(bugprone-macro-parentheses)
#define PRIVATE_JXL_ASSIGN_OR_RETURN_IMPL(name, lhs, statusor) \
@ -451,6 +452,18 @@ class JXL_MUST_USE_RESULT StatusOr {
lhs = std::move(name).value();
// NOLINTEND(bugprone-macro-parentheses)
// NB: do not use outside of tests / tools!!!
#define JXL_ASSIGN_OR_DIE(lhs, statusor) \
PRIVATE_JXL_ASSIGN_OR_DIE_IMPL( \
JXL_JOIN(assign_or_die_temporary_variable, __LINE__), lhs, statusor)
// NOLINTBEGIN(bugprone-macro-parentheses)
#define PRIVATE_JXL_ASSIGN_OR_DIE_IMPL(name, lhs, statusor) \
auto name = statusor; \
if (!name.ok()) jxl::Abort(); \
lhs = std::move(name).value();
// NOLINTEND(bugprone-macro-parentheses)
} // namespace jxl
#endif // LIB_JXL_BASE_STATUS_H_

14
third_party/jpeg-xl/lib/jxl/blending.cc поставляемый
Просмотреть файл

@ -6,7 +6,6 @@
#include "lib/jxl/blending.h"
#include "lib/jxl/alpha.h"
#include "lib/jxl/image_ops.h"
namespace jxl {
@ -29,11 +28,11 @@ bool NeedsBlending(const FrameHeader& frame_header) {
return true;
}
void PerformBlending(const float* const* bg, const float* const* fg,
float* const* out, size_t x0, size_t xsize,
const PatchBlending& color_blending,
const PatchBlending* ec_blending,
const std::vector<ExtraChannelInfo>& extra_channel_info) {
Status PerformBlending(
const float* const* bg, const float* const* fg, float* const* out,
size_t x0, size_t xsize, const PatchBlending& color_blending,
const PatchBlending* ec_blending,
const std::vector<ExtraChannelInfo>& extra_channel_info) {
bool has_alpha = false;
size_t num_ec = extra_channel_info.size();
for (size_t i = 0; i < num_ec; i++) {
@ -42,7 +41,7 @@ void PerformBlending(const float* const* bg, const float* const* fg,
break;
}
}
ImageF tmp(xsize, 3 + num_ec);
JXL_ASSIGN_OR_RETURN(ImageF tmp, ImageF::Create(xsize, 3 + num_ec));
// Blend extra channels first so that we use the pre-blending alpha.
for (size_t i = 0; i < num_ec; i++) {
if (ec_blending[i].mode == PatchBlendMode::kAdd) {
@ -146,6 +145,7 @@ void PerformBlending(const float* const* bg, const float* const* fg,
for (size_t i = 0; i < 3 + num_ec; i++) {
if (xsize != 0) memcpy(out[i] + x0, tmp.Row(i), xsize * sizeof(**out));
}
return true;
}
} // namespace jxl

10
third_party/jpeg-xl/lib/jxl/blending.h поставляемый
Просмотреть файл

@ -16,11 +16,11 @@ namespace jxl {
bool NeedsBlending(const FrameHeader& frame_header);
void PerformBlending(const float* const* bg, const float* const* fg,
float* const* out, size_t x0, size_t xsize,
const PatchBlending& color_blending,
const PatchBlending* ec_blending,
const std::vector<ExtraChannelInfo>& extra_channel_info);
Status PerformBlending(const float* const* bg, const float* const* fg,
float* const* out, size_t x0, size_t xsize,
const PatchBlending& color_blending,
const PatchBlending* ec_blending,
const std::vector<ExtraChannelInfo>& extra_channel_info);
} // namespace jxl

Просмотреть файл

@ -40,8 +40,10 @@ TEST(BlendingTest, Crops) {
jxl::test::ReadTestData(filename.str());
extras::PackedPixelFile decoded_frame_ppf;
decoded_frame_ppf.info = decoded.info;
decoded_frame_ppf.icc = decoded.icc;
decoded_frame_ppf.primary_color_representation =
decoded.primary_color_representation;
decoded_frame_ppf.color_encoding = decoded.color_encoding;
decoded_frame_ppf.icc = decoded.icc;
decoded_frame_ppf.extra_channels_info = decoded.extra_channels_info;
decoded_frame_ppf.frames.emplace_back(std::move(decoded_frame));
extras::PackedPixelFile expected_frame_ppf;

Просмотреть файл

@ -28,11 +28,12 @@
#include <string.h>
#include <algorithm>
#include <array>
#include <cmath>
#include <new>
#include <memory>
#include <vector>
#include "lib/jxl/image.h"
#undef HWY_TARGET_INCLUDE
#define HWY_TARGET_INCLUDE "lib/jxl/butteraugli/butteraugli.cc"
#include <hwy/foreach_target.h>
@ -222,8 +223,8 @@ void ConvolutionWithTranspose(const ImageF& in,
// We retain a special case for 5x5 kernels (even faster than gauss_blur),
// optionally use gauss_blur followed by fixup of the borders for large images,
// or fall back to the previous truncated FIR followed by a transpose.
void Blur(const ImageF& in, float sigma, const ButteraugliParams& params,
BlurTemp* temp, ImageF* out) {
Status Blur(const ImageF& in, float sigma, const ButteraugliParams& params,
BlurTemp* temp, ImageF* out) {
std::vector<float> kernel = ComputeKernel(sigma);
// Separable5 does an in-place convolution, so this fast path is not safe if
// in aliases out.
@ -241,12 +242,14 @@ void Blur(const ImageF& in, float sigma, const ButteraugliParams& params,
{HWY_REP4(w0), HWY_REP4(w1), HWY_REP4(w2)},
};
Separable5(in, Rect(in), weights, /*pool=*/nullptr, out);
return;
return true;
}
ImageF* JXL_RESTRICT temp_t = temp->GetTransposed(in);
ImageF* temp_t;
JXL_RETURN_IF_ERROR(temp->GetTransposed(in, &temp_t));
ConvolutionWithTranspose(in, kernel, temp_t);
ConvolutionWithTranspose(*temp_t, kernel, out);
return true;
}
// Allows PaddedMaltaUnit to call either function via overloading.
@ -386,29 +389,32 @@ void Subtract(const ImageF& a, const ImageF& b, ImageF* c) {
}
}
void SeparateLFAndMF(const ButteraugliParams& params, const Image3F& xyb,
Image3F* lf, Image3F* mf, BlurTemp* blur_temp) {
Status SeparateLFAndMF(const ButteraugliParams& params, const Image3F& xyb,
Image3F* lf, Image3F* mf, BlurTemp* blur_temp) {
static const double kSigmaLf = 7.15593339443;
for (int i = 0; i < 3; ++i) {
// Extract lf ...
Blur(xyb.Plane(i), kSigmaLf, params, blur_temp, &lf->Plane(i));
JXL_RETURN_IF_ERROR(
Blur(xyb.Plane(i), kSigmaLf, params, blur_temp, &lf->Plane(i)));
// ... and keep everything else in mf.
Subtract(xyb.Plane(i), lf->Plane(i), &mf->Plane(i));
}
XybLowFreqToVals(lf);
return true;
}
void SeparateMFAndHF(const ButteraugliParams& params, Image3F* mf, ImageF* hf,
BlurTemp* blur_temp) {
Status SeparateMFAndHF(const ButteraugliParams& params, Image3F* mf, ImageF* hf,
BlurTemp* blur_temp) {
const HWY_FULL(float) d;
static const double kSigmaHf = 3.22489901262;
const size_t xsize = mf->xsize();
const size_t ysize = mf->ysize();
hf[0] = ImageF(xsize, ysize);
hf[1] = ImageF(xsize, ysize);
JXL_ASSIGN_OR_RETURN(hf[0], ImageF::Create(xsize, ysize));
JXL_ASSIGN_OR_RETURN(hf[1], ImageF::Create(xsize, ysize));
for (int i = 0; i < 3; ++i) {
if (i == 2) {
Blur(mf->Plane(i), kSigmaHf, params, blur_temp, &mf->Plane(i));
JXL_RETURN_IF_ERROR(
Blur(mf->Plane(i), kSigmaHf, params, blur_temp, &mf->Plane(i)));
break;
}
for (size_t y = 0; y < ysize; ++y) {
@ -418,7 +424,8 @@ void SeparateMFAndHF(const ButteraugliParams& params, Image3F* mf, ImageF* hf,
Store(Load(d, row_mf + x), d, row_hf + x);
}
}
Blur(mf->Plane(i), kSigmaHf, params, blur_temp, &mf->Plane(i));
JXL_RETURN_IF_ERROR(
Blur(mf->Plane(i), kSigmaHf, params, blur_temp, &mf->Plane(i)));
static const double kRemoveMfRange = 0.29;
static const double kAddMfRange = 0.1;
if (i == 0) {
@ -450,16 +457,17 @@ void SeparateMFAndHF(const ButteraugliParams& params, Image3F* mf, ImageF* hf,
}
// Suppress red-green by intensity change in the high freq channels.
SuppressXByY(hf[1], &hf[0]);
return true;
}
void SeparateHFAndUHF(const ButteraugliParams& params, ImageF* hf, ImageF* uhf,
BlurTemp* blur_temp) {
Status SeparateHFAndUHF(const ButteraugliParams& params, ImageF* hf,
ImageF* uhf, BlurTemp* blur_temp) {
const HWY_FULL(float) d;
const size_t xsize = hf[0].xsize();
const size_t ysize = hf[0].ysize();
static const double kSigmaUhf = 1.56416327805;
uhf[0] = ImageF(xsize, ysize);
uhf[1] = ImageF(xsize, ysize);
JXL_ASSIGN_OR_RETURN(uhf[0], ImageF::Create(xsize, ysize));
JXL_ASSIGN_OR_RETURN(uhf[1], ImageF::Create(xsize, ysize));
for (int i = 0; i < 2; ++i) {
// Divide hf into hf and uhf.
for (size_t y = 0; y < ysize; ++y) {
@ -469,7 +477,7 @@ void SeparateHFAndUHF(const ButteraugliParams& params, ImageF* hf, ImageF* uhf,
row_uhf[x] = row_hf[x];
}
}
Blur(hf[i], kSigmaUhf, params, blur_temp, &hf[i]);
JXL_RETURN_IF_ERROR(Blur(hf[i], kSigmaUhf, params, blur_temp, &hf[i]));
static const double kRemoveHfRange = 1.5;
static const double kAddHfRange = 0.132;
static const double kRemoveUhfRange = 0.04;
@ -510,6 +518,7 @@ void SeparateHFAndUHF(const ButteraugliParams& params, ImageF* hf, ImageF* uhf,
}
}
}
return true;
}
void DeallocateHFAndUHF(ImageF* hf, ImageF* uhf) {
@ -519,15 +528,16 @@ void DeallocateHFAndUHF(ImageF* hf, ImageF* uhf) {
}
}
static void SeparateFrequencies(size_t xsize, size_t ysize,
const ButteraugliParams& params,
BlurTemp* blur_temp, const Image3F& xyb,
PsychoImage& ps) {
ps.lf = Image3F(xyb.xsize(), xyb.ysize());
ps.mf = Image3F(xyb.xsize(), xyb.ysize());
SeparateLFAndMF(params, xyb, &ps.lf, &ps.mf, blur_temp);
SeparateMFAndHF(params, &ps.mf, &ps.hf[0], blur_temp);
SeparateHFAndUHF(params, &ps.hf[0], &ps.uhf[0], blur_temp);
Status SeparateFrequencies(size_t xsize, size_t ysize,
const ButteraugliParams& params, BlurTemp* blur_temp,
const Image3F& xyb, PsychoImage& ps) {
JXL_ASSIGN_OR_RETURN(ps.lf, Image3F::Create(xyb.xsize(), xyb.ysize()));
JXL_ASSIGN_OR_RETURN(ps.mf, Image3F::Create(xyb.xsize(), xyb.ysize()));
JXL_RETURN_IF_ERROR(SeparateLFAndMF(params, xyb, &ps.lf, &ps.mf, blur_temp));
JXL_RETURN_IF_ERROR(SeparateMFAndHF(params, &ps.mf, &ps.hf[0], blur_temp));
JXL_RETURN_IF_ERROR(
SeparateHFAndUHF(params, &ps.hf[0], &ps.uhf[0], blur_temp));
return true;
}
namespace {
@ -1188,25 +1198,25 @@ void FuzzyErosion(const ImageF& from, ImageF* to) {
// Compute values of local frequency and dc masking based on the activity
// in the two images. img_diff_ac may be null.
void Mask(const ImageF& mask0, const ImageF& mask1,
const ButteraugliParams& params, BlurTemp* blur_temp,
ImageF* BUTTERAUGLI_RESTRICT mask,
ImageF* BUTTERAUGLI_RESTRICT diff_ac) {
Status Mask(const ImageF& mask0, const ImageF& mask1,
const ButteraugliParams& params, BlurTemp* blur_temp,
ImageF* BUTTERAUGLI_RESTRICT mask,
ImageF* BUTTERAUGLI_RESTRICT diff_ac) {
const size_t xsize = mask0.xsize();
const size_t ysize = mask0.ysize();
*mask = ImageF(xsize, ysize);
JXL_ASSIGN_OR_RETURN(*mask, ImageF::Create(xsize, ysize));
static const float kMul = 6.19424080439;
static const float kBias = 12.61050594197;
static const float kRadius = 2.7;
ImageF diff0(xsize, ysize);
ImageF diff1(xsize, ysize);
ImageF blurred0(xsize, ysize);
ImageF blurred1(xsize, ysize);
JXL_ASSIGN_OR_RETURN(ImageF diff0, ImageF::Create(xsize, ysize));
JXL_ASSIGN_OR_RETURN(ImageF diff1, ImageF::Create(xsize, ysize));
JXL_ASSIGN_OR_RETURN(ImageF blurred0, ImageF::Create(xsize, ysize));
JXL_ASSIGN_OR_RETURN(ImageF blurred1, ImageF::Create(xsize, ysize));
DiffPrecompute(mask0, kMul, kBias, &diff0);
DiffPrecompute(mask1, kMul, kBias, &diff1);
Blur(diff0, kRadius, params, blur_temp, &blurred0);
JXL_RETURN_IF_ERROR(Blur(diff0, kRadius, params, blur_temp, &blurred0));
FuzzyErosion(blurred0, &diff0);
Blur(diff1, kRadius, params, blur_temp, &blurred1);
JXL_RETURN_IF_ERROR(Blur(diff1, kRadius, params, blur_temp, &blurred1));
for (size_t y = 0; y < ysize; ++y) {
for (size_t x = 0; x < xsize; ++x) {
mask->Row(y)[x] = diff0.Row(y)[x];
@ -1217,19 +1227,21 @@ void Mask(const ImageF& mask0, const ImageF& mask1,
}
}
}
return true;
}
// `diff_ac` may be null.
void MaskPsychoImage(const PsychoImage& pi0, const PsychoImage& pi1,
const size_t xsize, const size_t ysize,
const ButteraugliParams& params, BlurTemp* blur_temp,
ImageF* BUTTERAUGLI_RESTRICT mask,
ImageF* BUTTERAUGLI_RESTRICT diff_ac) {
ImageF mask0(xsize, ysize);
ImageF mask1(xsize, ysize);
Status MaskPsychoImage(const PsychoImage& pi0, const PsychoImage& pi1,
const size_t xsize, const size_t ysize,
const ButteraugliParams& params, BlurTemp* blur_temp,
ImageF* BUTTERAUGLI_RESTRICT mask,
ImageF* BUTTERAUGLI_RESTRICT diff_ac) {
JXL_ASSIGN_OR_RETURN(ImageF mask0, ImageF::Create(xsize, ysize));
JXL_ASSIGN_OR_RETURN(ImageF mask1, ImageF::Create(xsize, ysize));
CombineChannelsForMasking(&pi0.hf[0], &pi0.uhf[0], &mask0);
CombineChannelsForMasking(&pi1.hf[0], &pi1.uhf[0], &mask1);
Mask(mask0, mask1, params, blur_temp, mask, diff_ac);
JXL_RETURN_IF_ERROR(Mask(mask0, mask1, params, blur_temp, mask, diff_ac));
return true;
}
double MaskY(double delta) {
@ -1430,12 +1442,15 @@ BUTTERAUGLI_INLINE void OpsinAbsorbance(const DF df, const V& in0, const V& in1,
}
// `blurred` is a temporary image used inside this function and not returned.
void OpsinDynamicsImage(const Image3F& rgb, const ButteraugliParams& params,
Image3F* blurred, BlurTemp* blur_temp, Image3F* xyb) {
Status OpsinDynamicsImage(const Image3F& rgb, const ButteraugliParams& params,
Image3F* blurred, BlurTemp* blur_temp, Image3F* xyb) {
const double kSigma = 1.2;
Blur(rgb.Plane(0), kSigma, params, blur_temp, &blurred->Plane(0));
Blur(rgb.Plane(1), kSigma, params, blur_temp, &blurred->Plane(1));
Blur(rgb.Plane(2), kSigma, params, blur_temp, &blurred->Plane(2));
JXL_RETURN_IF_ERROR(
Blur(rgb.Plane(0), kSigma, params, blur_temp, &blurred->Plane(0)));
JXL_RETURN_IF_ERROR(
Blur(rgb.Plane(1), kSigma, params, blur_temp, &blurred->Plane(1)));
JXL_RETURN_IF_ERROR(
Blur(rgb.Plane(2), kSigma, params, blur_temp, &blurred->Plane(2)));
const HWY_FULL(float) df;
const auto intensity_target_multiplier = Set(df, params.intensity_target);
for (size_t y = 0; y < rgb.ysize(); ++y) {
@ -1497,31 +1512,36 @@ void OpsinDynamicsImage(const Image3F& rgb, const ButteraugliParams& params,
Store(cur_mixed2, df, row_out_b + x);
}
}
return true;
}
void ButteraugliDiffmapInPlace(Image3F& image0, Image3F& image1,
const ButteraugliParams& params,
ImageF& diffmap) {
Status ButteraugliDiffmapInPlace(Image3F& image0, Image3F& image1,
const ButteraugliParams& params,
ImageF& diffmap) {
// image0 and image1 are in linear sRGB color space
const size_t xsize = image0.xsize();
const size_t ysize = image0.ysize();
BlurTemp blur_temp;
{
// Convert image0 and image1 to XYB in-place
Image3F temp(xsize, ysize);
OpsinDynamicsImage(image0, params, &temp, &blur_temp, &image0);
OpsinDynamicsImage(image1, params, &temp, &blur_temp, &image1);
JXL_ASSIGN_OR_RETURN(Image3F temp, Image3F::Create(xsize, ysize));
JXL_RETURN_IF_ERROR(
OpsinDynamicsImage(image0, params, &temp, &blur_temp, &image0));
JXL_RETURN_IF_ERROR(
OpsinDynamicsImage(image1, params, &temp, &blur_temp, &image1));
}
// image0 and image1 are in XYB color space
ImageF block_diff_dc(xsize, ysize);
JXL_ASSIGN_OR_RETURN(ImageF block_diff_dc, ImageF::Create(xsize, ysize));
ZeroFillImage(&block_diff_dc);
{
// separate out LF components from image0 and image1 and compute the dc
// diff image from them
Image3F lf0 = Image3F(xsize, ysize);
Image3F lf1 = Image3F(xsize, ysize);
SeparateLFAndMF(params, image0, &lf0, &image0, &blur_temp);
SeparateLFAndMF(params, image1, &lf1, &image1, &blur_temp);
JXL_ASSIGN_OR_RETURN(Image3F lf0, Image3F::Create(xsize, ysize));
JXL_ASSIGN_OR_RETURN(Image3F lf1, Image3F::Create(xsize, ysize));
JXL_RETURN_IF_ERROR(
SeparateLFAndMF(params, image0, &lf0, &image0, &blur_temp));
JXL_RETURN_IF_ERROR(
SeparateLFAndMF(params, image1, &lf1, &image1, &blur_temp));
for (size_t c = 0; c < 3; ++c) {
L2Diff(lf0.Plane(c), lf1.Plane(c), wmul[6 + c], &block_diff_dc);
}
@ -1529,15 +1549,15 @@ void ButteraugliDiffmapInPlace(Image3F& image0, Image3F& image1,
// image0 and image1 are MF residuals (before blurring) in XYB color space
ImageF hf0[2];
ImageF hf1[2];
SeparateMFAndHF(params, &image0, &hf0[0], &blur_temp);
SeparateMFAndHF(params, &image1, &hf1[0], &blur_temp);
JXL_RETURN_IF_ERROR(SeparateMFAndHF(params, &image0, &hf0[0], &blur_temp));
JXL_RETURN_IF_ERROR(SeparateMFAndHF(params, &image1, &hf1[0], &blur_temp));
// image0 and image1 are MF-images in XYB color space
ImageF block_diff_ac(xsize, ysize);
JXL_ASSIGN_OR_RETURN(ImageF block_diff_ac, ImageF::Create(xsize, ysize));
ZeroFillImage(&block_diff_ac);
// start accumulating ac diff image from MF images
{
ImageF diffs(xsize, ysize);
JXL_ASSIGN_OR_RETURN(ImageF diffs, ImageF::Create(xsize, ysize));
MaltaDiffMapLF(image0.Plane(1), image1.Plane(1), wMfMalta, wMfMalta,
norm1Mf, &diffs, &block_diff_ac);
MaltaDiffMapLF(image0.Plane(0), image1.Plane(0), wMfMaltaX, wMfMaltaX,
@ -1553,13 +1573,13 @@ void ButteraugliDiffmapInPlace(Image3F& image0, Image3F& image1,
ImageF uhf0[2];
ImageF uhf1[2];
SeparateHFAndUHF(params, &hf0[0], &uhf0[0], &blur_temp);
SeparateHFAndUHF(params, &hf1[0], &uhf1[0], &blur_temp);
JXL_RETURN_IF_ERROR(SeparateHFAndUHF(params, &hf0[0], &uhf0[0], &blur_temp));
JXL_RETURN_IF_ERROR(SeparateHFAndUHF(params, &hf1[0], &uhf1[0], &blur_temp));
// continue accumulating ac diff image from HF and UHF images
const float hf_asymmetry = params.hf_asymmetry;
{
ImageF diffs(xsize, ysize);
JXL_ASSIGN_OR_RETURN(ImageF diffs, ImageF::Create(xsize, ysize));
MaltaDiffMap(uhf0[1], uhf1[1], wUhfMalta * hf_asymmetry,
wUhfMalta / hf_asymmetry, norm1Uhf, &diffs, &block_diff_ac);
MaltaDiffMap(uhf0[0], uhf1[0], wUhfMaltaX * hf_asymmetry,
@ -1577,19 +1597,20 @@ void ButteraugliDiffmapInPlace(Image3F& image0, Image3F& image1,
}
// compute mask image from HF and UHF X and Y images
ImageF mask(xsize, ysize);
JXL_ASSIGN_OR_RETURN(ImageF mask, ImageF::Create(xsize, ysize));
{
ImageF mask0(xsize, ysize);
ImageF mask1(xsize, ysize);
JXL_ASSIGN_OR_RETURN(ImageF mask0, ImageF::Create(xsize, ysize));
JXL_ASSIGN_OR_RETURN(ImageF mask1, ImageF::Create(xsize, ysize));
CombineChannelsForMasking(&hf0[0], &uhf0[0], &mask0);
CombineChannelsForMasking(&hf1[0], &uhf1[0], &mask1);
DeallocateHFAndUHF(&hf1[0], &uhf1[0]);
DeallocateHFAndUHF(&hf0[0], &uhf0[0]);
Mask(mask0, mask1, params, &blur_temp, &mask, &block_diff_ac);
JXL_RETURN_IF_ERROR(
Mask(mask0, mask1, params, &blur_temp, &mask, &block_diff_ac));
}
// compute final diffmap from mask image and ac and dc diff images
diffmap = ImageF(xsize, ysize);
JXL_ASSIGN_OR_RETURN(diffmap, ImageF::Create(xsize, ysize));
for (size_t y = 0; y < ysize; ++y) {
const float* row_dc = block_diff_dc.Row(y);
const float* row_ac = block_diff_ac.Row(y);
@ -1599,6 +1620,7 @@ void ButteraugliDiffmapInPlace(Image3F& image0, Image3F& image1,
row_out[x] = sqrt(row_dc[x] * MaskDcY(val) + row_ac[x] * MaskY(val));
}
}
return true;
}
// NOLINTNEXTLINE(google-readability-namespace-comments)
@ -1669,10 +1691,10 @@ static inline void CheckImage(const ImageF& image, const char* name) {
// Calculate a 2x2 subsampled image for purposes of recursive butteraugli at
// multiresolution.
static Image3F SubSample2x(const Image3F& in) {
static StatusOr<Image3F> SubSample2x(const Image3F& in) {
size_t xs = (in.xsize() + 1) / 2;
size_t ys = (in.ysize() + 1) / 2;
Image3F retval(xs, ys);
JXL_ASSIGN_OR_RETURN(Image3F retval, Image3F::Create(xs, ys));
for (size_t c = 0; c < 3; ++c) {
for (size_t y = 0; y < ys; ++y) {
for (size_t x = 0; x < xs; ++x) {
@ -1724,69 +1746,86 @@ Image3F* ButteraugliComparator::Temp() const {
void ButteraugliComparator::ReleaseTemp() const { temp_in_use_.clear(); }
ButteraugliComparator::ButteraugliComparator(const Image3F& rgb0,
ButteraugliComparator::ButteraugliComparator(size_t xsize, size_t ysize,
const ButteraugliParams& params)
: xsize_(rgb0.xsize()),
ysize_(rgb0.ysize()),
params_(params),
temp_(xsize_, ysize_) {
if (xsize_ < 8 || ysize_ < 8) {
return;
: xsize_(xsize), ysize_(ysize), params_(params) {}
StatusOr<std::unique_ptr<ButteraugliComparator>> ButteraugliComparator::Make(
const Image3F& rgb0, const ButteraugliParams& params) {
size_t xsize = rgb0.xsize();
size_t ysize = rgb0.ysize();
std::unique_ptr<ButteraugliComparator> result =
std::unique_ptr<ButteraugliComparator>(
new ButteraugliComparator(xsize, ysize, params));
JXL_ASSIGN_OR_RETURN(result->temp_, Image3F::Create(xsize, ysize));
if (xsize < 8 || ysize < 8) {
return result;
}
Image3F xyb0(xsize_, ysize_);
HWY_DYNAMIC_DISPATCH(OpsinDynamicsImage)
(rgb0, params, Temp(), &blur_temp_, &xyb0);
ReleaseTemp();
HWY_DYNAMIC_DISPATCH(SeparateFrequencies)
(xsize_, ysize_, params_, &blur_temp_, xyb0, pi0_);
JXL_ASSIGN_OR_RETURN(Image3F xyb0, Image3F::Create(xsize, ysize));
JXL_RETURN_IF_ERROR(HWY_DYNAMIC_DISPATCH(OpsinDynamicsImage)(
rgb0, params, result->Temp(), &result->blur_temp_, &xyb0));
result->ReleaseTemp();
JXL_RETURN_IF_ERROR(HWY_DYNAMIC_DISPATCH(SeparateFrequencies)(
xsize, ysize, params, &result->blur_temp_, xyb0, result->pi0_));
// Awful recursive construction of samples of different resolution.
// This is an after-thought and possibly somewhat parallel in
// functionality with the PsychoImage multi-resolution approach.
sub_.reset(new ButteraugliComparator(SubSample2x(rgb0), params));
JXL_ASSIGN_OR_RETURN(Image3F subsampledRgb0, SubSample2x(rgb0));
StatusOr<std::unique_ptr<ButteraugliComparator>> sub =
ButteraugliComparator::Make(subsampledRgb0, params);
if (!sub.ok()) return sub.status();
result->sub_ = std::move(sub).value();
return result;
}
void ButteraugliComparator::Mask(ImageF* BUTTERAUGLI_RESTRICT mask) const {
HWY_DYNAMIC_DISPATCH(MaskPsychoImage)
(pi0_, pi0_, xsize_, ysize_, params_, &blur_temp_, mask, nullptr);
Status ButteraugliComparator::Mask(ImageF* BUTTERAUGLI_RESTRICT mask) const {
return HWY_DYNAMIC_DISPATCH(MaskPsychoImage)(
pi0_, pi0_, xsize_, ysize_, params_, &blur_temp_, mask, nullptr);
}
void ButteraugliComparator::Diffmap(const Image3F& rgb1, ImageF& result) const {
Status ButteraugliComparator::Diffmap(const Image3F& rgb1,
ImageF& result) const {
if (xsize_ < 8 || ysize_ < 8) {
ZeroFillImage(&result);
return;
return true;
}
Image3F xyb1(xsize_, ysize_);
HWY_DYNAMIC_DISPATCH(OpsinDynamicsImage)
(rgb1, params_, Temp(), &blur_temp_, &xyb1);
JXL_ASSIGN_OR_RETURN(Image3F xyb1, Image3F::Create(xsize_, ysize_));
JXL_RETURN_IF_ERROR(HWY_DYNAMIC_DISPATCH(OpsinDynamicsImage)(
rgb1, params_, Temp(), &blur_temp_, &xyb1));
ReleaseTemp();
DiffmapOpsinDynamicsImage(xyb1, result);
JXL_RETURN_IF_ERROR(DiffmapOpsinDynamicsImage(xyb1, result));
if (sub_) {
if (sub_->xsize_ < 8 || sub_->ysize_ < 8) {
return;
return true;
}
Image3F sub_xyb(sub_->xsize_, sub_->ysize_);
HWY_DYNAMIC_DISPATCH(OpsinDynamicsImage)
(SubSample2x(rgb1), params_, sub_->Temp(), &sub_->blur_temp_, &sub_xyb);
JXL_ASSIGN_OR_RETURN(Image3F sub_xyb,
Image3F::Create(sub_->xsize_, sub_->ysize_));
JXL_ASSIGN_OR_RETURN(Image3F subsampledRgb1, SubSample2x(rgb1));
JXL_RETURN_IF_ERROR(HWY_DYNAMIC_DISPATCH(OpsinDynamicsImage)(
subsampledRgb1, params_, sub_->Temp(), &sub_->blur_temp_, &sub_xyb));
sub_->ReleaseTemp();
ImageF subresult;
sub_->DiffmapOpsinDynamicsImage(sub_xyb, subresult);
JXL_RETURN_IF_ERROR(sub_->DiffmapOpsinDynamicsImage(sub_xyb, subresult));
AddSupersampled2x(subresult, 0.5, result);
}
return true;
}
void ButteraugliComparator::DiffmapOpsinDynamicsImage(const Image3F& xyb1,
ImageF& result) const {
Status ButteraugliComparator::DiffmapOpsinDynamicsImage(const Image3F& xyb1,
ImageF& result) const {
if (xsize_ < 8 || ysize_ < 8) {
ZeroFillImage(&result);
return;
return true;
}
PsychoImage pi1;
HWY_DYNAMIC_DISPATCH(SeparateFrequencies)
(xsize_, ysize_, params_, &blur_temp_, xyb1, pi1);
result = ImageF(xsize_, ysize_);
DiffmapPsychoImage(pi1, result);
JXL_RETURN_IF_ERROR(HWY_DYNAMIC_DISPATCH(SeparateFrequencies)(
xsize_, ysize_, params_, &blur_temp_, xyb1, pi1));
JXL_ASSIGN_OR_RETURN(result, ImageF::Create(xsize_, ysize_));
return DiffmapPsychoImage(pi1, result);
}
namespace {
@ -1809,18 +1848,18 @@ void MaltaDiffMapLF(const ImageF& lum0, const ImageF& lum1, const double w_0gt1,
} // namespace
void ButteraugliComparator::DiffmapPsychoImage(const PsychoImage& pi1,
ImageF& diffmap) const {
Status ButteraugliComparator::DiffmapPsychoImage(const PsychoImage& pi1,
ImageF& diffmap) const {
if (xsize_ < 8 || ysize_ < 8) {
ZeroFillImage(&diffmap);
return;
return true;
}
const float hf_asymmetry_ = params_.hf_asymmetry;
const float xmul_ = params_.xmul;
ImageF diffs(xsize_, ysize_);
Image3F block_diff_ac(xsize_, ysize_);
JXL_ASSIGN_OR_RETURN(ImageF diffs, ImageF::Create(xsize_, ysize_));
JXL_ASSIGN_OR_RETURN(Image3F block_diff_ac, Image3F::Create(xsize_, ysize_));
ZeroFillImage(&block_diff_ac);
MaltaDiffMap(pi0_.uhf[1], pi1.uhf[1], wUhfMalta * hf_asymmetry_,
wUhfMalta / hf_asymmetry_, norm1Uhf, &diffs, &block_diff_ac, 1);
@ -1838,7 +1877,7 @@ void ButteraugliComparator::DiffmapPsychoImage(const PsychoImage& pi1,
MaltaDiffMapLF(pi0_.mf.Plane(0), pi1.mf.Plane(0), wMfMaltaX, wMfMaltaX,
norm1MfX, &diffs, &block_diff_ac, 0);
Image3F block_diff_dc(xsize_, ysize_);
JXL_ASSIGN_OR_RETURN(Image3F block_diff_dc, Image3F::Create(xsize_, ysize_));
for (size_t c = 0; c < 3; ++c) {
if (c < 2) { // No blue channel error accumulated at HF.
HWY_DYNAMIC_DISPATCH(L2DiffAsymmetric)
@ -1852,12 +1891,13 @@ void ButteraugliComparator::DiffmapPsychoImage(const PsychoImage& pi1,
}
ImageF mask;
HWY_DYNAMIC_DISPATCH(MaskPsychoImage)
(pi0_, pi1, xsize_, ysize_, params_, &blur_temp_, &mask,
&block_diff_ac.Plane(1));
JXL_RETURN_IF_ERROR(HWY_DYNAMIC_DISPATCH(MaskPsychoImage)(
pi0_, pi1, xsize_, ysize_, params_, &blur_temp_, &mask,
&block_diff_ac.Plane(1)));
HWY_DYNAMIC_DISPATCH(CombineChannelsToDiffmap)
(mask, block_diff_dc, block_diff_ac, xmul_, &diffmap);
return true;
}
double ButteraugliScoreFromDiffmap(const ImageF& diffmap,
@ -1872,8 +1912,8 @@ double ButteraugliScoreFromDiffmap(const ImageF& diffmap,
return retval;
}
bool ButteraugliDiffmap(const Image3F& rgb0, const Image3F& rgb1,
double hf_asymmetry, double xmul, ImageF& diffmap) {
Status ButteraugliDiffmap(const Image3F& rgb0, const Image3F& rgb1,
double hf_asymmetry, double xmul, ImageF& diffmap) {
ButteraugliParams params;
params.hf_asymmetry = hf_asymmetry;
params.xmul = xmul;
@ -1893,8 +1933,8 @@ bool ButteraugliDiffmapSmall(const Image3F& rgb0, const Image3F& rgb1,
size_t yborder = ysize < kMax ? (kMax - ysize) / 2 : 0;
size_t xscaled = std::max<size_t>(kMax, xsize);
size_t yscaled = std::max<size_t>(kMax, ysize);
Image3F scaled0(xscaled, yscaled);
Image3F scaled1(xscaled, yscaled);
JXL_ASSIGN_OR_RETURN(Image3F scaled0, Image3F::Create(xscaled, yscaled));
JXL_ASSIGN_OR_RETURN(Image3F scaled1, Image3F::Create(xscaled, yscaled));
for (int i = 0; i < 3; ++i) {
for (size_t y = 0; y < yscaled; ++y) {
for (size_t x = 0; x < xscaled; ++x) {
@ -1907,7 +1947,7 @@ bool ButteraugliDiffmapSmall(const Image3F& rgb0, const Image3F& rgb1,
}
ImageF diffmap_scaled;
const bool ok = ButteraugliDiffmap(scaled0, scaled1, params, diffmap_scaled);
diffmap = ImageF(xsize, ysize);
JXL_ASSIGN_OR_RETURN(diffmap, ImageF::Create(xsize, ysize));
for (size_t y = 0; y < ysize; ++y) {
for (size_t x = 0; x < xsize; ++x) {
diffmap.Row(y)[x] = diffmap_scaled.Row(y + yborder)[x + xborder];
@ -1916,8 +1956,8 @@ bool ButteraugliDiffmapSmall(const Image3F& rgb0, const Image3F& rgb1,
return ok;
}
bool ButteraugliDiffmap(const Image3F& rgb0, const Image3F& rgb1,
const ButteraugliParams& params, ImageF& diffmap) {
Status ButteraugliDiffmap(const Image3F& rgb0, const Image3F& rgb1,
const ButteraugliParams& params, ImageF& diffmap) {
const size_t xsize = rgb0.xsize();
const size_t ysize = rgb0.ysize();
if (xsize < 1 || ysize < 1) {
@ -1930,8 +1970,9 @@ bool ButteraugliDiffmap(const Image3F& rgb0, const Image3F& rgb1,
if (xsize < kMax || ysize < kMax) {
return ButteraugliDiffmapSmall<kMax>(rgb0, rgb1, params, diffmap);
}
ButteraugliComparator butteraugli(rgb0, params);
butteraugli.Diffmap(rgb1, diffmap);
JXL_ASSIGN_OR_RETURN(std::unique_ptr<ButteraugliComparator> butteraugli,
ButteraugliComparator::Make(rgb0, params));
JXL_RETURN_IF_ERROR(butteraugli->Diffmap(rgb1, diffmap));
return true;
}
@ -1954,9 +1995,9 @@ bool ButteraugliInterface(const Image3F& rgb0, const Image3F& rgb1,
return true;
}
bool ButteraugliInterfaceInPlace(Image3F&& rgb0, Image3F&& rgb1,
const ButteraugliParams& params,
ImageF& diffmap, double& diffvalue) {
Status ButteraugliInterfaceInPlace(Image3F&& rgb0, Image3F&& rgb1,
const ButteraugliParams& params,
ImageF& diffmap, double& diffvalue) {
const size_t xsize = rgb0.xsize();
const size_t ysize = rgb0.ysize();
if (xsize < 1 || ysize < 1) {
@ -1973,12 +2014,13 @@ bool ButteraugliInterfaceInPlace(Image3F&& rgb0, Image3F&& rgb1,
}
ImageF subdiffmap;
if (xsize >= 15 && ysize >= 15) {
Image3F rgb0_sub = SubSample2x(rgb0);
Image3F rgb1_sub = SubSample2x(rgb1);
HWY_DYNAMIC_DISPATCH(ButteraugliDiffmapInPlace)
(rgb0_sub, rgb1_sub, params, subdiffmap);
JXL_ASSIGN_OR_RETURN(Image3F rgb0_sub, SubSample2x(rgb0));
JXL_ASSIGN_OR_RETURN(Image3F rgb1_sub, SubSample2x(rgb1));
JXL_RETURN_IF_ERROR(HWY_DYNAMIC_DISPATCH(ButteraugliDiffmapInPlace)(
rgb0_sub, rgb1_sub, params, subdiffmap));
}
HWY_DYNAMIC_DISPATCH(ButteraugliDiffmapInPlace)(rgb0, rgb1, params, diffmap);
JXL_RETURN_IF_ERROR(HWY_DYNAMIC_DISPATCH(ButteraugliDiffmapInPlace)(
rgb0, rgb1, params, diffmap));
if (xsize >= 15 && ysize >= 15) {
AddSupersampled2x(subdiffmap, 0.5, diffmap);
}
@ -2066,9 +2108,11 @@ void ScoreToRgb(double score, double good_threshold, double bad_threshold,
} // namespace
Image3F CreateHeatMapImage(const ImageF& distmap, double good_threshold,
double bad_threshold) {
Image3F heatmap(distmap.xsize(), distmap.ysize());
StatusOr<Image3F> CreateHeatMapImage(const ImageF& distmap,
double good_threshold,
double bad_threshold) {
JXL_ASSIGN_OR_RETURN(Image3F heatmap,
Image3F::Create(distmap.xsize(), distmap.ysize()));
for (size_t y = 0; y < distmap.ysize(); ++y) {
const float* BUTTERAUGLI_RESTRICT row_distmap = distmap.ConstRow(y);
float* BUTTERAUGLI_RESTRICT row_h0 = heatmap.PlaneRow(0, y);

Просмотреть файл

@ -14,12 +14,12 @@
#include <atomic>
#include <cmath>
#include <cstddef>
#include <memory>
#include <vector>
#include "lib/jxl/base/compiler_specific.h"
#include "lib/jxl/base/status.h"
#include "lib/jxl/image.h"
#include "lib/jxl/image_ops.h"
#define BUTTERAUGLI_ENABLE_CHECKS 0
#define BUTTERAUGLI_RESTRICT JXL_RESTRICT
@ -87,9 +87,9 @@ bool ButteraugliInterface(const Image3F &rgb0, const Image3F &rgb1,
// Same as ButteraugliInterface, but reuses rgb0 and rgb1 for other purposes
// inside the function after they are not needed any more, and it ignores
// params.xmul.
bool ButteraugliInterfaceInPlace(Image3F &&rgb0, Image3F &&rgb1,
const ButteraugliParams &params,
ImageF &diffmap, double &diffvalue);
Status ButteraugliInterfaceInPlace(Image3F &&rgb0, Image3F &&rgb1,
const ButteraugliParams &params,
ImageF &diffmap, double &diffvalue);
// Converts the butteraugli score into fuzzy class values that are continuous
// at the class boundary. The class boundary location is based on human
@ -147,11 +147,13 @@ struct PsychoImage {
// Blur needs a transposed image.
// Hold it here and only allocate on demand to reduce memory usage.
struct BlurTemp {
ImageF *GetTransposed(const ImageF &in) {
Status GetTransposed(const ImageF &in, ImageF **out) {
if (transposed_temp.xsize() == 0) {
transposed_temp = ImageF(in.ysize(), in.xsize());
JXL_ASSIGN_OR_RETURN(transposed_temp,
ImageF::Create(in.ysize(), in.xsize()));
}
return &transposed_temp;
*out = &transposed_temp;
return true;
}
ImageF transposed_temp;
@ -162,22 +164,26 @@ class ButteraugliComparator {
// Butteraugli is calibrated at xmul = 1.0. We add a multiplier here so that
// we can test the hypothesis that a higher weighing of the X channel would
// improve results at higher Butteraugli values.
ButteraugliComparator(const Image3F &rgb0, const ButteraugliParams &params);
virtual ~ButteraugliComparator() = default;
static StatusOr<std::unique_ptr<ButteraugliComparator>> Make(
const Image3F &rgb0, const ButteraugliParams &params);
// Computes the butteraugli map between the original image given in the
// constructor and the distorted image give here.
void Diffmap(const Image3F &rgb1, ImageF &result) const;
Status Diffmap(const Image3F &rgb1, ImageF &result) const;
// Same as above, but OpsinDynamicsImage() was already applied.
void DiffmapOpsinDynamicsImage(const Image3F &xyb1, ImageF &result) const;
Status DiffmapOpsinDynamicsImage(const Image3F &xyb1, ImageF &result) const;
// Same as above, but the frequency decomposition was already applied.
void DiffmapPsychoImage(const PsychoImage &pi1, ImageF &diffmap) const;
Status DiffmapPsychoImage(const PsychoImage &pi1, ImageF &diffmap) const;
void Mask(ImageF *BUTTERAUGLI_RESTRICT mask) const;
Status Mask(ImageF *BUTTERAUGLI_RESTRICT mask) const;
private:
ButteraugliComparator(size_t xsize, size_t ysize,
const ButteraugliParams &params);
Image3F *Temp() const;
void ReleaseTemp() const;
@ -196,18 +202,19 @@ class ButteraugliComparator {
};
// Deprecated.
bool ButteraugliDiffmap(const Image3F &rgb0, const Image3F &rgb1,
double hf_asymmetry, double xmul, ImageF &diffmap);
Status ButteraugliDiffmap(const Image3F &rgb0, const Image3F &rgb1,
double hf_asymmetry, double xmul, ImageF &diffmap);
bool ButteraugliDiffmap(const Image3F &rgb0, const Image3F &rgb1,
const ButteraugliParams &params, ImageF &diffmap);
Status ButteraugliDiffmap(const Image3F &rgb0, const Image3F &rgb1,
const ButteraugliParams &params, ImageF &diffmap);
double ButteraugliScoreFromDiffmap(const ImageF &diffmap,
const ButteraugliParams *params = nullptr);
// Generate rgb-representation of the distance between two images.
Image3F CreateHeatMapImage(const ImageF &distmap, double good_threshold,
double bad_threshold);
StatusOr<Image3F> CreateHeatMapImage(const ImageF &distmap,
double good_threshold,
double bad_threshold);
} // namespace jxl

Просмотреть файл

@ -30,7 +30,7 @@ using extras::PackedPixelFile;
using test::TestImage;
Image3F SinglePixelImage(float red, float green, float blue) {
Image3F img(1, 1);
JXL_ASSIGN_OR_DIE(Image3F img, Image3F::Create(1, 1));
img.PlaneRow(0, 0)[0] = red;
img.PlaneRow(1, 0)[0] = green;
img.PlaneRow(2, 0)[0] = blue;
@ -42,7 +42,7 @@ Image3F GetColorImage(const PackedPixelFile& ppf) {
const PackedImage& image = ppf.frames[0].color;
const JxlPixelFormat& format = image.format;
const uint8_t* pixels = reinterpret_cast<const uint8_t*>(image.pixels());
Image3F color(image.xsize, image.ysize);
JXL_ASSIGN_OR_DIE(Image3F color, Image3F::Create(image.xsize, image.ysize));
for (size_t c = 0; c < format.num_channels; ++c) {
JXL_CHECK(ConvertFromExternal(pixels, image.pixels_size, image.xsize,
image.ysize, ppf.info.bits_per_sample, format,
@ -93,7 +93,7 @@ TEST(ButteraugliInPlaceTest, LargeImage) {
TestImage img;
img.SetDimensions(xsize, ysize).AddFrame().RandomFill(777);
Image3F rgb0 = GetColorImage(img.ppf());
Image3F rgb1(xsize, ysize);
JXL_ASSIGN_OR_DIE(Image3F rgb1, Image3F::Create(xsize, ysize));
CopyImageTo(rgb0, &rgb1);
AddUniformNoise(&rgb1, 0.02f, 7777);
AddEdge(&rgb1, 0.1f, xsize / 2, xsize / 2);

Просмотреть файл

@ -5,17 +5,25 @@
#include "lib/jxl/chroma_from_luma.h"
#include "lib/jxl/image_ops.h"
namespace jxl {
ColorCorrelationMap::ColorCorrelationMap(size_t xsize, size_t ysize, bool XYB)
: ytox_map(DivCeil(xsize, kColorTileDim), DivCeil(ysize, kColorTileDim)),
ytob_map(DivCeil(xsize, kColorTileDim), DivCeil(ysize, kColorTileDim)) {
ZeroFillImage(&ytox_map);
ZeroFillImage(&ytob_map);
StatusOr<ColorCorrelationMap> ColorCorrelationMap::Create(size_t xsize,
size_t ysize,
bool XYB) {
ColorCorrelationMap result;
size_t xblocks = DivCeil(xsize, kColorTileDim);
size_t yblocks = DivCeil(ysize, kColorTileDim);
JXL_ASSIGN_OR_RETURN(result.ytox_map, ImageSB::Create(xblocks, yblocks));
JXL_ASSIGN_OR_RETURN(result.ytob_map, ImageSB::Create(xblocks, yblocks));
ZeroFillImage(&result.ytox_map);
ZeroFillImage(&result.ytob_map);
if (!XYB) {
base_correlation_b_ = 0;
result.base_correlation_b_ = 0;
}
RecomputeDCFactors();
result.RecomputeDCFactors();
return result;
}
} // namespace jxl

Просмотреть файл

@ -12,19 +12,15 @@
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include <limits>
#include "lib/jxl/base/compiler_specific.h"
#include "lib/jxl/base/data_parallel.h"
#include "lib/jxl/base/status.h"
#include "lib/jxl/cms/opsin_params.h"
#include "lib/jxl/dec_bit_reader.h"
#include "lib/jxl/entropy_coder.h"
#include "lib/jxl/field_encodings.h"
#include "lib/jxl/fields.h"
#include "lib/jxl/frame_dimensions.h"
#include "lib/jxl/image.h"
#include "lib/jxl/quant_weights.h"
namespace jxl {
@ -55,7 +51,8 @@ struct ColorCorrelationMap {
// xsize/ysize are in pixels
// set XYB=false to do something close to no-op cmap (needed for now since
// cmap is mandatory)
ColorCorrelationMap(size_t xsize, size_t ysize, bool XYB = true);
static StatusOr<ColorCorrelationMap> Create(size_t xsize, size_t ysize,
bool XYB = true);
float YtoXRatio(int32_t x_factor) const {
return base_correlation_x_ + x_factor * color_scale_;
@ -96,7 +93,7 @@ struct ColorCorrelationMap {
color_factor_ == kDefaultColorFactor;
}
int32_t RatioJPEG(int32_t factor) const {
static int32_t RatioJPEG(int32_t factor) {
return factor * (1 << kCFLFixedPointPrecision) / kDefaultColorFactor;
}

29
third_party/jpeg-xl/lib/jxl/cms/jxl_cms.cc поставляемый
Просмотреть файл

@ -971,14 +971,31 @@ JXL_BOOL JxlCmsSetFieldsFromICC(void* user_data, const uint8_t* icc_data,
JXL_RETURN_IF_ERROR(skcms_Parse(icc_data, icc_size, &profile));
// skcms does not return the rendering intent, so get it from the file. It
// is encoded as big-endian 32-bit integer in bytes 60..63.
uint32_t rendering_intent32 = icc_data[67];
if (rendering_intent32 > 3 || icc_data[64] != 0 || icc_data[65] != 0 ||
icc_data[66] != 0) {
return JXL_FAILURE("Invalid rendering intent %u\n", rendering_intent32);
// should be encoded as big-endian 32-bit integer in bytes 60..63.
uint32_t big_endian_rendering_intent = icc_data[67] + (icc_data[66] << 8) +
(icc_data[65] << 16) +
(icc_data[64] << 24);
// Some files encode rendering intent as little endian, which is not spec
// compliant. However we accept those with a warning.
uint32_t little_endian_rendering_intent = (icc_data[67] << 24) +
(icc_data[66] << 16) +
(icc_data[65] << 8) + icc_data[64];
uint32_t candidate_rendering_intent =
std::min(big_endian_rendering_intent, little_endian_rendering_intent);
if (candidate_rendering_intent != big_endian_rendering_intent) {
JXL_WARNING(
"Invalid rendering intent bytes: [0x%02X 0x%02X 0x%02X 0x%02X], "
"assuming %u was meant",
icc_data[64], icc_data[65], icc_data[66], icc_data[67],
candidate_rendering_intent);
}
if (candidate_rendering_intent > 3) {
return JXL_FAILURE("Invalid rendering intent %u\n",
candidate_rendering_intent);
}
// ICC and RenderingIntent have the same values (0..3).
c_enc.rendering_intent = static_cast<RenderingIntent>(rendering_intent32);
c_enc.rendering_intent =
static_cast<RenderingIntent>(candidate_rendering_intent);
if (profile.has_CICP &&
ApplyCICP(profile.CICP.color_primaries,

Просмотреть файл

@ -49,9 +49,9 @@ using ::testing::ElementsAre;
using ::testing::FloatNear;
// Small enough to be fast. If changed, must update Generate*.
static constexpr size_t kWidth = 16;
constexpr size_t kWidth = 16;
static constexpr size_t kNumThreads = 1; // only have a single row.
constexpr size_t kNumThreads = 1; // only have a single row.
MATCHER_P(HasSameFieldsAs, expected, "") {
if (arg.GetRenderingIntent() != expected.GetRenderingIntent()) {
@ -106,15 +106,15 @@ struct Globals {
Globals() {
in_gray = GenerateGray();
in_color = GenerateColor();
out_gray = ImageF(kWidth, 1);
out_color = ImageF(kWidth * 3, 1);
JXL_ASSIGN_OR_DIE(out_gray, ImageF::Create(kWidth, 1));
JXL_ASSIGN_OR_DIE(out_color, ImageF::Create(kWidth * 3, 1));
c_native = ColorEncoding::LinearSRGB(/*is_gray=*/false);
c_gray = ColorEncoding::LinearSRGB(/*is_gray=*/true);
}
static ImageF GenerateGray() {
ImageF gray(kWidth, 1);
JXL_ASSIGN_OR_DIE(ImageF gray, ImageF::Create(kWidth, 1));
float* JXL_RESTRICT row = gray.Row(0);
// Increasing left to right
for (uint32_t x = 0; x < kWidth; ++x) {
@ -124,7 +124,7 @@ struct Globals {
}
static ImageF GenerateColor() {
ImageF image(kWidth * 3, 1);
JXL_ASSIGN_OR_DIE(ImageF image, ImageF::Create(kWidth * 3, 1));
float* JXL_RESTRICT interleaved = image.Row(0);
std::fill(interleaved, interleaved + kWidth * 3, 0.0f);
@ -373,7 +373,7 @@ TEST_F(ColorManagementTest, XYBProfile) {
ImageMetadata metadata;
metadata.color_encoding = c_native;
ImageBundle ib(&metadata);
Image3F native(kNumColors, 1);
JXL_ASSIGN_OR_DIE(Image3F native, Image3F::Create(kNumColors, 1));
float mul = 1.0f / (kGridDim - 1);
for (size_t ir = 0, x = 0; ir < kGridDim; ++ir) {
for (size_t ig = 0; ig < kGridDim; ++ig) {
@ -386,10 +386,10 @@ TEST_F(ColorManagementTest, XYBProfile) {
}
ib.SetFromImage(std::move(native), c_native);
const Image3F& in = *ib.color();
Image3F opsin(kNumColors, 1);
ToXYB(ib, nullptr, &opsin, cms, nullptr);
JXL_ASSIGN_OR_DIE(Image3F opsin, Image3F::Create(kNumColors, 1));
JXL_CHECK(ToXYB(ib, nullptr, &opsin, cms, nullptr));
Image3F opsin2(kNumColors, 1);
JXL_ASSIGN_OR_DIE(Image3F opsin2, Image3F::Create(kNumColors, 1));
CopyImageTo(opsin, &opsin2);
ScaleXYB(&opsin2);
@ -403,7 +403,7 @@ TEST_F(ColorManagementTest, XYBProfile) {
float* dst = xform.BufDst(0);
ASSERT_TRUE(xform.Run(0, src, dst));
Image3F out(kNumColors, 1);
JXL_ASSIGN_OR_DIE(Image3F out, Image3F::Create(kNumColors, 1));
for (size_t i = 0; i < kNumColors; ++i) {
for (size_t c = 0; c < 3; ++c) {
out.PlaneRow(c, 0)[i] = dst[3 * i + c];

32
third_party/jpeg-xl/lib/jxl/common.h поставляемый
Просмотреть файл

@ -33,6 +33,38 @@ constexpr size_t kMaxNumPasses = 11;
// Maximum number of reference frames.
constexpr size_t kMaxNumReferenceFrames = 4;
enum class SpeedTier {
// Try multiple combinations of Glacier flags for modular mode. Otherwise
// like kGlacier.
kTectonicPlate = -1,
// Learn a global tree in Modular mode.
kGlacier = 0,
// Turns on FindBestQuantizationHQ loop. Equivalent to "guetzli" mode.
kTortoise = 1,
// Turns on FindBestQuantization butteraugli loop.
kKitten = 2,
// Turns on dots, patches, and spline detection by default, as well as full
// context clustering. Default.
kSquirrel = 3,
// Turns on error diffusion and full AC strategy heuristics. Equivalent to
// "fast" mode.
kWombat = 4,
// Turns on gaborish by default, non-default cmap, initial quant field.
kHare = 5,
// Turns on simple heuristics for AC strategy, quant field, and clustering;
// also enables coefficient reordering.
kCheetah = 6,
// Turns off most encoder features. Does context clustering.
// Modular: uses fixed tree with Weighted predictor.
kFalcon = 7,
// Currently fastest possible setting for VarDCT.
// Modular: uses fixed tree with Gradient predictor.
kThunder = 8,
// VarDCT: same as kThunder.
// Modular: no tree, Gradient predictor, fast histograms
kLightning = 9
};
} // namespace jxl
#endif // LIB_JXL_COMMON_H_

32
third_party/jpeg-xl/lib/jxl/compressed_dc.cc поставляемый
Просмотреть файл

@ -10,9 +10,6 @@
#include <string.h>
#include <algorithm>
#include <array>
#include <memory>
#include <utility>
#include <vector>
#undef HWY_TARGET_INCLUDE
@ -21,17 +18,9 @@
#include <hwy/foreach_target.h>
#include <hwy/highway.h>
#include "lib/jxl/ac_strategy.h"
#include "lib/jxl/ans_params.h"
#include "lib/jxl/base/bits.h"
#include "lib/jxl/base/compiler_specific.h"
#include "lib/jxl/base/data_parallel.h"
#include "lib/jxl/base/status.h"
#include "lib/jxl/chroma_from_luma.h"
#include "lib/jxl/dec_ans.h"
#include "lib/jxl/dec_bit_reader.h"
#include "lib/jxl/dec_cache.h"
#include "lib/jxl/entropy_coder.h"
#include "lib/jxl/image.h"
HWY_BEFORE_NAMESPACE();
namespace jxl {
@ -131,18 +120,18 @@ JXL_INLINE void ComputePixel(
Store(out, d, out_rows[2] + x);
}
void AdaptiveDCSmoothing(const float* dc_factors, Image3F* dc,
ThreadPool* pool) {
Status AdaptiveDCSmoothing(const float* dc_factors, Image3F* dc,
ThreadPool* pool) {
const size_t xsize = dc->xsize();
const size_t ysize = dc->ysize();
if (ysize <= 2 || xsize <= 2) return;
if (ysize <= 2 || xsize <= 2) return true;
// TODO(veluca): use tile-based processing?
// TODO(veluca): decide if changes to the y channel should be propagated to
// the x and b channels through color correlation.
JXL_ASSERT(w1 + w2 < 0.25f);
Image3F smoothed(xsize, ysize);
JXL_ASSIGN_OR_RETURN(Image3F smoothed, Image3F::Create(xsize, ysize));
// Fill in borders that the loop below will not. First and last are unused.
for (size_t c = 0; c < 3; c++) {
for (size_t y : {size_t(0), ysize - 1}) {
@ -197,12 +186,13 @@ void AdaptiveDCSmoothing(const float* dc_factors, Image3F* dc,
JXL_CHECK(RunOnPool(pool, 1, ysize - 1, ThreadPool::NoInit, process_row,
"DCSmoothingRow"));
dc->Swap(smoothed);
return true;
}
// DC dequantization.
void DequantDC(const Rect& r, Image3F* dc, ImageB* quant_dc, const Image& in,
const float* dc_factors, float mul, const float* cfl_factors,
YCbCrChromaSubsampling chroma_subsampling,
const YCbCrChromaSubsampling& chroma_subsampling,
const BlockCtxMap& bctx) {
const HWY_FULL(float) df;
const Rebind<pixel_type, HWY_FULL(float)> di; // assumes pixel_type <= float
@ -265,7 +255,9 @@ void DequantDC(const Rect& r, Image3F* dc, ImageB* quant_dc, const Image& in,
const int32_t* quant_row_b =
in.channel[2].plane.Row(y >> chroma_subsampling.VShift(2));
for (size_t x = 0; x < r.xsize(); x++) {
int bucket_x = 0, bucket_y = 0, bucket_b = 0;
int bucket_x = 0;
int bucket_y = 0;
int bucket_b = 0;
for (int t : bctx.dc_thresholds[0]) {
if (quant_row_x[x >> chroma_subsampling.HShift(0)] > t) bucket_x++;
}
@ -296,14 +288,14 @@ namespace jxl {
HWY_EXPORT(DequantDC);
HWY_EXPORT(AdaptiveDCSmoothing);
void AdaptiveDCSmoothing(const float* dc_factors, Image3F* dc,
ThreadPool* pool) {
Status AdaptiveDCSmoothing(const float* dc_factors, Image3F* dc,
ThreadPool* pool) {
return HWY_DYNAMIC_DISPATCH(AdaptiveDCSmoothing)(dc_factors, dc, pool);
}
void DequantDC(const Rect& r, Image3F* dc, ImageB* quant_dc, const Image& in,
const float* dc_factors, float mul, const float* cfl_factors,
YCbCrChromaSubsampling chroma_subsampling,
const YCbCrChromaSubsampling& chroma_subsampling,
const BlockCtxMap& bctx) {
return HWY_DYNAMIC_DISPATCH(DequantDC)(r, dc, quant_dc, in, dc_factors, mul,
cfl_factors, chroma_subsampling, bctx);

6
third_party/jpeg-xl/lib/jxl/compressed_dc.h поставляемый
Просмотреть файл

@ -21,12 +21,12 @@
namespace jxl {
// Smooth DC in already-smooth areas, to counteract banding.
void AdaptiveDCSmoothing(const float* dc_factors, Image3F* dc,
ThreadPool* pool);
Status AdaptiveDCSmoothing(const float* dc_factors, Image3F* dc,
ThreadPool* pool);
void DequantDC(const Rect& r, Image3F* dc, ImageB* quant_dc, const Image& in,
const float* dc_factors, float mul, const float* cfl_factors,
YCbCrChromaSubsampling chroma_subsampling,
const YCbCrChromaSubsampling& chroma_subsampling,
const BlockCtxMap& bctx);
} // namespace jxl

28
third_party/jpeg-xl/lib/jxl/convolve_test.cc поставляемый
Просмотреть файл

@ -68,11 +68,11 @@ void VerifySymmetric3(const size_t xsize, const size_t ysize, ThreadPool* pool,
Rng* rng) {
const Rect rect(0, 0, xsize, ysize);
ImageF in(xsize, ysize);
JXL_ASSIGN_OR_DIE(ImageF in, ImageF::Create(xsize, ysize));
GenerateImage(*rng, &in, 0.0f, 1.0f);
ImageF out_expected(xsize, ysize);
ImageF out_actual(xsize, ysize);
JXL_ASSIGN_OR_DIE(ImageF out_expected, ImageF::Create(xsize, ysize));
JXL_ASSIGN_OR_DIE(ImageF out_actual, ImageF::Create(xsize, ysize));
const WeightsSymmetric3& weights = WeightsSymmetric3Lowpass();
Symmetric3(in, rect, weights, pool, &out_expected);
@ -96,7 +96,7 @@ std::vector<Rect> GenerateTestRectangles(size_t xsize, size_t ysize) {
// Ensures Symmetric and Separable give the same result.
void VerifySymmetric5(const size_t xsize, const size_t ysize, ThreadPool* pool,
Rng* rng) {
ImageF in(xsize, ysize);
JXL_ASSIGN_OR_DIE(ImageF in, ImageF::Create(xsize, ysize));
GenerateImage(*rng, &in, 0.0f, 1.0f);
for (const Rect& in_rect : GenerateTestRectangles(xsize, ysize)) {
@ -105,8 +105,8 @@ void VerifySymmetric5(const size_t xsize, const size_t ysize, ThreadPool* pool,
in_rect.xsize(), in_rect.ysize(), in_rect.x0(), in_rect.y0());
{
Rect out_rect = in_rect;
ImageF out_expected(xsize, ysize);
ImageF out_actual(xsize, ysize);
JXL_ASSIGN_OR_DIE(ImageF out_expected, ImageF::Create(xsize, ysize));
JXL_ASSIGN_OR_DIE(ImageF out_actual, ImageF::Create(xsize, ysize));
FillImage(-1.0f, &out_expected);
FillImage(-1.0f, &out_actual);
@ -120,8 +120,10 @@ void VerifySymmetric5(const size_t xsize, const size_t ysize, ThreadPool* pool,
}
{
Rect out_rect(0, 0, in_rect.xsize(), in_rect.ysize());
ImageF out_expected(out_rect.xsize(), out_rect.ysize());
ImageF out_actual(out_rect.xsize(), out_rect.ysize());
JXL_ASSIGN_OR_DIE(ImageF out_expected,
ImageF::Create(out_rect.xsize(), out_rect.ysize()));
JXL_ASSIGN_OR_DIE(ImageF out_actual,
ImageF::Create(out_rect.xsize(), out_rect.ysize()));
SlowSeparable5(in, in_rect, WeightsSeparable5Lowpass(), pool,
&out_expected, out_rect);
@ -138,11 +140,11 @@ void VerifySeparable5(const size_t xsize, const size_t ysize, ThreadPool* pool,
Rng* rng) {
const Rect rect(0, 0, xsize, ysize);
ImageF in(xsize, ysize);
JXL_ASSIGN_OR_DIE(ImageF in, ImageF::Create(xsize, ysize));
GenerateImage(*rng, &in, 0.0f, 1.0f);
ImageF out_expected(xsize, ysize);
ImageF out_actual(xsize, ysize);
JXL_ASSIGN_OR_DIE(ImageF out_expected, ImageF::Create(xsize, ysize));
JXL_ASSIGN_OR_DIE(ImageF out_actual, ImageF::Create(xsize, ysize));
const WeightsSeparable5& weights = WeightsSeparable5Lowpass();
SlowSeparable5(in, rect, weights, pool, &out_expected, rect);
@ -197,10 +199,10 @@ void BenchmarkConv(const char* caption, const Conv& conv,
hwy::Result results[kNumInputs];
const size_t kDim = 160; // in+out fit in L2
ImageF in(kDim, kDim);
JXL_ASSIGN_OR_DIE(ImageF in, ImageF::Create(kDim, kDim));
ZeroFillImage(&in);
in.Row(kDim / 2)[kDim / 2] = unpredictable1;
ImageF out(kDim, kDim);
JXL_ASSIGN_OR_DIE(ImageF out, ImageF::Create(kDim, kDim));
hwy::Params p;
p.verbose = false;

13
third_party/jpeg-xl/lib/jxl/dct_util.h поставляемый
Просмотреть файл

@ -8,8 +8,9 @@
#include <stddef.h>
#include "lib/jxl/base/compiler_specific.h"
#include "lib/jxl/base/data_parallel.h"
#include <memory>
#include "lib/jxl/base/common.h"
#include "lib/jxl/base/status.h"
#include "lib/jxl/image.h"
#include "lib/jxl/image_ops.h"
@ -50,12 +51,16 @@ template <typename T>
class ACImageT final : public ACImage {
public:
ACImageT() = default;
ACImageT(size_t xsize, size_t ysize) {
static StatusOr<std::unique_ptr<ACImageT>> Make(size_t xsize, size_t ysize) {
static_assert(
std::is_same<T, int16_t>::value || std::is_same<T, int32_t>::value,
"ACImage must be either 32- or 16- bit");
img_ = Image3<T>(xsize, ysize);
std::unique_ptr<ACImageT> result = jxl::make_unique<ACImageT>();
JXL_ASSIGN_OR_RETURN(result->img_, Image3<T>::Create(xsize, ysize));
return result;
}
ACType Type() const override {
return sizeof(T) == 2 ? ACType::k16 : ACType::k32;
}

4
third_party/jpeg-xl/lib/jxl/dec_cache.cc поставляемый
Просмотреть файл

@ -5,6 +5,7 @@
#include "lib/jxl/dec_cache.h"
#include "lib/jxl/base/status.h"
#include "lib/jxl/blending.h"
#include "lib/jxl/common.h" // JXL_HIGH_PRECISION
#include "lib/jxl/render_pipeline/stage_blending.h"
@ -257,7 +258,8 @@ Status PassesDecoderState::PreparePipeline(const FrameHeader& frame_header,
decoded, output_encoding_info.color_encoding));
}
}
render_pipeline = std::move(builder).Finalize(shared->frame_dim);
JXL_ASSIGN_OR_RETURN(render_pipeline,
std::move(builder).Finalize(shared->frame_dim));
return render_pipeline->IsInitialized();
}

27
third_party/jpeg-xl/lib/jxl/dec_cache.h поставляемый
Просмотреть файл

@ -52,7 +52,8 @@ struct PixelCallback {
const bool has_init = init != nullptr;
const bool has_run = run != nullptr;
const bool has_destroy = destroy != nullptr;
JXL_ASSERT(has_init == has_run && has_run == has_destroy);
const bool healthy = (has_init == has_run) && (has_run == has_destroy);
JXL_ASSERT(healthy);
#endif
}
@ -128,7 +129,7 @@ struct PassesDecoderState {
std::atomic<uint32_t> used_acs{0};
// Storage for coefficients if in "accumulate" mode.
std::unique_ptr<ACImage> coefficients = make_unique<ACImageT<int32_t>>(0, 0);
std::unique_ptr<ACImage> coefficients = make_unique<ACImageT<int32_t>>();
// Rendering pipeline.
std::unique_ptr<RenderPipeline> render_pipeline;
@ -166,8 +167,10 @@ struct PassesDecoderState {
upsampler8x = GetUpsamplingStage(shared->metadata->transform_data, 0, 3);
if (frame_header.loop_filter.epf_iters > 0) {
sigma = ImageF(shared->frame_dim.xsize_blocks + 2 * kSigmaPadding,
shared->frame_dim.ysize_blocks + 2 * kSigmaPadding);
JXL_ASSIGN_OR_RETURN(
sigma,
ImageF::Create(shared->frame_dim.xsize_blocks + 2 * kSigmaPadding,
shared->frame_dim.ysize_blocks + 2 * kSigmaPadding));
}
return true;
}
@ -193,14 +196,16 @@ struct PassesDecoderState {
// Temp images required for decoding a single group. Reduces memory allocations
// for large images because we only initialize min(#threads, #groups) instances.
struct GroupDecCache {
void InitOnce(size_t num_passes, size_t used_acs) {
Status InitOnce(size_t num_passes, size_t used_acs) {
for (size_t i = 0; i < num_passes; i++) {
if (num_nzeroes[i].xsize() == 0) {
// Allocate enough for a whole group - partial groups on the
// right/bottom border just use a subset. The valid size is passed via
// Rect.
num_nzeroes[i] = Image3I(kGroupDimInBlocks, kGroupDimInBlocks);
JXL_ASSIGN_OR_RETURN(
num_nzeroes[i],
Image3I::Create(kGroupDimInBlocks, kGroupDimInBlocks));
}
}
size_t max_block_area = 0;
@ -227,13 +232,17 @@ struct GroupDecCache {
scratch_space = dec_group_block + max_block_area_ * 3;
dec_group_qblock = int32_memory_.get();
dec_group_qblock16 = int16_memory_.get();
return true;
}
void InitDCBufferOnce() {
Status InitDCBufferOnce() {
if (dc_buffer.xsize() == 0) {
dc_buffer = ImageF(kGroupDimInBlocks + kRenderPipelineXOffset * 2,
kGroupDimInBlocks + 4);
JXL_ASSIGN_OR_RETURN(
dc_buffer,
ImageF::Create(kGroupDimInBlocks + kRenderPipelineXOffset * 2,
kGroupDimInBlocks + 4));
}
return true;
}
// Scratch space used by DecGroupImpl().

Просмотреть файл

@ -9,11 +9,11 @@
#include <string.h>
#include <algorithm>
#include <array>
#include <functional>
#include <utility>
#include <vector>
#include "lib/jxl/base/status.h"
#undef HWY_TARGET_INCLUDE
#define HWY_TARGET_INCLUDE "lib/jxl/dec_external_image.cc"
#include <hwy/foreach_target.h>
@ -113,7 +113,7 @@ Status UndoOrientation(jxl::Orientation undo_orientation, const Plane<T>& image,
const size_t ysize = image.ysize();
if (undo_orientation == Orientation::kFlipHorizontal) {
out = Plane<T>(xsize, ysize);
JXL_ASSIGN_OR_RETURN(out, Plane<T>::Create(xsize, ysize));
JXL_RETURN_IF_ERROR(RunOnPool(
pool, 0, static_cast<uint32_t>(ysize), ThreadPool::NoInit,
[&](const uint32_t task, size_t /*thread*/) {
@ -126,7 +126,7 @@ Status UndoOrientation(jxl::Orientation undo_orientation, const Plane<T>& image,
},
"UndoOrientation"));
} else if (undo_orientation == Orientation::kRotate180) {
out = Plane<T>(xsize, ysize);
JXL_ASSIGN_OR_RETURN(out, Plane<T>::Create(xsize, ysize));
JXL_RETURN_IF_ERROR(RunOnPool(
pool, 0, static_cast<uint32_t>(ysize), ThreadPool::NoInit,
[&](const uint32_t task, size_t /*thread*/) {
@ -139,7 +139,7 @@ Status UndoOrientation(jxl::Orientation undo_orientation, const Plane<T>& image,
},
"UndoOrientation"));
} else if (undo_orientation == Orientation::kFlipVertical) {
out = Plane<T>(xsize, ysize);
JXL_ASSIGN_OR_RETURN(out, Plane<T>::Create(xsize, ysize));
JXL_RETURN_IF_ERROR(RunOnPool(
pool, 0, static_cast<uint32_t>(ysize), ThreadPool::NoInit,
[&](const uint32_t task, size_t /*thread*/) {
@ -152,7 +152,7 @@ Status UndoOrientation(jxl::Orientation undo_orientation, const Plane<T>& image,
},
"UndoOrientation"));
} else if (undo_orientation == Orientation::kTranspose) {
out = Plane<T>(ysize, xsize);
JXL_ASSIGN_OR_RETURN(out, Plane<T>::Create(ysize, xsize));
JXL_RETURN_IF_ERROR(RunOnPool(
pool, 0, static_cast<uint32_t>(ysize), ThreadPool::NoInit,
[&](const uint32_t task, size_t /*thread*/) {
@ -164,7 +164,7 @@ Status UndoOrientation(jxl::Orientation undo_orientation, const Plane<T>& image,
},
"UndoOrientation"));
} else if (undo_orientation == Orientation::kRotate90) {
out = Plane<T>(ysize, xsize);
JXL_ASSIGN_OR_RETURN(out, Plane<T>::Create(ysize, xsize));
JXL_RETURN_IF_ERROR(RunOnPool(
pool, 0, static_cast<uint32_t>(ysize), ThreadPool::NoInit,
[&](const uint32_t task, size_t /*thread*/) {
@ -176,7 +176,7 @@ Status UndoOrientation(jxl::Orientation undo_orientation, const Plane<T>& image,
},
"UndoOrientation"));
} else if (undo_orientation == Orientation::kAntiTranspose) {
out = Plane<T>(ysize, xsize);
JXL_ASSIGN_OR_RETURN(out, Plane<T>::Create(ysize, xsize));
JXL_RETURN_IF_ERROR(RunOnPool(
pool, 0, static_cast<uint32_t>(ysize), ThreadPool::NoInit,
[&](const uint32_t task, size_t /*thread*/) {
@ -188,7 +188,7 @@ Status UndoOrientation(jxl::Orientation undo_orientation, const Plane<T>& image,
},
"UndoOrientation"));
} else if (undo_orientation == Orientation::kRotate270) {
out = Plane<T>(ysize, xsize);
JXL_ASSIGN_OR_RETURN(out, Plane<T>::Create(ysize, xsize));
JXL_RETURN_IF_ERROR(RunOnPool(
pool, 0, static_cast<uint32_t>(ysize), ThreadPool::NoInit,
[&](const uint32_t task, size_t /*thread*/) {
@ -309,7 +309,7 @@ Status ConvertChannelsToExternal(const ImageF* in_channels[],
ImageF ones;
for (size_t c = 0; c < num_channels; ++c) {
if (!channels[c]) {
ones = ImageF(xsize, 1);
JXL_ASSIGN_OR_RETURN(ones, ImageF::Create(xsize, 1));
FillImage(1.0f, &ones);
break;
}
@ -322,9 +322,12 @@ Status ConvertChannelsToExternal(const ImageF* in_channels[],
JXL_RETURN_IF_ERROR(RunOnPool(
pool, 0, static_cast<uint32_t>(ysize),
[&](size_t num_threads) {
f16_cache =
Plane<hwy::float16_t>(xsize, num_channels * num_threads);
return InitOutCallback(num_threads);
StatusOr<Plane<hwy::float16_t>> f16_cache_or =
Plane<hwy::float16_t>::Create(xsize,
num_channels * num_threads);
if (!f16_cache_or.ok()) return false;
f16_cache = std::move(f16_cache_or).value();
return !!InitOutCallback(num_threads);
},
[&](const uint32_t task, const size_t thread) {
const int64_t y = task;
@ -398,8 +401,11 @@ Status ConvertChannelsToExternal(const ImageF* in_channels[],
JXL_RETURN_IF_ERROR(RunOnPool(
pool, 0, static_cast<uint32_t>(ysize),
[&](size_t num_threads) {
u32_cache = Plane<uint32_t>(xsize, num_channels * num_threads);
return InitOutCallback(num_threads);
StatusOr<Plane<uint32_t>> u32_cache_or =
Plane<uint32_t>::Create(xsize, num_channels * num_threads);
if (!u32_cache_or.ok()) return false;
u32_cache = std::move(u32_cache_or).value();
return !!InitOutCallback(num_threads);
},
[&](const uint32_t task, const size_t thread) {
const int64_t y = task;
@ -453,7 +459,8 @@ Status ConvertToExternal(const jxl::ImageBundle& ib, size_t bits_per_sample,
// Undo premultiplied alpha.
Image3F unpremul;
if (ib.AlphaIsPremultiplied() && ib.HasAlpha() && unpremul_alpha) {
unpremul = Image3F(color->xsize(), color->ysize());
JXL_ASSIGN_OR_RETURN(unpremul,
Image3F::Create(color->xsize(), color->ysize()));
CopyImageTo(*color, &unpremul);
for (size_t y = 0; y < unpremul.ysize(); y++) {
UnpremultiplyAlpha(unpremul.PlaneRow(0, y), unpremul.PlaneRow(1, y),

Просмотреть файл

@ -20,10 +20,10 @@ void BM_DecExternalImage_ConvertImageRGBA(benchmark::State& state) {
ImageMetadata im;
im.SetAlphaBits(8);
ImageBundle ib(&im);
Image3F color(xsize, ysize);
JXL_ASSIGN_OR_DIE(Image3F color, Image3F::Create(xsize, ysize));
ZeroFillImage(&color);
ib.SetFromImage(std::move(color), ColorEncoding::SRGB());
ImageF alpha(xsize, ysize);
JXL_ASSIGN_OR_DIE(ImageF alpha, ImageF::Create(xsize, ysize));
ZeroFillImage(&alpha);
ib.SetAlpha(std::move(alpha));

50
third_party/jpeg-xl/lib/jxl/dec_frame.cc поставляемый
Просмотреть файл

@ -335,17 +335,19 @@ Status FrameDecoder::ProcessDCGroup(size_t dc_group_id, BitReader* br) {
return true;
}
void FrameDecoder::FinalizeDC() {
Status FrameDecoder::FinalizeDC() {
// Do Adaptive DC smoothing if enabled. This *must* happen between all the
// ProcessDCGroup and ProcessACGroup.
if (frame_header_.encoding == FrameEncoding::kVarDCT &&
!(frame_header_.flags & FrameHeader::kSkipAdaptiveDCSmoothing) &&
!(frame_header_.flags & FrameHeader::kUseDcFrame)) {
AdaptiveDCSmoothing(dec_state_->shared->quantizer.MulDC(),
&dec_state_->shared_storage.dc_storage, pool_);
JXL_RETURN_IF_ERROR(
AdaptiveDCSmoothing(dec_state_->shared->quantizer.MulDC(),
&dec_state_->shared_storage.dc_storage, pool_));
}
finalized_dc_ = true;
return true;
}
Status FrameDecoder::AllocateOutput() {
@ -410,9 +412,11 @@ Status FrameDecoder::ProcessACGlobal(BitReader* br) {
size_t xs = store ? kGroupDim * kGroupDim : 0;
size_t ys = store ? frame_dim_.num_groups : 0;
if (use_16_bit) {
dec_state_->coefficients = make_unique<ACImageT<int16_t>>(xs, ys);
JXL_ASSIGN_OR_RETURN(dec_state_->coefficients,
ACImageT<int16_t>::Make(xs, ys));
} else {
dec_state_->coefficients = make_unique<ACImageT<int32_t>>(xs, ys);
JXL_ASSIGN_OR_RETURN(dec_state_->coefficients,
ACImageT<int32_t>::Make(xs, ys));
}
if (store) {
dec_state_->coefficients->ZeroFill();
@ -482,8 +486,8 @@ Status FrameDecoder::ProcessACGroup(size_t ac_group_id,
bool should_run_pipeline = true;
if (frame_header_.encoding == FrameEncoding::kVarDCT) {
group_dec_caches_[thread].InitOnce(frame_header_.passes.num_passes,
dec_state_->used_acs);
JXL_RETURN_IF_ERROR(group_dec_caches_[thread].InitOnce(
frame_header_.passes.num_passes, dec_state_->used_acs));
JXL_RETURN_IF_ERROR(DecodeGroup(frame_header_, br, num_passes, ac_group_id,
dec_state_, &group_dec_caches_[thread],
thread, render_pipeline_input, decoded_,
@ -498,9 +502,12 @@ Status FrameDecoder::ProcessACGroup(size_t ac_group_id,
size_t pass1 =
force_draw ? frame_header_.passes.num_passes : pass0 + num_passes;
for (size_t i = pass0; i < pass1; ++i) {
int minShift, maxShift;
int minShift;
int maxShift;
frame_header_.passes.GetDownsamplingBracket(i, minShift, maxShift);
bool modular_pass_ready = true;
JXL_DEBUG_V(2, "Decoding modular in group %d pass %d", (int)ac_group_id,
(int)i);
if (i < pass0 + num_passes) {
JXL_RETURN_IF_ERROR(modular_frame_decoder_.DecodeGroup(
frame_header_, mrect, br[i - pass0], minShift, maxShift,
@ -546,7 +553,7 @@ Status FrameDecoder::ProcessACGroup(size_t ac_group_id,
if (!modular_frame_decoder_.UsesFullImage() && !decoded_->IsJPEG()) {
if (should_run_pipeline && modular_ready) {
render_pipeline_input.Done();
JXL_RETURN_IF_ERROR(render_pipeline_input.Done());
} else if (force_draw) {
return JXL_FAILURE("Modular group decoding failed.");
}
@ -555,7 +562,7 @@ Status FrameDecoder::ProcessACGroup(size_t ac_group_id,
}
void FrameDecoder::MarkSections(const SectionInfo* sections, size_t num,
SectionStatus* section_status) {
const SectionStatus* section_status) {
num_sections_done_ += num;
for (size_t i = 0; i < num; i++) {
if (section_status[i] != SectionStatus::kDone) {
@ -645,9 +652,11 @@ Status FrameDecoder::ProcessSections(const SectionInfo* sections, size_t num,
pool_, 0, dc_group_sec.size(), ThreadPool::NoInit,
[this, &dc_group_sec, &num, &sections, &section_status, &has_error](
size_t i, size_t thread) {
if (has_error) return;
if (dc_group_sec[i] != num) {
if (!ProcessDCGroup(i, sections[dc_group_sec[i]].br)) {
has_error = true;
return;
} else {
section_status[dc_group_sec[i]] = SectionStatus::kDone;
}
@ -666,7 +675,7 @@ Status FrameDecoder::ProcessSections(const SectionInfo* sections, size_t num,
pipeline_options.render_noise = true;
JXL_RETURN_IF_ERROR(
dec_state_->PreparePipeline(frame_header_, decoded_, pipeline_options));
FinalizeDC();
JXL_RETURN_IF_ERROR(FinalizeDC());
JXL_RETURN_IF_ERROR(AllocateOutput());
if (progressive_detail_ >= JxlProgressiveDetail::kDC) {
MarkSections(sections, num, section_status);
@ -776,21 +785,22 @@ Status FrameDecoder::Flush() {
decoded_passes_per_ac_group_.size());
},
[this, &has_error](const uint32_t g, size_t thread) {
if (has_error) return;
if (decoded_passes_per_ac_group_[g] ==
frame_header_.passes.num_passes) {
// This group was drawn already, nothing to do.
return;
}
BitReader* JXL_RESTRICT readers[kMaxNumPasses] = {};
bool ok = ProcessACGroup(
g, readers, /*num_passes=*/0, GetStorageLocation(thread, g),
/*force_draw=*/true, /*dc_only=*/!decoded_ac_global_);
if (!ok) has_error = true;
if (!ProcessACGroup(
g, readers, /*num_passes=*/0, GetStorageLocation(thread, g),
/*force_draw=*/true, /*dc_only=*/!decoded_ac_global_)) {
has_error = true;
return;
}
},
"ForceDrawGroup"));
if (has_error) {
return JXL_FAILURE("Drawing groups failed");
}
if (has_error) return JXL_FAILURE("Drawing groups failed");
}
// undo global modular transforms and copy int pixel buffers to float ones
@ -815,10 +825,10 @@ int FrameDecoder::SavedAs(const FrameHeader& header) {
bool FrameDecoder::HasEverything() const {
if (!decoded_dc_global_) return false;
if (!decoded_ac_global_) return false;
for (auto& have_dc_group : decoded_dc_groups_) {
for (const auto& have_dc_group : decoded_dc_groups_) {
if (!have_dc_group) return false;
}
for (auto& nb_passes : decoded_passes_per_ac_group_) {
for (const auto& nb_passes : decoded_passes_per_ac_group_) {
if (nb_passes < frame_header_.passes.num_passes) return false;
}
return true;

6
third_party/jpeg-xl/lib/jxl/dec_frame.h поставляемый
Просмотреть файл

@ -242,14 +242,14 @@ class FrameDecoder {
private:
Status ProcessDCGlobal(BitReader* br);
Status ProcessDCGroup(size_t dc_group_id, BitReader* br);
void FinalizeDC();
Status FinalizeDC();
Status AllocateOutput();
Status ProcessACGlobal(BitReader* br);
Status ProcessACGroup(size_t ac_group_id, BitReader* JXL_RESTRICT* br,
size_t num_passes, size_t thread, bool force_draw,
bool dc_only);
void MarkSections(const SectionInfo* sections, size_t num,
SectionStatus* section_status);
const SectionStatus* section_status);
// Allocates storage for parallel decoding using up to `num_threads` threads
// of up to `num_tasks` tasks. The value of `thread` passed to
@ -272,7 +272,7 @@ class FrameDecoder {
return true;
}
size_t GetStorageLocation(size_t thread, size_t task) {
size_t GetStorageLocation(size_t thread, size_t task) const {
if (use_task_id_) return task;
return thread;
}

37
third_party/jpeg-xl/lib/jxl/dec_group.cc поставляемый
Просмотреть файл

@ -27,13 +27,10 @@
#include "lib/jxl/base/status.h"
#include "lib/jxl/coeff_order.h"
#include "lib/jxl/common.h" // kMaxNumPasses
#include "lib/jxl/convolve.h"
#include "lib/jxl/dct_scales.h"
#include "lib/jxl/dec_cache.h"
#include "lib/jxl/dec_transforms-inl.h"
#include "lib/jxl/dec_xyb.h"
#include "lib/jxl/entropy_coder.h"
#include "lib/jxl/epf.h"
#include "lib/jxl/quant_weights.h"
#include "lib/jxl/quantizer-inl.h"
#include "lib/jxl/quantizer.h"
@ -70,6 +67,11 @@ namespace jxl {
namespace HWY_NAMESPACE {
// These templates are not found via ADL.
using hwy::HWY_NAMESPACE::AllFalse;
using hwy::HWY_NAMESPACE::Gt;
using hwy::HWY_NAMESPACE::Le;
using hwy::HWY_NAMESPACE::MaskFromVec;
using hwy::HWY_NAMESPACE::Or;
using hwy::HWY_NAMESPACE::Rebind;
using hwy::HWY_NAMESPACE::ShiftRight;
@ -77,9 +79,11 @@ using D = HWY_FULL(float);
using DU = HWY_FULL(uint32_t);
using DI = HWY_FULL(int32_t);
using DI16 = Rebind<int16_t, DI>;
using DI16_FULL = HWY_CAPPED(int16_t, kDCTBlockSize);
constexpr D d;
constexpr DI di;
constexpr DI16 di16;
constexpr DI16_FULL di16_full;
// TODO(veluca): consider SIMDfying.
void Transpose8x8InPlace(int32_t* JXL_RESTRICT block) {
@ -181,6 +185,9 @@ Status DecodeGroupImpl(const FrameHeader& frame_header,
const YCbCrChromaSubsampling& cs = frame_header.chroma_subsampling;
const auto kJpegDctMin = Set(di16_full, -4095);
const auto kJpegDctMax = Set(di16_full, 4095);
size_t idct_stride[3];
for (size_t c = 0; c < 3; c++) {
idct_stride[c] = render_pipeline_input.GetBuffer(c).first->PixelsPerRow();
@ -355,7 +362,7 @@ Status DecodeGroupImpl(const FrameHeader& frame_header,
int16_t* JXL_RESTRICT jpeg_pos =
jpeg_row[c] + sbx[c] * kDCTBlockSize;
// JPEG XL is transposed, JPEG is not.
auto transposed_dct = qblock[c].ptr32;
auto* transposed_dct = qblock[c].ptr32;
Transpose8x8InPlace(transposed_dct);
// No CfL - no need to store the y block converted to integers.
if (!cs.Is444() ||
@ -391,6 +398,16 @@ Status DecodeGroupImpl(const FrameHeader& frame_header,
}
jpeg_pos[0] =
Clamp1<float>(dc_rows[c][sbx[c]] - dcoff[c], -2047, 2047);
auto overflow = MaskFromVec(Set(di16_full, 0));
auto underflow = MaskFromVec(Set(di16_full, 0));
for (int i = 0; i < 64; i += Lanes(di16_full)) {
auto in = LoadU(di16_full, jpeg_pos + i);
overflow = Or(overflow, Gt(in, kJpegDctMax));
underflow = Or(underflow, Lt(in, kJpegDctMin));
}
if (!AllFalse(di16_full, Or(overflow, underflow))) {
return JXL_FAILURE("JPEG DCT coefficients out of range");
}
}
} else {
HWY_ALIGN float* const block = group_dec_cache->dec_group_block;
@ -683,7 +700,7 @@ Status DecodeGroup(const FrameHeader& frame_header,
}
if (draw == kDraw && num_passes == 0 && first_pass == 0) {
group_dec_cache->InitDCBufferOnce();
JXL_RETURN_IF_ERROR(group_dec_cache->InitDCBufferOnce());
const YCbCrChromaSubsampling& cs = frame_header.chroma_subsampling;
for (size_t c : {0, 1, 2}) {
size_t hs = cs.HShift(c);
@ -736,9 +753,9 @@ Status DecodeGroup(const FrameHeader& frame_header,
kRenderPipelineXOffset;
}
// Arguments set to 0/nullptr are not used.
dec_state->upsampler8x->ProcessRow(input_rows, output_rows,
/*xextra=*/0, src_rect.xsize(), 0, 0,
thread);
JXL_RETURN_IF_ERROR(dec_state->upsampler8x->ProcessRow(
input_rows, output_rows,
/*xextra=*/0, src_rect.xsize(), 0, 0, thread));
}
}
return true;
@ -780,9 +797,9 @@ Status DecodeGroupForRoundtrip(const FrameHeader& frame_header,
ImageBundle* JXL_RESTRICT decoded,
AuxOut* aux_out) {
GetBlockFromEncoder get_block(ac, group_idx, frame_header.passes.shift);
group_dec_cache->InitOnce(
JXL_RETURN_IF_ERROR(group_dec_cache->InitOnce(
/*num_passes=*/0,
/*used_acs=*/(1u << AcStrategy::kNumValidStrategies) - 1);
/*used_acs=*/(1u << AcStrategy::kNumValidStrategies) - 1));
return HWY_DYNAMIC_DISPATCH(DecodeGroupImpl)(
frame_header, &get_block, group_dec_cache, dec_state, thread, group_idx,

60
third_party/jpeg-xl/lib/jxl/dec_modular.cc поставляемый
Просмотреть файл

@ -8,7 +8,6 @@
#include <stdint.h>
#include <atomic>
#include <sstream>
#include <vector>
#include "lib/jxl/frame_header.h"
@ -18,10 +17,8 @@
#include <hwy/foreach_target.h>
#include <hwy/highway.h>
#include "lib/jxl/alpha.h"
#include "lib/jxl/base/compiler_specific.h"
#include "lib/jxl/base/printf_macros.h"
#include "lib/jxl/base/span.h"
#include "lib/jxl/base/status.h"
#include "lib/jxl/compressed_dc.h"
#include "lib/jxl/epf.h"
@ -216,8 +213,10 @@ Status ModularFrameDecoder::DecodeGlobalInfo(BitReader* reader,
}
}
Image gi(frame_dim.xsize, frame_dim.ysize, metadata.bit_depth.bits_per_sample,
nb_chans + nb_extra);
JXL_ASSIGN_OR_RETURN(
Image gi,
Image::Create(frame_dim.xsize, frame_dim.ysize,
metadata.bit_depth.bits_per_sample, nb_chans + nb_extra));
all_same_shift = true;
if (frame_header.color_transform == ColorTransform::kYCbCr) {
@ -228,7 +227,7 @@ Status ModularFrameDecoder::DecodeGlobalInfo(BitReader* reader,
DivCeil(frame_dim.xsize, 1 << gi.channel[c].hshift);
size_t ysize_shifted =
DivCeil(frame_dim.ysize, 1 << gi.channel[c].vshift);
gi.channel[c].shrink(xsize_shifted, ysize_shifted);
JXL_RETURN_IF_ERROR(gi.channel[c].shrink(xsize_shifted, ysize_shifted));
if (gi.channel[c].hshift != gi.channel[0].hshift ||
gi.channel[c].vshift != gi.channel[0].vshift)
all_same_shift = false;
@ -237,8 +236,9 @@ Status ModularFrameDecoder::DecodeGlobalInfo(BitReader* reader,
for (size_t ec = 0, c = nb_chans; ec < nb_extra; ec++, c++) {
size_t ecups = frame_header.extra_channel_upsampling[ec];
gi.channel[c].shrink(DivCeil(frame_dim.xsize_upsampled, ecups),
DivCeil(frame_dim.ysize_upsampled, ecups));
JXL_RETURN_IF_ERROR(
gi.channel[c].shrink(DivCeil(frame_dim.xsize_upsampled, ecups),
DivCeil(frame_dim.ysize_upsampled, ecups)));
gi.channel[c].hshift = gi.channel[c].vshift =
CeilLog2Nonzero(ecups) - CeilLog2Nonzero(frame_header.upsampling);
if (gi.channel[c].hshift != gi.channel[0].hshift ||
@ -306,7 +306,8 @@ Status ModularFrameDecoder::DecodeGroup(
stream.kind == ModularStreamId::kModularAC);
const size_t xsize = rect.xsize();
const size_t ysize = rect.ysize();
Image gi(xsize, ysize, full_image.bitdepth, 0);
JXL_ASSIGN_OR_RETURN(Image gi,
Image::Create(xsize, ysize, full_image.bitdepth, 0));
// start at the first bigger-than-groupsize non-metachannel
size_t c = full_image.nb_meta_channels;
for (; c < full_image.channel.size(); c++) {
@ -328,7 +329,7 @@ Status ModularFrameDecoder::DecodeGroup(
memset(row_out, 0, r.xsize() * sizeof(*row_out));
}
} else {
Channel gc(r.xsize(), r.ysize());
JXL_ASSIGN_OR_RETURN(Channel gc, Channel::Create(r.xsize(), r.ysize()));
if (zerofill) ZeroFillImage(&gc.plane);
gc.hshift = fc.hshift;
gc.vshift = fc.vshift;
@ -398,7 +399,8 @@ Status ModularFrameDecoder::DecodeVarDCTDC(const FrameHeader& frame_header,
// 3 comes from XybToRgb that cubes the values, and "magic" is
// the sum of all other contributions. 2**18 is known to lead
// to NaN on input found by fuzzing (see commit message).
Image image(r.xsize(), r.ysize(), full_image.bitdepth, 3);
JXL_ASSIGN_OR_RETURN(
Image image, Image::Create(r.xsize(), r.ysize(), full_image.bitdepth, 3));
size_t stream_id = ModularStreamId::VarDCTDC(group_id).ID(frame_dim);
reader->Refill();
size_t extra_precision = reader->ReadFixedBits<2>();
@ -408,12 +410,13 @@ Status ModularFrameDecoder::DecodeVarDCTDC(const FrameHeader& frame_header,
Channel& ch = image.channel[c < 2 ? c ^ 1 : c];
ch.w >>= frame_header.chroma_subsampling.HShift(c);
ch.h >>= frame_header.chroma_subsampling.VShift(c);
ch.shrink();
JXL_RETURN_IF_ERROR(ch.shrink());
}
if (!ModularGenericDecompress(
reader, image, /*header=*/nullptr, stream_id, &options,
/*undo_transforms=*/true, &tree, &code, &context_map)) {
return JXL_FAILURE("Failed to decode VarDCT DC group");
return JXL_FAILURE("Failed to decode VarDCT DC group (DC group id %d)",
(int)group_id);
}
DequantDC(r, &dec_state->shared_storage.dc_storage,
&dec_state->shared_storage.quant_dc, image,
@ -433,12 +436,15 @@ Status ModularFrameDecoder::DecodeAcMetadata(const FrameHeader& frame_header,
size_t count = reader->ReadBits(CeilLog2Nonzero(upper_bound)) + 1;
size_t stream_id = ModularStreamId::ACMetadata(group_id).ID(frame_dim);
// YToX, YToB, ACS + QF, EPF
Image image(r.xsize(), r.ysize(), full_image.bitdepth, 4);
JXL_ASSIGN_OR_RETURN(
Image image, Image::Create(r.xsize(), r.ysize(), full_image.bitdepth, 4));
static_assert(kColorTileDimInBlocks == 8, "Color tile size changed");
Rect cr(r.x0() >> 3, r.y0() >> 3, (r.xsize() + 7) >> 3, (r.ysize() + 7) >> 3);
image.channel[0] = Channel(cr.xsize(), cr.ysize(), 3, 3);
image.channel[1] = Channel(cr.xsize(), cr.ysize(), 3, 3);
image.channel[2] = Channel(count, 2, 0, 0);
JXL_ASSIGN_OR_RETURN(image.channel[0],
Channel::Create(cr.xsize(), cr.ysize(), 3, 3));
JXL_ASSIGN_OR_RETURN(image.channel[1],
Channel::Create(cr.xsize(), cr.ysize(), 3, 3));
JXL_ASSIGN_OR_RETURN(image.channel[2], Channel::Create(count, 2, 0, 0));
ModularOptions options;
if (!ModularGenericDecompress(
reader, image, /*header=*/nullptr, stream_id, &options,
@ -686,7 +692,12 @@ Status ModularFrameDecoder::FinalizeDecoding(const FrameHeader& frame_header,
jxl::ThreadPool* pool,
bool inplace) {
if (!use_full_image) return true;
Image gi = (inplace ? std::move(full_image) : full_image.clone());
Image gi;
if (inplace) {
gi = std::move(full_image);
} else {
JXL_ASSIGN_OR_RETURN(gi, Image::Clone(full_image));
}
size_t xsize = gi.w;
size_t ysize = gi.h;
@ -714,6 +725,7 @@ Status ModularFrameDecoder::FinalizeDecoding(const FrameHeader& frame_header,
use_group_ids);
},
[&](const uint32_t group, size_t thread_id) {
if (has_error) return;
RenderPipelineInput input =
dec_state->render_pipeline->GetInputBuffers(group, thread_id);
if (!ModularImageToDecodedRect(
@ -722,12 +734,13 @@ Status ModularFrameDecoder::FinalizeDecoding(const FrameHeader& frame_header,
has_error = true;
return;
}
input.Done();
if (!input.Done()) {
has_error = true;
return;
}
},
"ModularToRect"));
if (has_error) {
return JXL_FAILURE("Error producing input to render pipeline");
}
if (has_error) return JXL_FAILURE("Error producing input to render pipeline");
return true;
}
@ -743,7 +756,8 @@ Status ModularFrameDecoder::DecodeQuantTable(
// be negative.
return JXL_FAILURE("Invalid qtable_den: value too small");
}
Image image(required_size_x, required_size_y, 8, 3);
JXL_ASSIGN_OR_RETURN(Image image,
Image::Create(required_size_x, required_size_y, 8, 3));
ModularOptions options;
if (modular_frame_decoder) {
JXL_RETURN_IF_ERROR(ModularGenericDecompress(

Просмотреть файл

@ -10,26 +10,16 @@
#include <sys/types.h>
#include <algorithm>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "lib/jxl/ans_params.h"
#include "lib/jxl/base/compiler_specific.h"
#include "lib/jxl/base/override.h"
#include "lib/jxl/base/printf_macros.h"
#include "lib/jxl/base/status.h"
#include "lib/jxl/blending.h"
#include "lib/jxl/chroma_from_luma.h"
#include "lib/jxl/common.h" // kMaxNumReferenceFrames
#include "lib/jxl/dec_ans.h"
#include "lib/jxl/dec_frame.h"
#include "lib/jxl/entropy_coder.h"
#include "lib/jxl/frame_header.h"
#include "lib/jxl/image.h"
#include "lib/jxl/image_bundle.h"
#include "lib/jxl/image_ops.h"
#include "lib/jxl/pack_signed.h"
#include "lib/jxl/patch_dictionary_internal.h"
@ -322,8 +312,8 @@ std::vector<size_t> PatchDictionary::GetPatchesForRow(size_t y) const {
// Adds patches to a segment of `xsize` pixels, starting at `inout`, assumed
// to be located at position (x0, y) in the frame.
void PatchDictionary::AddOneRow(float* const* inout, size_t y, size_t x0,
size_t xsize) const {
Status PatchDictionary::AddOneRow(float* const* inout, size_t y, size_t x0,
size_t xsize) const {
size_t num_ec = shared_->metadata->m.num_extra_channels;
std::vector<const float*> fg_ptrs(3 + num_ec);
for (size_t pos_idx : GetPatchesForRow(y)) {
@ -352,10 +342,11 @@ void PatchDictionary::AddOneRow(float* const* inout, size_t y, size_t x0,
ref_pos.y0 + iy) +
ref_pos.x0 + x0 - bx;
}
PerformBlending(inout, fg_ptrs.data(), inout, patch_x0 - x0,
patch_x1 - patch_x0, blendings_[blending_idx],
blendings_.data() + blending_idx + 1,
shared_->metadata->m.extra_channel_info);
JXL_RETURN_IF_ERROR(PerformBlending(
inout, fg_ptrs.data(), inout, patch_x0 - x0, patch_x1 - patch_x0,
blendings_[blending_idx], blendings_.data() + blending_idx + 1,
shared_->metadata->m.extra_channel_info));
}
return true;
}
} // namespace jxl

Просмотреть файл

@ -12,12 +12,10 @@
#include <string.h>
#include <sys/types.h>
#include <tuple>
#include <vector>
#include "lib/jxl/base/status.h"
#include "lib/jxl/dec_bit_reader.h"
#include "lib/jxl/image.h"
namespace jxl {
@ -109,7 +107,8 @@ class PatchDictionary {
// Adds patches to a segment of `xsize` pixels, starting at `inout`, assumed
// to be located at position (x0, y) in the frame.
void AddOneRow(float* const* inout, size_t y, size_t x0, size_t xsize) const;
Status AddOneRow(float* const* inout, size_t y, size_t x0,
size_t xsize) const;
// Returns dependencies of this patch dictionary on reference frame ids as a
// bit mask: bits 0-3 indicate reference frame 0-3.

74
third_party/jpeg-xl/lib/jxl/decode.cc поставляемый
Просмотреть файл

@ -2348,29 +2348,40 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderSetCms(JxlDecoder* dec,
return JXL_DEC_SUCCESS;
}
JXL_EXPORT JxlDecoderStatus JxlDecoderPreviewOutBufferSize(
const JxlDecoder* dec, const JxlPixelFormat* format, size_t* size) {
static JxlDecoderStatus GetMinSize(const JxlDecoder* dec,
const JxlPixelFormat* format,
size_t num_channels, size_t* min_size,
bool preview) {
size_t bits;
JxlDecoderStatus status = PrepareSizeCheck(dec, format, &bits);
if (status != JXL_DEC_SUCCESS) return status;
if (format->num_channels < 3 &&
!dec->image_metadata.color_encoding.IsGray()) {
return JXL_API_ERROR("Number of channels is too low for color output");
size_t xsize, ysize;
if (preview) {
xsize = dec->metadata.oriented_preview_xsize(dec->keep_orientation);
ysize = dec->metadata.oriented_preview_ysize(dec->keep_orientation);
} else {
GetCurrentDimensions(dec, xsize, ysize);
}
size_t xsize = dec->metadata.oriented_preview_xsize(dec->keep_orientation);
size_t ysize = dec->metadata.oriented_preview_ysize(dec->keep_orientation);
if (num_channels == 0) num_channels = format->num_channels;
size_t row_size =
jxl::DivCeil(xsize * format->num_channels * bits, jxl::kBitsPerByte);
jxl::DivCeil(xsize * num_channels * bits, jxl::kBitsPerByte);
size_t last_row_size = row_size;
if (format->align > 1) {
row_size = jxl::DivCeil(row_size, format->align) * format->align;
}
*size = row_size * (ysize - 1) + last_row_size;
*min_size = row_size * (ysize - 1) + last_row_size;
return JXL_DEC_SUCCESS;
}
JXL_EXPORT JxlDecoderStatus JxlDecoderPreviewOutBufferSize(
const JxlDecoder* dec, const JxlPixelFormat* format, size_t* size) {
if (format->num_channels < 3 &&
!dec->image_metadata.color_encoding.IsGray()) {
return JXL_API_ERROR("Number of channels is too low for color output");
}
return GetMinSize(dec, format, 0, size, true);
}
JXL_EXPORT JxlDecoderStatus JxlDecoderSetPreviewOutBuffer(
JxlDecoder* dec, const JxlPixelFormat* format, void* buffer, size_t size) {
if (!dec->got_basic_info || !dec->metadata.m.have_preview ||
@ -2401,23 +2412,12 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderSetPreviewOutBuffer(
JXL_EXPORT JxlDecoderStatus JxlDecoderImageOutBufferSize(
const JxlDecoder* dec, const JxlPixelFormat* format, size_t* size) {
size_t bits;
JxlDecoderStatus status = PrepareSizeCheck(dec, format, &bits);
if (status != JXL_DEC_SUCCESS) return status;
if (format->num_channels < 3 &&
!dec->image_metadata.color_encoding.IsGray()) {
return JXL_API_ERROR("Number of channels is too low for color output");
}
size_t xsize, ysize;
GetCurrentDimensions(dec, xsize, ysize);
size_t row_size =
jxl::DivCeil(xsize * format->num_channels * bits, jxl::kBitsPerByte);
if (format->align > 1) {
row_size = jxl::DivCeil(row_size, format->align) * format->align;
}
*size = row_size * ysize;
return JXL_DEC_SUCCESS;
return GetMinSize(dec, format, 0, size, false);
}
JxlDecoderStatus JxlDecoderSetImageOutBuffer(JxlDecoder* dec,
@ -2463,22 +2463,7 @@ JxlDecoderStatus JxlDecoderExtraChannelBufferSize(const JxlDecoder* dec,
return JXL_API_ERROR("Invalid extra channel index");
}
size_t num_channels = 1; // Do not use format's num_channels
size_t bits;
JxlDecoderStatus status = PrepareSizeCheck(dec, format, &bits);
if (status != JXL_DEC_SUCCESS) return status;
size_t xsize, ysize;
GetCurrentDimensions(dec, xsize, ysize);
size_t row_size =
jxl::DivCeil(xsize * num_channels * bits, jxl::kBitsPerByte);
if (format->align > 1) {
row_size = jxl::DivCeil(row_size, format->align) * format->align;
}
*size = row_size * ysize;
return JXL_DEC_SUCCESS;
return GetMinSize(dec, format, 1, size, false);
}
JxlDecoderStatus JxlDecoderSetExtraChannelBuffer(JxlDecoder* dec,
@ -2798,6 +2783,17 @@ JxlDecoderStatus JxlDecoderGetBoxSizeRaw(const JxlDecoder* dec,
return JXL_DEC_SUCCESS;
}
JxlDecoderStatus JxlDecoderGetBoxSizeContents(const JxlDecoder* dec,
uint64_t* size) {
if (!dec->box_event) {
return JXL_API_ERROR("can only get box info after JXL_DEC_BOX event");
}
if (size) {
*size = dec->box_contents_size;
}
return JXL_DEC_SUCCESS;
}
JxlDecoderStatus JxlDecoderSetProgressiveDetail(JxlDecoder* dec,
JxlProgressiveDetail detail) {
if (detail != kDC && detail != kLastPasses && detail != kPasses) {

183
third_party/jpeg-xl/lib/jxl/decode_test.cc поставляемый
Просмотреть файл

@ -47,7 +47,6 @@
#include "lib/jxl/dec_bit_reader.h"
#include "lib/jxl/dec_external_image.h"
#include "lib/jxl/enc_aux_out.h"
#include "lib/jxl/enc_butteraugli_comparator.h"
#include "lib/jxl/enc_external_image.h"
#include "lib/jxl/enc_fields.h"
#include "lib/jxl/enc_frame.h"
@ -113,23 +112,23 @@ enum CodeStreamBoxFormat {
};
// Unknown boxes for testing
static const char* unk1_box_type = "unk1";
static const char* unk1_box_contents = "abcdefghijklmnopqrstuvwxyz";
static const size_t unk1_box_size = strlen(unk1_box_contents);
static const char* unk2_box_type = "unk2";
static const char* unk2_box_contents = "0123456789";
static const size_t unk2_box_size = strlen(unk2_box_contents);
static const char* unk3_box_type = "unk3";
static const char* unk3_box_contents = "ABCDEF123456";
static const size_t unk3_box_size = strlen(unk3_box_contents);
const char* unk1_box_type = "unk1";
const char* unk1_box_contents = "abcdefghijklmnopqrstuvwxyz";
const size_t unk1_box_size = strlen(unk1_box_contents);
const char* unk2_box_type = "unk2";
const char* unk2_box_contents = "0123456789";
const size_t unk2_box_size = strlen(unk2_box_contents);
const char* unk3_box_type = "unk3";
const char* unk3_box_contents = "ABCDEF123456";
const size_t unk3_box_size = strlen(unk3_box_contents);
// Box with brob-compressed exif, including header
static const uint8_t* box_brob_exif = reinterpret_cast<const uint8_t*>(
const uint8_t* box_brob_exif = reinterpret_cast<const uint8_t*>(
"\0\0\0@brobExif\241\350\2\300\177\244v\2525\304\360\27=?\267{"
"\33\37\314\332\214QX17PT\"\256\0\0\202s\214\313t\333\310\320k\20\276\30"
"\204\277l$\326c#\1\b");
size_t box_brob_exif_size = 64;
// The uncompressed Exif data from the brob box
static const uint8_t* exif_uncompressed = reinterpret_cast<const uint8_t*>(
const uint8_t* exif_uncompressed = reinterpret_cast<const uint8_t*>(
"\0\0\0\0MM\0*"
"\0\0\0\b\0\5\1\22\0\3\0\0\0\1\0\5\0\0\1\32\0\5\0\0\0\1\0\0\0J\1\33\0\5\0\0"
"\0\1\0\0\0R\1("
@ -214,13 +213,15 @@ void GeneratePreview(PreviewMode preview_mode, ImageBundle* ib) {
}
}
};
Image3F preview(ib->xsize() * 7, ib->ysize() * 7);
JXL_ASSIGN_OR_DIE(Image3F preview,
Image3F::Create(ib->xsize() * 7, ib->ysize() * 7));
for (size_t c = 0; c < 3; ++c) {
upsample7(ib->color()->Plane(c), &preview.Plane(c));
}
std::vector<ImageF> extra_channels;
for (size_t i = 0; i < ib->extra_channels().size(); ++i) {
ImageF ec(ib->xsize() * 7, ib->ysize() * 7);
JXL_ASSIGN_OR_DIE(ImageF ec,
ImageF::Create(ib->xsize() * 7, ib->ysize() * 7));
upsample7(ib->extra_channels()[i], &ec);
extra_channels.emplace_back(std::move(ec));
}
@ -321,7 +322,7 @@ std::vector<uint8_t> CreateTestJXLCodestream(
}
}
if (params.preview_mode) {
io.preview_frame = io.Main().Copy();
JXL_ASSIGN_OR_DIE(io.preview_frame, io.Main().Copy());
GeneratePreview(params.preview_mode, &io.preview_frame);
io.metadata.m.have_preview = true;
EXPECT_TRUE(io.metadata.m.preview_size.Set(io.preview_frame.xsize(),
@ -622,6 +623,10 @@ std::vector<uint8_t> DecodeWithAPI(Span<const uint8_t> compressed,
////////////////////////////////////////////////////////////////////////////////
using jxl::Image3F;
using jxl::ImageF;
using jxl::test::ButteraugliDistance;
TEST(DecodeTest, JxlSignatureCheckTest) {
std::vector<std::pair<int, std::vector<uint8_t>>> tests = {
// No JPEGXL header starts with 'a'.
@ -1420,7 +1425,7 @@ std::vector<PixelTestConfig> GeneratePixelTests() {
c.add_intrinsic_size = intrinsic_size;
c.xsize = xsize;
c.ysize = ysize;
c.add_container = (CodeStreamBoxFormat)box;
c.add_container = box;
c.output_channels = ch.output_channels;
c.data_type = format.data_type;
c.endianness = format.endianness;
@ -1577,7 +1582,8 @@ JXL_GTEST_INSTANTIATE_TEST_SUITE_P(DecodeTest, DecodeTestParam,
TEST(DecodeTest, PixelTestWithICCProfileLossless) {
JxlDecoder* dec = JxlDecoderCreate(NULL);
size_t xsize = 123, ysize = 77;
size_t xsize = 123;
size_t ysize = 77;
size_t num_pixels = xsize * ysize;
std::vector<uint8_t> pixels = jxl::test::GetSomeTestImage(xsize, ysize, 4, 0);
JxlPixelFormat format_orig = {4, JXL_TYPE_UINT16, JXL_BIG_ENDIAN, 0};
@ -1644,7 +1650,8 @@ TEST(DecodeTest, PixelTestWithICCProfileLossless) {
TEST(DecodeTest, PixelTestWithICCProfileLossy) {
JxlDecoder* dec = JxlDecoderCreate(NULL);
size_t xsize = 123, ysize = 77;
size_t xsize = 123;
size_t ysize = 77;
size_t num_pixels = xsize * ysize;
std::vector<uint8_t> pixels = jxl::test::GetSomeTestImage(xsize, ysize, 3, 0);
JxlPixelFormat format_orig = {3, JXL_TYPE_UINT16, JXL_BIG_ENDIAN, 0};
@ -1753,7 +1760,8 @@ JXL_GTEST_INSTANTIATE_TEST_SUITE_P(
DecodeAllEncodingsTestInstantiation, DecodeAllEncodingsTest,
::testing::ValuesIn(jxl::test::AllEncodings()));
TEST_P(DecodeAllEncodingsTest, PreserveOriginalProfileTest) {
size_t xsize = 123, ysize = 77;
size_t xsize = 123;
size_t ysize = 77;
std::vector<uint8_t> pixels = jxl::test::GetSomeTestImage(xsize, ysize, 3, 0);
JxlPixelFormat format = {3, JXL_TYPE_UINT16, JXL_BIG_ENDIAN, 0};
int events = JXL_DEC_BASIC_INFO | JXL_DEC_COLOR_ENCODING | JXL_DEC_FULL_IMAGE;
@ -1796,7 +1804,8 @@ namespace {
void SetPreferredColorProfileTest(
const jxl::test::ColorEncodingDescriptor& from, bool icc_dst,
bool use_cms) {
size_t xsize = 123, ysize = 77;
size_t xsize = 123;
size_t ysize = 77;
int events = JXL_DEC_BASIC_INFO | JXL_DEC_COLOR_ENCODING | JXL_DEC_FULL_IMAGE;
jxl::ColorEncoding c_in = jxl::test::ColorEncodingFromDescriptor(from);
if (c_in.GetRenderingIntent() != jxl::RenderingIntent::kRelative) return;
@ -1970,6 +1979,7 @@ void DecodeImageWithColorEncoding(const std::vector<uint8_t>& compressed,
EXPECT_EQ(JXL_DEC_BASIC_INFO, JxlDecoderProcessInput(dec));
EXPECT_EQ(JXL_DEC_SUCCESS, JxlDecoderGetBasicInfo(dec, &info));
EXPECT_EQ(JXL_DEC_COLOR_ENCODING, JxlDecoderProcessInput(dec));
// TODO(eustas): why unused?
std::string color_space_in = GetOrigProfile(dec);
if (with_cms) {
JxlDecoderSetCms(dec, *JxlGetDefaultCms());
@ -2009,7 +2019,8 @@ JXL_GTEST_INSTANTIATE_TEST_SUITE_P(
TEST_P(DecodeAllEncodingsWithCMSTest, DecodeWithCMS) {
auto all_encodings = jxl::test::AllEncodings();
uint32_t num_channels = 3;
size_t xsize = 177, ysize = 123;
size_t xsize = 177;
size_t ysize = 123;
std::vector<uint8_t> pixels =
jxl::test::GetSomeTestImage(xsize, ysize, num_channels, 0);
jxl::TestCodestreamParams params;
@ -2047,7 +2058,8 @@ TEST(DecodeTest, PixelTestOpaqueSrgbLossy) {
for (unsigned channels = 3; channels <= 4; channels++) {
JxlDecoder* dec = JxlDecoderCreate(NULL);
size_t xsize = 123, ysize = 77;
size_t xsize = 123;
size_t ysize = 77;
size_t num_pixels = xsize * ysize;
std::vector<uint8_t> pixels =
jxl::test::GetSomeTestImage(xsize, ysize, 3, 0);
@ -2096,7 +2108,8 @@ TEST(DecodeTest, PixelTestOpaqueSrgbLossyNoise) {
for (unsigned channels = 3; channels <= 4; channels++) {
JxlDecoder* dec = JxlDecoderCreate(NULL);
size_t xsize = 512, ysize = 300;
size_t xsize = 512;
size_t ysize = 300;
size_t num_pixels = xsize * ysize;
std::vector<uint8_t> pixels =
jxl::test::GetSomeTestImage(xsize, ysize, 3, 0);
@ -2142,7 +2155,8 @@ TEST(DecodeTest, PixelTestOpaqueSrgbLossyNoise) {
}
TEST(DecodeTest, ProcessEmptyInputWithBoxes) {
size_t xsize = 123, ysize = 77;
size_t xsize = 123;
size_t ysize = 77;
std::vector<uint8_t> pixels = jxl::test::GetSomeTestImage(xsize, ysize, 3, 0);
jxl::CompressParams cparams;
uint32_t channels = 3;
@ -2175,7 +2189,8 @@ TEST(DecodeTest, ProcessEmptyInputWithBoxes) {
}
TEST(DecodeTest, ExtraBytesAfterCompressedStream) {
size_t xsize = 123, ysize = 77;
size_t xsize = 123;
size_t ysize = 77;
size_t num_pixels = xsize * ysize;
std::vector<uint8_t> pixels = jxl::test::GetSomeTestImage(xsize, ysize, 3, 0);
jxl::CompressParams cparams;
@ -2217,7 +2232,8 @@ TEST(DecodeTest, ExtraBytesAfterCompressedStream) {
}
TEST(DecodeTest, ExtraBytesAfterCompressedStreamRequireBoxes) {
size_t xsize = 123, ysize = 77;
size_t xsize = 123;
size_t ysize = 77;
size_t num_pixels = xsize * ysize;
std::vector<uint8_t> pixels = jxl::test::GetSomeTestImage(xsize, ysize, 3, 0);
jxl::CompressParams cparams;
@ -2251,7 +2267,8 @@ TEST(DecodeTest, ExtraBytesAfterCompressedStreamRequireBoxes) {
}
TEST(DecodeTest, ConcatenatedCompressedStreams) {
size_t xsize = 123, ysize = 77;
size_t xsize = 123;
size_t ysize = 77;
size_t num_pixels = xsize * ysize;
std::vector<uint8_t> pixels = jxl::test::GetSomeTestImage(xsize, ysize, 3, 0);
jxl::CompressParams cparams;
@ -2300,7 +2317,8 @@ TEST(DecodeTest, ConcatenatedCompressedStreams) {
}
void TestPartialStream(bool reconstructible_jpeg) {
size_t xsize = 123, ysize = 77;
size_t xsize = 123;
size_t ysize = 77;
uint32_t channels = 4;
if (reconstructible_jpeg) {
channels = 3;
@ -2487,7 +2505,8 @@ TEST(DecodeTest, DCNotGettableTest) {
}
TEST(DecodeTest, PreviewTest) {
size_t xsize = 77, ysize = 120;
size_t xsize = 77;
size_t ysize = 120;
std::vector<uint8_t> pixels = jxl::test::GetSomeTestImage(xsize, ysize, 3, 0);
JxlPixelFormat format_orig = {3, JXL_TYPE_UINT16, JXL_BIG_ENDIAN, 0};
for (jxl::PreviewMode mode : {jxl::kSmallPreview, jxl::kBigPreview}) {
@ -2561,7 +2580,8 @@ TEST(DecodeTest, PreviewTest) {
}
TEST(DecodeTest, AlignTest) {
size_t xsize = 123, ysize = 77;
size_t xsize = 123;
size_t ysize = 77;
std::vector<uint8_t> pixels = jxl::test::GetSomeTestImage(xsize, ysize, 4, 0);
JxlPixelFormat format_orig = {4, JXL_TYPE_UINT16, JXL_BIG_ENDIAN, 0};
@ -2575,7 +2595,11 @@ TEST(DecodeTest, AlignTest) {
size_t align = 17;
JxlPixelFormat format = {3, JXL_TYPE_UINT8, JXL_LITTLE_ENDIAN, align};
// On purpose not using jxl::RoundUpTo to test it independently.
size_t expected_line_bytes = (1 * 3 * xsize + align - 1) / align * align;
size_t expected_line_size_last = 1 * 3 * xsize;
size_t expected_line_size =
((expected_line_size_last + align - 1) / align) * align;
size_t expected_pixels_size =
expected_line_size * (ysize - 1) + expected_line_size_last;
for (int use_callback = 0; use_callback <= 1; ++use_callback) {
std::vector<uint8_t> pixels2 = jxl::DecodeWithAPI(
@ -2583,14 +2607,15 @@ TEST(DecodeTest, AlignTest) {
/*set_buffer_early=*/false,
/*use_resizable_runner=*/false, /*require_boxes=*/false,
/*expect_success=*/true);
EXPECT_EQ(expected_line_bytes * ysize, pixels2.size());
EXPECT_EQ(expected_pixels_size, pixels2.size());
EXPECT_EQ(0u, jxl::test::ComparePixels(pixels.data(), pixels2.data(), xsize,
ysize, format_orig, format));
}
}
TEST(DecodeTest, AnimationTest) {
size_t xsize = 123, ysize = 77;
size_t xsize = 123;
size_t ysize = 77;
static const size_t num_frames = 2;
std::vector<uint8_t> frames[2];
frames[0] = jxl::test::GetSomeTestImage(xsize, ysize, 3, 0);
@ -2690,7 +2715,8 @@ TEST(DecodeTest, AnimationTest) {
}
TEST(DecodeTest, AnimationTestStreaming) {
size_t xsize = 123, ysize = 77;
size_t xsize = 123;
size_t ysize = 77;
static const size_t num_frames = 2;
std::vector<uint8_t> frames[2];
frames[0] = jxl::test::GetSomeTestImage(xsize, ysize, 3, 0);
@ -2822,7 +2848,8 @@ TEST(DecodeTest, AnimationTestStreaming) {
}
TEST(DecodeTest, ExtraChannelTest) {
size_t xsize = 55, ysize = 257;
size_t xsize = 55;
size_t ysize = 257;
std::vector<uint8_t> pixels = jxl::test::GetSomeTestImage(xsize, ysize, 4, 0);
JxlPixelFormat format_orig = {4, JXL_TYPE_UINT16, JXL_BIG_ENDIAN, 0};
@ -2899,7 +2926,8 @@ TEST(DecodeTest, ExtraChannelTest) {
}
TEST(DecodeTest, SkipCurrentFrameTest) {
size_t xsize = 90, ysize = 120;
size_t xsize = 90;
size_t ysize = 120;
constexpr size_t num_frames = 7;
std::vector<uint8_t> frames[num_frames];
for (size_t i = 0; i < num_frames; i++) {
@ -3010,7 +3038,8 @@ TEST(DecodeTest, SkipCurrentFrameTest) {
}
TEST(DecodeTest, SkipFrameTest) {
size_t xsize = 90, ysize = 120;
size_t xsize = 90;
size_t ysize = 120;
constexpr size_t num_frames = 16;
std::vector<uint8_t> frames[num_frames];
for (size_t i = 0; i < num_frames; i++) {
@ -3146,7 +3175,8 @@ TEST(DecodeTest, SkipFrameTest) {
}
TEST(DecodeTest, SkipFrameWithBlendingTest) {
size_t xsize = 90, ysize = 120;
size_t xsize = 90;
size_t ysize = 120;
constexpr size_t num_frames = 16;
std::vector<uint8_t> frames[num_frames];
JxlPixelFormat format = {3, JXL_TYPE_UINT16, JXL_BIG_ENDIAN, 0};
@ -3360,7 +3390,8 @@ TEST(DecodeTest, SkipFrameWithBlendingTest) {
}
TEST(DecodeTest, SkipFrameWithAlphaBlendingTest) {
size_t xsize = 90, ysize = 120;
size_t xsize = 90;
size_t ysize = 120;
constexpr size_t num_frames = 16;
std::vector<uint8_t> frames[num_frames + 5];
JxlPixelFormat format = {4, JXL_TYPE_UINT16, JXL_BIG_ENDIAN, 0};
@ -3376,7 +3407,10 @@ TEST(DecodeTest, SkipFrameWithAlphaBlendingTest) {
std::vector<uint32_t> frame_durations_c;
std::vector<uint32_t> frame_durations_nc;
std::vector<uint32_t> frame_xsize, frame_ysize, frame_x0, frame_y0;
std::vector<uint32_t> frame_xsize;
std::vector<uint32_t> frame_ysize;
std::vector<uint32_t> frame_x0;
std::vector<uint32_t> frame_y0;
for (size_t i = 0; i < num_frames; ++i) {
size_t cropxsize = 1 + xsize * 2 / (i + 1);
@ -3648,7 +3682,8 @@ TEST(DecodeTest, SkipFrameWithAlphaBlendingTest) {
TEST(DecodeTest, OrientedCroppedFrameTest) {
const auto test = [](bool keep_orientation, uint32_t orientation,
uint32_t resampling) {
size_t xsize = 90, ysize = 120;
size_t xsize = 90;
size_t ysize = 120;
JxlPixelFormat format = {4, JXL_TYPE_UINT16, JXL_BIG_ENDIAN, 0};
size_t oxsize = (!keep_orientation && orientation > 4 ? ysize : xsize);
size_t oysize = (!keep_orientation && orientation > 4 ? xsize : ysize);
@ -3985,7 +4020,8 @@ void VerifyProgression(size_t xsize, size_t ysize, uint32_t num_channels,
}
TEST(DecodeTest, ProgressionTest) {
size_t xsize = 508, ysize = 470;
size_t xsize = 508;
size_t ysize = 470;
uint32_t num_channels = 3;
std::vector<uint8_t> pixels =
jxl::test::GetSomeTestImage(xsize, ysize, num_channels, 0);
@ -4020,7 +4056,8 @@ TEST(DecodeTest, ProgressionTest) {
}
TEST(DecodeTest, ProgressionTestLosslessAlpha) {
size_t xsize = 508, ysize = 470;
size_t xsize = 508;
size_t ysize = 470;
uint32_t num_channels = 4;
std::vector<uint8_t> pixels =
jxl::test::GetSomeTestImage(xsize, ysize, num_channels, 0);
@ -4063,7 +4100,8 @@ void VerifyFilePosition(size_t expected_pos, const std::vector<uint8_t>& data,
}
TEST(DecodeTest, InputHandlingTestOneShot) {
size_t xsize = 508, ysize = 470;
size_t xsize = 508;
size_t ysize = 470;
uint32_t num_channels = 3;
std::vector<uint8_t> pixels =
jxl::test::GetSomeTestImage(xsize, ysize, num_channels, 0);
@ -4246,7 +4284,8 @@ TEST(DecodeTest, JXL_TRANSCODE_JPEG_TEST(InputHandlingTestJPEGOneshot)) {
}
TEST(DecodeTest, InputHandlingTestStreaming) {
size_t xsize = 508, ysize = 470;
size_t xsize = 508;
size_t ysize = 470;
uint32_t num_channels = 3;
std::vector<uint8_t> pixels =
jxl::test::GetSomeTestImage(xsize, ysize, num_channels, 0);
@ -4346,7 +4385,8 @@ TEST(DecodeTest, InputHandlingTestStreaming) {
TEST(DecodeTest, FlushTest) {
// Size large enough for multiple groups, required to have progressive
// stages
size_t xsize = 333, ysize = 300;
size_t xsize = 333;
size_t ysize = 300;
uint32_t num_channels = 3;
std::vector<uint8_t> pixels =
jxl::test::GetSomeTestImage(xsize, ysize, num_channels, 0);
@ -4421,7 +4461,8 @@ TEST(DecodeTest, FlushTest) {
TEST(DecodeTest, FlushTestImageOutCallback) {
// Size large enough for multiple groups, required to have progressive
// stages
size_t xsize = 333, ysize = 300;
size_t xsize = 333;
size_t ysize = 300;
uint32_t num_channels = 3;
std::vector<uint8_t> pixels =
jxl::test::GetSomeTestImage(xsize, ysize, num_channels, 0);
@ -4507,7 +4548,8 @@ TEST(DecodeTest, FlushTestImageOutCallback) {
TEST(DecodeTest, FlushTestLossyProgressiveAlpha) {
// Size large enough for multiple groups, required to have progressive
// stages
size_t xsize = 333, ysize = 300;
size_t xsize = 333;
size_t ysize = 300;
uint32_t num_channels = 4;
std::vector<uint8_t> pixels =
jxl::test::GetSomeTestImage(xsize, ysize, num_channels, 0);
@ -4577,7 +4619,8 @@ TEST(DecodeTest, FlushTestLossyProgressiveAlpha) {
JxlDecoderDestroy(dec);
}
TEST(DecodeTest, FlushTestLossyProgressiveAlphaUpsampling) {
size_t xsize = 533, ysize = 401;
size_t xsize = 533;
size_t ysize = 401;
uint32_t num_channels = 4;
std::vector<uint8_t> pixels =
jxl::test::GetSomeTestImage(xsize, ysize, num_channels, 0);
@ -4651,7 +4694,8 @@ TEST(DecodeTest, FlushTestLossyProgressiveAlphaUpsampling) {
TEST(DecodeTest, FlushTestLosslessProgressiveAlpha) {
// Size large enough for multiple groups, required to have progressive
// stages
size_t xsize = 333, ysize = 300;
size_t xsize = 333;
size_t ysize = 300;
uint32_t num_channels = 4;
std::vector<uint8_t> pixels =
jxl::test::GetSomeTestImage(xsize, ysize, num_channels, 0);
@ -4741,7 +4785,8 @@ TEST_P(DecodeProgressiveTest, ProgressiveEventTest) {
// intermediate flushes for complete DC and complete passes.
// The test can be updated if more cases are expected to support it.
bool expect_flush = (num_channels & 1) && !lossless;
size_t xsize, ysize;
size_t xsize;
size_t ysize;
if (single_group) {
// An image smaller than 256x256 ensures it contains only 1 group.
xsize = 99;
@ -4982,7 +5027,8 @@ TEST(DecodeTest, JXL_TRANSCODE_JPEG_TEST(JPEGReconstructionMetadataTest)) {
}
TEST(DecodeTest, ContinueFinalNonEssentialBoxTest) {
size_t xsize = 80, ysize = 90;
size_t xsize = 80;
size_t ysize = 90;
std::vector<uint8_t> pixels = jxl::test::GetSomeTestImage(xsize, ysize, 4, 0);
jxl::TestCodestreamParams params;
params.box_format = kCSBF_Multi_Other_Terminated;
@ -5038,7 +5084,7 @@ TEST(DecodeTest, ContinueFinalNonEssentialBoxTest) {
}
namespace {
bool BoxTypeEquals(const std::string& type_string, JxlBoxType type) {
bool BoxTypeEquals(const std::string& type_string, const JxlBoxType type) {
return type_string.size() == 4 && type_string[0] == type[0] &&
type_string[1] == type[1] && type_string[2] == type[2] &&
type_string[3] == type[3];
@ -5054,28 +5100,38 @@ TEST(DecodeTest, ExtentedBoxSizeTest) {
JxlBoxType type;
uint64_t box_size;
uint64_t contents_size;
EXPECT_EQ(JXL_DEC_SUCCESS, JxlDecoderSetInput(dec, orig.data(), orig.size()));
EXPECT_EQ(JXL_DEC_BOX, JxlDecoderProcessInput(dec));
EXPECT_EQ(JXL_DEC_SUCCESS, JxlDecoderGetBoxType(dec, type, JXL_FALSE));
EXPECT_TRUE(BoxTypeEquals("JXL ", type));
EXPECT_EQ(JXL_DEC_SUCCESS, JxlDecoderGetBoxSizeRaw(dec, &box_size));
EXPECT_EQ(12, box_size);
EXPECT_EQ(JXL_DEC_SUCCESS, JxlDecoderGetBoxSizeContents(dec, &contents_size));
EXPECT_EQ(contents_size + 8, box_size);
EXPECT_EQ(JXL_DEC_BOX, JxlDecoderProcessInput(dec));
EXPECT_EQ(JXL_DEC_SUCCESS, JxlDecoderGetBoxType(dec, type, JXL_FALSE));
EXPECT_TRUE(BoxTypeEquals("ftyp", type));
EXPECT_EQ(JXL_DEC_SUCCESS, JxlDecoderGetBoxSizeRaw(dec, &box_size));
EXPECT_EQ(20, box_size);
EXPECT_EQ(JXL_DEC_SUCCESS, JxlDecoderGetBoxSizeContents(dec, &contents_size));
EXPECT_EQ(contents_size + 8, box_size);
EXPECT_EQ(JXL_DEC_BOX, JxlDecoderProcessInput(dec));
EXPECT_EQ(JXL_DEC_SUCCESS, JxlDecoderGetBoxType(dec, type, JXL_FALSE));
EXPECT_TRUE(BoxTypeEquals("jxlc", type));
EXPECT_EQ(JXL_DEC_SUCCESS, JxlDecoderGetBoxSizeRaw(dec, &box_size));
EXPECT_EQ(72, box_size);
EXPECT_EQ(JXL_DEC_SUCCESS, JxlDecoderGetBoxSizeContents(dec, &contents_size));
// This is an extended box, hence the difference between `box_size` and
// `contents_size` is 16.
EXPECT_EQ(contents_size + 8 + 8, box_size);
JxlDecoderDestroy(dec);
}
TEST(DecodeTest, JXL_BOXES_TEST(BoxTest)) {
size_t xsize = 1, ysize = 1;
size_t xsize = 1;
size_t ysize = 1;
std::vector<uint8_t> pixels = jxl::test::GetSomeTestImage(xsize, ysize, 4, 0);
jxl::TestCodestreamParams params;
params.box_format = kCSBF_Multi_Other_Terminated;
@ -5096,6 +5152,7 @@ TEST(DecodeTest, JXL_BOXES_TEST(BoxTest)) {
JxlBoxType type;
uint64_t box_size;
uint64_t contents_size;
std::vector<uint8_t> contents(50);
size_t expected_release_size = 0;
@ -5113,6 +5170,9 @@ TEST(DecodeTest, JXL_BOXES_TEST(BoxTest)) {
EXPECT_TRUE(BoxTypeEquals(expected_box_types[i], type));
if (expected_box_sizes[i]) {
EXPECT_EQ(expected_box_sizes[i], box_size);
EXPECT_EQ(JXL_DEC_SUCCESS,
JxlDecoderGetBoxSizeContents(dec, &contents_size));
EXPECT_EQ(contents_size + 8, box_size);
}
if (expected_release_size > 0) {
@ -5147,7 +5207,8 @@ TEST(DecodeTest, JXL_BOXES_TEST(BoxTest)) {
}
TEST(DecodeTest, JXL_BOXES_TEST(ExifBrobBoxTest)) {
size_t xsize = 1, ysize = 1;
size_t xsize = 1;
size_t ysize = 1;
std::vector<uint8_t> pixels = jxl::test::GetSomeTestImage(xsize, ysize, 4, 0);
jxl::TestCodestreamParams params;
// Lossless to verify pixels exactly after roundtrip.
@ -5328,7 +5389,8 @@ TEST(DecodeTest, JXL_BOXES_TEST(ExifBrobBoxTest)) {
}
TEST(DecodeTest, JXL_BOXES_TEST(PartialCodestreamBoxTest)) {
size_t xsize = 23, ysize = 81;
size_t xsize = 23;
size_t ysize = 81;
std::vector<uint8_t> pixels = jxl::test::GetSomeTestImage(xsize, ysize, 4, 0);
JxlPixelFormat format_orig = {4, JXL_TYPE_UINT16, JXL_BIG_ENDIAN, 0};
// Lossless to verify pixels exactly after roundtrip.
@ -5482,10 +5544,11 @@ TEST(DecodeTest, JXL_BOXES_TEST(PartialCodestreamBoxTest)) {
TEST(DecodeTest, SpotColorTest) {
jxl::CodecInOut io;
size_t xsize = 55, ysize = 257;
size_t xsize = 55;
size_t ysize = 257;
io.metadata.m.color_encoding = jxl::ColorEncoding::LinearSRGB();
jxl::Image3F main(xsize, ysize);
jxl::ImageF spot(xsize, ysize);
JXL_ASSIGN_OR_DIE(Image3F main, Image3F::Create(xsize, ysize));
JXL_ASSIGN_OR_DIE(ImageF spot, ImageF::Create(xsize, ysize));
jxl::ZeroFillImage(&main);
jxl::ZeroFillImage(&spot);
@ -5508,7 +5571,7 @@ TEST(DecodeTest, SpotColorTest) {
info.spot_color[3] = 0.5f;
io.metadata.m.extra_channel_info.push_back(info);
std::vector<jxl::ImageF> ec;
std::vector<ImageF> ec;
ec.push_back(std::move(spot));
io.frames[0].SetExtraChannels(std::move(ec));

Просмотреть файл

@ -18,20 +18,15 @@
#include <hwy/highway.h>
#include "lib/jxl/ac_strategy.h"
#include "lib/jxl/ans_params.h"
#include "lib/jxl/base/bits.h"
#include "lib/jxl/base/compiler_specific.h"
#include "lib/jxl/base/fast_math-inl.h"
#include "lib/jxl/base/status.h"
#include "lib/jxl/coeff_order_fwd.h"
#include "lib/jxl/convolve.h"
#include "lib/jxl/dct_scales.h"
#include "lib/jxl/dec_transforms-inl.h"
#include "lib/jxl/enc_aux_out.h"
#include "lib/jxl/enc_debug_image.h"
#include "lib/jxl/enc_params.h"
#include "lib/jxl/enc_transforms-inl.h"
#include "lib/jxl/entropy_coder.h"
#include "lib/jxl/simd_util.h"
// Some of the floating point constants in this file and in other
@ -215,10 +210,10 @@ const uint8_t* TypeMask(const uint8_t& raw_strategy) {
return kMask[raw_strategy];
}
void DumpAcStrategy(const AcStrategyImage& ac_strategy, size_t xsize,
size_t ysize, const char* tag, AuxOut* aux_out,
const CompressParams& cparams) {
Image3F color_acs(xsize, ysize);
Status DumpAcStrategy(const AcStrategyImage& ac_strategy, size_t xsize,
size_t ysize, const char* tag, AuxOut* aux_out,
const CompressParams& cparams) {
JXL_ASSIGN_OR_RETURN(Image3F color_acs, Image3F::Create(xsize, ysize));
for (size_t y = 0; y < ysize; y++) {
float* JXL_RESTRICT rows[3] = {
color_acs.PlaneRow(0, y),
@ -269,7 +264,7 @@ void DumpAcStrategy(const AcStrategyImage& ac_strategy, size_t xsize,
}
}
}
DumpImage(cparams, tag, color_acs);
return DumpImage(cparams, tag, color_acs);
}
} // namespace
@ -1102,9 +1097,9 @@ void AcStrategyHeuristics::ProcessRect(const Rect& rect,
(cparams, config, rect, cmap, ac_strategy);
}
void AcStrategyHeuristics::Finalize(const FrameDimensions& frame_dim,
const AcStrategyImage& ac_strategy,
AuxOut* aux_out) {
Status AcStrategyHeuristics::Finalize(const FrameDimensions& frame_dim,
const AcStrategyImage& ac_strategy,
AuxOut* aux_out) {
// Accounting and debug output.
if (aux_out != nullptr) {
aux_out->num_small_blocks =
@ -1141,9 +1136,11 @@ void AcStrategyHeuristics::Finalize(const FrameDimensions& frame_dim,
// if (JXL_DEBUG_AC_STRATEGY && WantDebugOutput(aux_out)) {
if (JXL_DEBUG_AC_STRATEGY && WantDebugOutput(cparams)) {
DumpAcStrategy(ac_strategy, frame_dim.xsize, frame_dim.ysize, "ac_strategy",
aux_out, cparams);
JXL_RETURN_IF_ERROR(DumpAcStrategy(ac_strategy, frame_dim.xsize,
frame_dim.ysize, "ac_strategy", aux_out,
cparams));
}
return true;
}
} // namespace jxl

Просмотреть файл

@ -58,14 +58,15 @@ struct ACSConfig {
};
struct AcStrategyHeuristics {
AcStrategyHeuristics(const CompressParams& cparams) : cparams(cparams) {}
explicit AcStrategyHeuristics(const CompressParams& cparams)
: cparams(cparams) {}
void Init(const Image3F& src, const Rect& rect_in, const ImageF& quant_field,
const ImageF& mask, const ImageF& mask1x1,
DequantMatrices* matrices);
void ProcessRect(const Rect& rect, const ColorCorrelationMap& cmap,
AcStrategyImage* ac_strategy);
void Finalize(const FrameDimensions& frame_dim,
const AcStrategyImage& ac_strategy, AuxOut* aux_out);
Status Finalize(const FrameDimensions& frame_dim,
const AcStrategyImage& ac_strategy, AuxOut* aux_out);
const CompressParams& cparams;
ACSConfig config;
};

Просмотреть файл

@ -9,6 +9,7 @@
#include <stdlib.h>
#include <algorithm>
#include <atomic>
#include <cmath>
#include <string>
#include <vector>
@ -26,8 +27,6 @@
#include "lib/jxl/base/status.h"
#include "lib/jxl/butteraugli/butteraugli.h"
#include "lib/jxl/cms/opsin_params.h"
#include "lib/jxl/coeff_order_fwd.h"
#include "lib/jxl/color_encoding_internal.h"
#include "lib/jxl/convolve.h"
#include "lib/jxl/dec_cache.h"
#include "lib/jxl/dec_group.h"
@ -102,12 +101,12 @@ V ComputeMask(const D d, const V out_val) {
}
// mul and mul2 represent a scaling difference between jxl and butteraugli.
static const float kSGmul = 226.77216153508914f;
static const float kSGmul2 = 1.0f / 73.377132366608819f;
static const float kLog2 = 0.693147181f;
const float kSGmul = 226.77216153508914f;
const float kSGmul2 = 1.0f / 73.377132366608819f;
const float kLog2 = 0.693147181f;
// Includes correction factor for std::log -> log2.
static const float kSGRetMul = kSGmul2 * 18.6580932135f * kLog2;
static const float kSGVOffset = 7.7825991679894591f;
const float kSGRetMul = kSGmul2 * 18.6580932135f * kLog2;
const float kSGVOffset = 7.7825991679894591f;
template <bool invert, typename D, typename V>
V RatioOfDerivativesOfCubicRootToSimpleGamma(const D d, V v) {
@ -131,7 +130,7 @@ V RatioOfDerivativesOfCubicRootToSimpleGamma(const D d, V v) {
}
template <bool invert = false>
static float RatioOfDerivativesOfCubicRootToSimpleGamma(float v) {
float RatioOfDerivativesOfCubicRootToSimpleGamma(float v) {
using DScalar = HWY_CAPPED(float, 1);
auto vscalar = Load(DScalar(), &v);
return GetLane(
@ -396,12 +395,16 @@ void FuzzyErosion(const float butteraugli_target, const Rect& from_rect,
}
struct AdaptiveQuantizationImpl {
void PrepareBuffers(size_t num_threads) {
diff_buffer = ImageF(kEncTileDim + 8, num_threads);
Status PrepareBuffers(size_t num_threads) {
JXL_ASSIGN_OR_RETURN(diff_buffer,
ImageF::Create(kEncTileDim + 8, num_threads));
for (size_t i = pre_erosion.size(); i < num_threads; i++) {
pre_erosion.emplace_back(kEncTileDimInBlocks * 2 + 2,
kEncTileDimInBlocks * 2 + 2);
JXL_ASSIGN_OR_RETURN(ImageF tmp,
ImageF::Create(kEncTileDimInBlocks * 2 + 2,
kEncTileDimInBlocks * 2 + 2));
pre_erosion.emplace_back(std::move(tmp));
}
return true;
}
void ComputeTile(float butteraugli_target, float scale, const Image3F& xyb,
@ -568,8 +571,7 @@ struct AdaptiveQuantizationImpl {
ImageF diff_buffer;
};
static void Blur1x1Masking(ThreadPool* pool, ImageF* mask1x1,
const Rect& rect) {
Status Blur1x1Masking(ThreadPool* pool, ImageF* mask1x1, const Rect& rect) {
// Blur the mask1x1 to obtain the masking image.
// Before blurring it contains an image of absolute value of the
// Laplacian of the intensity channel.
@ -595,30 +597,30 @@ static void Blur1x1Masking(ThreadPool* pool, ImageF* mask1x1,
{HWY_REP4(normalize_mul * kFilterMask1x1[1])},
{HWY_REP4(normalize_mul * kFilterMask1x1[4])},
{HWY_REP4(normalize_mul * kFilterMask1x1[3])}};
ImageF temp(rect.xsize(), rect.ysize());
JXL_ASSIGN_OR_RETURN(ImageF temp, ImageF::Create(rect.xsize(), rect.ysize()));
Symmetric5(*mask1x1, rect, weights, pool, &temp);
*mask1x1 = std::move(temp);
return true;
}
ImageF AdaptiveQuantizationMap(const float butteraugli_target,
const Image3F& xyb, const Rect& rect,
float scale, ThreadPool* pool, ImageF* mask,
ImageF* mask1x1) {
StatusOr<ImageF> AdaptiveQuantizationMap(const float butteraugli_target,
const Image3F& xyb, const Rect& rect,
float scale, ThreadPool* pool,
ImageF* mask, ImageF* mask1x1) {
JXL_DASSERT(rect.xsize() % kBlockDim == 0);
JXL_DASSERT(rect.ysize() % kBlockDim == 0);
AdaptiveQuantizationImpl impl;
const size_t xsize_blocks = rect.xsize() / kBlockDim;
const size_t ysize_blocks = rect.ysize() / kBlockDim;
impl.aq_map = ImageF(xsize_blocks, ysize_blocks);
*mask = ImageF(xsize_blocks, ysize_blocks);
*mask1x1 = ImageF(xyb.xsize(), xyb.ysize());
JXL_ASSIGN_OR_RETURN(impl.aq_map, ImageF::Create(xsize_blocks, ysize_blocks));
JXL_ASSIGN_OR_RETURN(*mask, ImageF::Create(xsize_blocks, ysize_blocks));
JXL_ASSIGN_OR_RETURN(*mask1x1, ImageF::Create(xyb.xsize(), xyb.ysize()));
JXL_CHECK(RunOnPool(
pool, 0,
DivCeil(xsize_blocks, kEncTileDimInBlocks) *
DivCeil(ysize_blocks, kEncTileDimInBlocks),
[&](const size_t num_threads) {
impl.PrepareBuffers(num_threads);
return true;
return !!impl.PrepareBuffers(num_threads);
},
[&](const uint32_t tid, const size_t thread) {
size_t n_enc_tiles = DivCeil(xsize_blocks, kEncTileDimInBlocks);
@ -634,7 +636,7 @@ ImageF AdaptiveQuantizationMap(const float butteraugli_target,
},
"AQ DiffPrecompute"));
Blur1x1Masking(pool, mask1x1, rect);
JXL_RETURN_IF_ERROR(Blur1x1Masking(pool, mask1x1, rect));
return std::move(impl).aq_map;
}
@ -654,24 +656,28 @@ namespace {
// If true, prints the quantization maps at each iteration.
constexpr bool FLAGS_dump_quant_state = false;
void DumpHeatmap(const CompressParams& cparams, const AuxOut* aux_out,
const std::string& label, const ImageF& image,
float good_threshold, float bad_threshold) {
Status DumpHeatmap(const CompressParams& cparams, const AuxOut* aux_out,
const std::string& label, const ImageF& image,
float good_threshold, float bad_threshold) {
if (JXL_DEBUG_ADAPTIVE_QUANTIZATION) {
Image3F heatmap = CreateHeatMapImage(image, good_threshold, bad_threshold);
JXL_ASSIGN_OR_RETURN(
Image3F heatmap,
CreateHeatMapImage(image, good_threshold, bad_threshold));
char filename[200];
snprintf(filename, sizeof(filename), "%s%05d", label.c_str(),
aux_out->num_butteraugli_iters);
DumpImage(cparams, filename, heatmap);
JXL_RETURN_IF_ERROR(DumpImage(cparams, filename, heatmap));
}
return true;
}
void DumpHeatmaps(const CompressParams& cparams, const AuxOut* aux_out,
float ba_target, const ImageF& quant_field,
const ImageF& tile_heatmap, const ImageF& bt_diffmap) {
Status DumpHeatmaps(const CompressParams& cparams, const AuxOut* aux_out,
float ba_target, const ImageF& quant_field,
const ImageF& tile_heatmap, const ImageF& bt_diffmap) {
if (JXL_DEBUG_ADAPTIVE_QUANTIZATION) {
if (!WantDebugOutput(cparams)) return;
ImageF inv_qmap(quant_field.xsize(), quant_field.ysize());
if (!WantDebugOutput(cparams)) return true;
JXL_ASSIGN_OR_RETURN(ImageF inv_qmap, ImageF::Create(quant_field.xsize(),
quant_field.ysize()));
for (size_t y = 0; y < quant_field.ysize(); ++y) {
const float* JXL_RESTRICT row_q = quant_field.ConstRow(y);
float* JXL_RESTRICT row_inv_q = inv_qmap.Row(y);
@ -679,21 +685,24 @@ void DumpHeatmaps(const CompressParams& cparams, const AuxOut* aux_out,
row_inv_q[x] = 1.0f / row_q[x]; // never zero
}
}
DumpHeatmap(cparams, aux_out, "quant_heatmap", inv_qmap, 4.0f * ba_target,
6.0f * ba_target);
DumpHeatmap(cparams, aux_out, "tile_heatmap", tile_heatmap, ba_target,
1.5f * ba_target);
JXL_RETURN_IF_ERROR(DumpHeatmap(cparams, aux_out, "quant_heatmap", inv_qmap,
4.0f * ba_target, 6.0f * ba_target));
JXL_RETURN_IF_ERROR(DumpHeatmap(cparams, aux_out, "tile_heatmap",
tile_heatmap, ba_target, 1.5f * ba_target));
// matches heat maps produced by the command line tool.
DumpHeatmap(cparams, aux_out, "bt_diffmap", bt_diffmap,
ButteraugliFuzzyInverse(1.5), ButteraugliFuzzyInverse(0.5));
JXL_RETURN_IF_ERROR(DumpHeatmap(cparams, aux_out, "bt_diffmap", bt_diffmap,
ButteraugliFuzzyInverse(1.5),
ButteraugliFuzzyInverse(0.5)));
}
return true;
}
ImageF TileDistMap(const ImageF& distmap, int tile_size, int margin,
const AcStrategyImage& ac_strategy) {
StatusOr<ImageF> TileDistMap(const ImageF& distmap, int tile_size, int margin,
const AcStrategyImage& ac_strategy) {
const int tile_xsize = (distmap.xsize() + tile_size - 1) / tile_size;
const int tile_ysize = (distmap.ysize() + tile_size - 1) / tile_size;
ImageF tile_distmap(tile_xsize, tile_ysize);
JXL_ASSIGN_OR_RETURN(ImageF tile_distmap,
ImageF::Create(tile_xsize, tile_ysize));
size_t distmap_stride = tile_distmap.PixelsPerRow();
for (int tile_y = 0; tile_y < tile_ysize; ++tile_y) {
AcStrategyRow ac_strategy_row = ac_strategy.ConstRow(tile_y);
@ -754,14 +763,16 @@ ImageF TileDistMap(const ImageF& distmap, int tile_size, int margin,
return tile_distmap;
}
static const float kDcQuantPow = 0.83f;
static const float kDcQuant = 1.095924047623553f;
static const float kAcQuant = 0.7381485255235064f;
const float kDcQuantPow = 0.83f;
const float kDcQuant = 1.095924047623553f;
const float kAcQuant = 0.7381485255235064f;
// Computes the decoded image for a given set of compression parameters.
ImageBundle RoundtripImage(const FrameHeader& frame_header,
const Image3F& opsin, PassesEncoderState* enc_state,
const JxlCmsInterface& cms, ThreadPool* pool) {
StatusOr<ImageBundle> RoundtripImage(const FrameHeader& frame_header,
const Image3F& opsin,
PassesEncoderState* enc_state,
const JxlCmsInterface& cms,
ThreadPool* pool) {
std::unique_ptr<PassesDecoderState> dec_state =
jxl::make_unique<PassesDecoderState>();
JXL_CHECK(dec_state->output_encoding_info.SetFromMetadata(
@ -775,7 +786,8 @@ ImageBundle RoundtripImage(const FrameHeader& frame_header,
size_t num_special_frames = enc_state->special_frames.size();
size_t num_passes = enc_state->progressive_splitter.GetNumPasses();
ModularFrameEncoder modular_frame_encoder(frame_header, enc_state->cparams);
ModularFrameEncoder modular_frame_encoder(frame_header, enc_state->cparams,
false);
JXL_CHECK(InitializePassesEncoder(frame_header, opsin, Rect(opsin), cms, pool,
enc_state, &modular_frame_encoder,
nullptr));
@ -784,7 +796,9 @@ ImageBundle RoundtripImage(const FrameHeader& frame_header,
ImageBundle decoded(&enc_state->shared.metadata->m);
decoded.origin = frame_header.frame_origin;
decoded.SetFromImage(Image3F(opsin.xsize(), opsin.ysize()),
JXL_ASSIGN_OR_RETURN(Image3F tmp,
Image3F::Create(opsin.xsize(), opsin.ysize()));
decoded.SetFromImage(std::move(tmp),
dec_state->output_encoding_info.color_encoding);
PassesDecoderState::PipelineOptions options;
@ -806,8 +820,10 @@ ImageBundle RoundtripImage(const FrameHeader& frame_header,
group_dec_caches = hwy::MakeUniqueAlignedArray<GroupDecCache>(num_threads);
return true;
};
std::atomic<bool> has_error{false};
const auto process_group = [&](const uint32_t group_index,
const size_t thread) {
if (has_error) return;
if (frame_header.loop_filter.epf_iters > 0) {
ComputeSigma(frame_header.loop_filter,
dec_state->shared->frame_dim.BlockGroupRect(group_index),
@ -822,10 +838,14 @@ ImageBundle RoundtripImage(const FrameHeader& frame_header,
std::pair<ImageF*, Rect> ri = input.GetBuffer(3 + c);
FillPlane(0.0f, ri.first, ri.second);
}
input.Done();
if (!input.Done()) {
has_error = true;
return;
}
};
JXL_CHECK(RunOnPool(pool, 0, num_groups, allocate_storage, process_group,
"AQ loop"));
if (has_error) return JXL_FAILURE("AQ loop failure");
// Ensure we don't create any new special frames.
enc_state->special_frames.resize(num_special_frames);
@ -835,18 +855,18 @@ ImageBundle RoundtripImage(const FrameHeader& frame_header,
constexpr int kMaxButteraugliIters = 4;
void FindBestQuantization(const FrameHeader& frame_header,
const Image3F& linear, const Image3F& opsin,
ImageF& quant_field, PassesEncoderState* enc_state,
const JxlCmsInterface& cms, ThreadPool* pool,
AuxOut* aux_out) {
Status FindBestQuantization(const FrameHeader& frame_header,
const Image3F& linear, const Image3F& opsin,
ImageF& quant_field, PassesEncoderState* enc_state,
const JxlCmsInterface& cms, ThreadPool* pool,
AuxOut* aux_out) {
const CompressParams& cparams = enc_state->cparams;
if (cparams.resampling > 1 &&
cparams.original_butteraugli_distance <= 4.0 * cparams.resampling) {
// For downsampled opsin image, the butteraugli based adaptive quantization
// loop would only make the size bigger without improving the distance much,
// so in this case we enable it only for very high butteraugli targets.
return;
return true;
}
Quantizer& quantizer = enc_state->shared.quantizer;
ImageI& raw_quant_field = enc_state->shared.raw_quant_field;
@ -863,10 +883,13 @@ void FindBestQuantization(const FrameHeader& frame_header,
AdjustQuantField(enc_state->shared.ac_strategy, Rect(quant_field),
original_butteraugli, &quant_field);
ImageF tile_distmap;
ImageF initial_quant_field(quant_field.xsize(), quant_field.ysize());
JXL_ASSIGN_OR_RETURN(
ImageF initial_quant_field,
ImageF::Create(quant_field.xsize(), quant_field.ysize()));
CopyImageTo(quant_field, &initial_quant_field);
float initial_qf_min, initial_qf_max;
float initial_qf_min;
float initial_qf_max;
ImageMinMax(initial_quant_field, &initial_qf_min, &initial_qf_max);
float initial_qf_ratio = initial_qf_max / initial_qf_min;
float qf_max_deviation_low = std::sqrt(250 / initial_qf_ratio);
@ -893,8 +916,9 @@ void FindBestQuantization(const FrameHeader& frame_header,
}
}
quantizer.SetQuantField(initial_quant_dc, quant_field, &raw_quant_field);
ImageBundle dec_linear =
RoundtripImage(frame_header, opsin, enc_state, cms, pool);
JXL_ASSIGN_OR_RETURN(
ImageBundle dec_linear,
RoundtripImage(frame_header, opsin, enc_state, cms, pool));
float score;
ImageF diffmap;
JXL_CHECK(comparator.CompareWith(dec_linear, &diffmap, &score));
@ -902,16 +926,19 @@ void FindBestQuantization(const FrameHeader& frame_header,
score = -score;
ScaleImage(-1.0f, &diffmap);
}
tile_distmap = TileDistMap(diffmap, 8 * cparams.resampling, 0,
enc_state->shared.ac_strategy);
JXL_ASSIGN_OR_RETURN(tile_distmap,
TileDistMap(diffmap, 8 * cparams.resampling, 0,
enc_state->shared.ac_strategy));
if (JXL_DEBUG_ADAPTIVE_QUANTIZATION && WantDebugOutput(cparams)) {
DumpImage(cparams, ("dec" + ToString(i)).c_str(), *dec_linear.color());
DumpHeatmaps(cparams, aux_out, butteraugli_target, quant_field,
tile_distmap, diffmap);
JXL_RETURN_IF_ERROR(DumpImage(cparams, ("dec" + ToString(i)).c_str(),
*dec_linear.color()));
JXL_RETURN_IF_ERROR(DumpHeatmaps(cparams, aux_out, butteraugli_target,
quant_field, tile_distmap, diffmap));
}
if (aux_out != nullptr) ++aux_out->num_butteraugli_iters;
if (JXL_DEBUG_ADAPTIVE_QUANTIZATION) {
float minval, maxval;
float minval;
float maxval;
ImageMinMax(quant_field, &minval, &maxval);
printf("\nButteraugli iter: %d/%d\n", i, kMaxButteraugliIters);
printf("Butteraugli distance: %f (target = %f)\n", score,
@ -1001,13 +1028,14 @@ void FindBestQuantization(const FrameHeader& frame_header,
}
}
quantizer.SetQuantField(initial_quant_dc, quant_field, &raw_quant_field);
return true;
}
void FindBestQuantizationMaxError(const FrameHeader& frame_header,
const Image3F& opsin, ImageF& quant_field,
PassesEncoderState* enc_state,
const JxlCmsInterface& cms, ThreadPool* pool,
AuxOut* aux_out) {
Status FindBestQuantizationMaxError(const FrameHeader& frame_header,
const Image3F& opsin, ImageF& quant_field,
PassesEncoderState* enc_state,
const JxlCmsInterface& cms,
ThreadPool* pool, AuxOut* aux_out) {
// TODO(szabadka): Make this work for non-opsin color spaces.
const CompressParams& cparams = enc_state->cparams;
Quantizer& quantizer = enc_state->shared.quantizer;
@ -1026,12 +1054,15 @@ void FindBestQuantizationMaxError(const FrameHeader& frame_header,
for (int i = 0; i < kMaxButteraugliIters + 1; ++i) {
quantizer.SetQuantField(initial_quant_dc, quant_field, &raw_quant_field);
if (JXL_DEBUG_ADAPTIVE_QUANTIZATION && aux_out) {
DumpXybImage(cparams, ("ops" + ToString(i)).c_str(), opsin);
JXL_RETURN_IF_ERROR(
DumpXybImage(cparams, ("ops" + ToString(i)).c_str(), opsin));
}
ImageBundle decoded =
RoundtripImage(frame_header, opsin, enc_state, cms, pool);
JXL_ASSIGN_OR_RETURN(
ImageBundle decoded,
RoundtripImage(frame_header, opsin, enc_state, cms, pool));
if (JXL_DEBUG_ADAPTIVE_QUANTIZATION && aux_out) {
DumpXybImage(cparams, ("dec" + ToString(i)).c_str(), *decoded.color());
JXL_RETURN_IF_ERROR(DumpXybImage(cparams, ("dec" + ToString(i)).c_str(),
*decoded.color()));
}
for (size_t by = 0; by < enc_state->shared.frame_dim.ysize_blocks; by++) {
AcStrategyRow ac_strategy_row =
@ -1073,6 +1104,7 @@ void FindBestQuantizationMaxError(const FrameHeader& frame_header,
}
}
quantizer.SetQuantField(initial_quant_dc, quant_field, &raw_quant_field);
return true;
}
} // namespace
@ -1142,28 +1174,31 @@ float InitialQuantDC(float butteraugli_target) {
return std::min(kDcQuant / butteraugli_target_dc, 50.f);
}
ImageF InitialQuantField(const float butteraugli_target, const Image3F& opsin,
const Rect& rect, ThreadPool* pool, float rescale,
ImageF* mask, ImageF* mask1x1) {
StatusOr<ImageF> InitialQuantField(const float butteraugli_target,
const Image3F& opsin, const Rect& rect,
ThreadPool* pool, float rescale,
ImageF* mask, ImageF* mask1x1) {
const float quant_ac = kAcQuant / butteraugli_target;
return HWY_DYNAMIC_DISPATCH(AdaptiveQuantizationMap)(
butteraugli_target, opsin, rect, quant_ac * rescale, pool, mask, mask1x1);
}
void FindBestQuantizer(const FrameHeader& frame_header, const Image3F* linear,
const Image3F& opsin, ImageF& quant_field,
PassesEncoderState* enc_state,
const JxlCmsInterface& cms, ThreadPool* pool,
AuxOut* aux_out, double rescale) {
Status FindBestQuantizer(const FrameHeader& frame_header, const Image3F* linear,
const Image3F& opsin, ImageF& quant_field,
PassesEncoderState* enc_state,
const JxlCmsInterface& cms, ThreadPool* pool,
AuxOut* aux_out, double rescale) {
const CompressParams& cparams = enc_state->cparams;
if (cparams.max_error_mode) {
FindBestQuantizationMaxError(frame_header, opsin, quant_field, enc_state,
cms, pool, aux_out);
JXL_RETURN_IF_ERROR(FindBestQuantizationMaxError(
frame_header, opsin, quant_field, enc_state, cms, pool, aux_out));
} else if (linear && cparams.speed_tier <= SpeedTier::kKitten) {
// Normal encoding to a butteraugli score.
FindBestQuantization(frame_header, *linear, opsin, quant_field, enc_state,
cms, pool, aux_out);
JXL_RETURN_IF_ERROR(FindBestQuantization(frame_header, *linear, opsin,
quant_field, enc_state, cms, pool,
aux_out));
}
return true;
}
} // namespace jxl

Просмотреть файл

@ -31,10 +31,11 @@ struct AuxOut;
// of the input image, while a value less than 1.0 indicates that less
// fine-grained quantization should be enough. Returns a mask, too, which
// can later be used to make better decisions about ac strategy.
ImageF InitialQuantField(float butteraugli_target, const Image3F& opsin,
const Rect& rect, ThreadPool* pool, float rescale,
ImageF* initial_quant_mask,
ImageF* initial_quant_mask1x1);
StatusOr<ImageF> InitialQuantField(float butteraugli_target,
const Image3F& opsin, const Rect& rect,
ThreadPool* pool, float rescale,
ImageF* initial_quant_mask,
ImageF* initial_quant_mask1x1);
float InitialQuantDC(float butteraugli_target);
@ -45,11 +46,11 @@ void AdjustQuantField(const AcStrategyImage& ac_strategy, const Rect& rect,
// quant_field. Also computes the dequant_map corresponding to the given
// dequant_float_map and chosen quantization levels.
// `linear` is only used in Kitten mode or slower.
void FindBestQuantizer(const FrameHeader& frame_header, const Image3F* linear,
const Image3F& opsin, ImageF& quant_field,
PassesEncoderState* enc_state,
const JxlCmsInterface& cms, ThreadPool* pool,
AuxOut* aux_out, double rescale = 1.0);
Status FindBestQuantizer(const FrameHeader& frame_header, const Image3F* linear,
const Image3F& opsin, ImageF& quant_field,
PassesEncoderState* enc_state,
const JxlCmsInterface& cms, ThreadPool* pool,
AuxOut* aux_out, double rescale = 1.0);
} // namespace jxl

63
third_party/jpeg-xl/lib/jxl/enc_ans.cc поставляемый
Просмотреть файл

@ -10,6 +10,7 @@
#include <algorithm>
#include <array>
#include <cmath>
#include <cstdint>
#include <limits>
#include <numeric>
#include <type_traits>
@ -20,12 +21,15 @@
#include "lib/jxl/ans_common.h"
#include "lib/jxl/base/bits.h"
#include "lib/jxl/base/fast_math-inl.h"
#include "lib/jxl/base/status.h"
#include "lib/jxl/dec_ans.h"
#include "lib/jxl/enc_ans_params.h"
#include "lib/jxl/enc_aux_out.h"
#include "lib/jxl/enc_cluster.h"
#include "lib/jxl/enc_context_map.h"
#include "lib/jxl/enc_fields.h"
#include "lib/jxl/enc_huffman.h"
#include "lib/jxl/enc_params.h"
#include "lib/jxl/fields.h"
namespace jxl {
@ -553,8 +557,7 @@ void ChooseUintConfigs(const HistogramParams& params,
std::vector<Histogram>* clustered_histograms,
EntropyEncodingData* codes, size_t* log_alpha_size) {
codes->uint_config.resize(clustered_histograms->size());
if (params.streaming_mode ||
params.uint_method == HistogramParams::HybridUintMethod::kNone) {
if (params.uint_method == HistogramParams::HybridUintMethod::kNone) {
return;
}
if (params.uint_method == HistogramParams::HybridUintMethod::k000) {
@ -570,6 +573,12 @@ void ChooseUintConfigs(const HistogramParams& params,
return;
}
// If the uint config is adaptive, just stick with the default in streaming
// mode.
if (params.streaming_mode) {
return;
}
// Brute-force method that tries a few options.
std::vector<HybridUintConfig> configs;
if (params.uint_method == HistogramParams::HybridUintMethod::kBest) {
@ -1765,7 +1774,8 @@ void WriteTokens(const std::vector<Token>& tokens,
const EntropyEncodingData& codes,
const std::vector<uint8_t>& context_map, size_t context_offset,
BitWriter* writer, size_t layer, AuxOut* aux_out) {
BitWriter::Allotment allotment(writer, 32 * tokens.size() + 32 * 1024 * 4);
// Theoretically, we could have 15 prefix code bits + 31 extra bits.
BitWriter::Allotment allotment(writer, 46 * tokens.size() + 32 * 1024 * 4);
size_t num_extra_bits =
WriteTokens(tokens, codes, context_map, context_offset, writer);
allotment.ReclaimAndCharge(writer, layer, aux_out);
@ -1779,4 +1789,51 @@ void SetANSFuzzerFriendly(bool ans_fuzzer_friendly) {
ans_fuzzer_friendly_ = ans_fuzzer_friendly;
#endif
}
HistogramParams HistogramParams::ForModular(
const CompressParams& cparams,
const std::vector<uint8_t>& extra_dc_precision, bool streaming_mode) {
HistogramParams params;
params.streaming_mode = streaming_mode;
if (cparams.speed_tier > SpeedTier::kKitten) {
params.clustering = HistogramParams::ClusteringType::kFast;
params.ans_histogram_strategy =
cparams.speed_tier > SpeedTier::kThunder
? HistogramParams::ANSHistogramStrategy::kFast
: HistogramParams::ANSHistogramStrategy::kApproximate;
params.lz77_method =
cparams.decoding_speed_tier >= 3 && cparams.modular_mode
? (cparams.speed_tier >= SpeedTier::kFalcon
? HistogramParams::LZ77Method::kRLE
: HistogramParams::LZ77Method::kLZ77)
: HistogramParams::LZ77Method::kNone;
// Near-lossless DC, as well as modular mode, require choosing hybrid uint
// more carefully.
if ((!extra_dc_precision.empty() && extra_dc_precision[0] != 0) ||
(cparams.modular_mode && cparams.speed_tier < SpeedTier::kCheetah)) {
params.uint_method = HistogramParams::HybridUintMethod::kFast;
} else {
params.uint_method = HistogramParams::HybridUintMethod::kNone;
}
} else if (cparams.speed_tier <= SpeedTier::kTortoise) {
params.lz77_method = HistogramParams::LZ77Method::kOptimal;
} else {
params.lz77_method = HistogramParams::LZ77Method::kLZ77;
}
if (cparams.decoding_speed_tier >= 1) {
params.max_histograms = 12;
}
if (cparams.decoding_speed_tier >= 1 && cparams.responsive) {
params.lz77_method = cparams.speed_tier >= SpeedTier::kCheetah
? HistogramParams::LZ77Method::kRLE
: cparams.speed_tier >= SpeedTier::kKitten
? HistogramParams::LZ77Method::kLZ77
: HistogramParams::LZ77Method::kOptimal;
}
if (cparams.decoding_speed_tier >= 2 && cparams.responsive) {
params.uint_method = HistogramParams::HybridUintMethod::k000;
params.force_huffman = true;
}
return params;
}
} // namespace jxl

11
third_party/jpeg-xl/lib/jxl/enc_ans_params.h поставляемый
Просмотреть файл

@ -11,10 +11,15 @@
#include <stdint.h>
#include <stdlib.h>
#include "lib/jxl/enc_params.h"
#include <vector>
#include "lib/jxl/common.h"
namespace jxl {
// Forward declaration to break include cycle.
struct CompressParams;
// RebalanceHistogram requires a signed type.
using ANSHistBin = int32_t;
@ -65,6 +70,10 @@ struct HistogramParams {
}
}
static HistogramParams ForModular(
const CompressParams& cparams,
const std::vector<uint8_t>& extra_dc_precision, bool streaming_mode);
ClusteringType clustering = ClusteringType::kBest;
HybridUintMethod uint_method = HybridUintMethod::kBest;
LZ77Method lz77_method = LZ77Method::kRLE;

Просмотреть файл

@ -17,16 +17,10 @@
#include "lib/jxl/ac_strategy.h"
#include "lib/jxl/base/compiler_specific.h"
#include "lib/jxl/base/data_parallel.h"
#include "lib/jxl/base/status.h"
#include "lib/jxl/chroma_from_luma.h"
#include "lib/jxl/enc_adaptive_quantization.h"
#include "lib/jxl/enc_params.h"
#include "lib/jxl/image.h"
#include "lib/jxl/image_bundle.h"
#include "lib/jxl/image_ops.h"
#include "lib/jxl/quant_weights.h"
#include "lib/jxl/quantizer.h"
HWY_BEFORE_NAMESPACE();
namespace jxl {
@ -40,11 +34,12 @@ using hwy::HWY_NAMESPACE::Mul;
using hwy::HWY_NAMESPACE::MulAdd;
using hwy::HWY_NAMESPACE::Sqrt;
void ProcessTile(const CompressParams& cparams, const FrameHeader& frame_header,
const Image3F& opsin, const Rect& opsin_rect,
const ImageF& quant_field, const AcStrategyImage& ac_strategy,
ImageB* epf_sharpness, const Rect& rect,
ArControlFieldHeuristics::TempImages* temp_image) {
Status ProcessTile(const CompressParams& cparams,
const FrameHeader& frame_header, const Image3F& opsin,
const Rect& opsin_rect, const ImageF& quant_field,
const AcStrategyImage& ac_strategy, ImageB* epf_sharpness,
const Rect& rect,
ArControlFieldHeuristics::TempImages* temp_image) {
JXL_ASSERT(opsin_rect.x0() % 8 == 0);
JXL_ASSERT(opsin_rect.y0() % 8 == 0);
JXL_ASSERT(opsin_rect.xsize() % 8 == 0);
@ -54,7 +49,7 @@ void ProcessTile(const CompressParams& cparams, const FrameHeader& frame_header,
cparams.speed_tier > SpeedTier::kWombat ||
frame_header.loop_filter.epf_iters == 0) {
FillPlane(static_cast<uint8_t>(4), epf_sharpness, rect);
return;
return true;
}
// Likely better to have a higher X weight, like:
@ -70,7 +65,7 @@ void ProcessTile(const CompressParams& cparams, const FrameHeader& frame_header,
size_t by1 = by0 + rect.ysize();
size_t bx0 = opsin_rect.x0() / 8 + rect.x0();
size_t bx1 = bx0 + rect.xsize();
temp_image->InitOnce();
JXL_RETURN_IF_ERROR(temp_image->InitOnce());
ImageF& laplacian_sqrsum = temp_image->laplacian_sqrsum;
// Calculate the L2 of the 3x3 Laplacian in an integral transform
// (for example 32x32 dct). This relates to transforms ability
@ -295,6 +290,7 @@ void ProcessTile(const CompressParams& cparams, const FrameHeader& frame_header,
}
}
}
return true;
}
} // namespace
@ -307,14 +303,14 @@ HWY_AFTER_NAMESPACE();
namespace jxl {
HWY_EXPORT(ProcessTile);
void ArControlFieldHeuristics::RunRect(
Status ArControlFieldHeuristics::RunRect(
const CompressParams& cparams, const FrameHeader& frame_header,
const Rect& block_rect, const Image3F& opsin, const Rect& opsin_rect,
const ImageF& quant_field, const AcStrategyImage& ac_strategy,
ImageB* epf_sharpness, size_t thread) {
HWY_DYNAMIC_DISPATCH(ProcessTile)
(cparams, frame_header, opsin, opsin_rect, quant_field, ac_strategy,
epf_sharpness, block_rect, &temp_images[thread]);
return HWY_DYNAMIC_DISPATCH(ProcessTile)(
cparams, frame_header, opsin, opsin_rect, quant_field, ac_strategy,
epf_sharpness, block_rect, &temp_images[thread]);
}
} // namespace jxl

Просмотреть файл

@ -21,11 +21,15 @@ struct PassesEncoderState;
struct ArControlFieldHeuristics {
struct TempImages {
void InitOnce() {
if (laplacian_sqrsum.xsize() != 0) return;
laplacian_sqrsum = ImageF(kEncTileDim + 4, kEncTileDim + 4);
sqrsum_00 = ImageF(kEncTileDim / 4, kEncTileDim / 4);
sqrsum_22 = ImageF(kEncTileDim / 4 + 1, kEncTileDim / 4 + 1);
Status InitOnce() {
if (laplacian_sqrsum.xsize() != 0) return true;
JXL_ASSIGN_OR_RETURN(laplacian_sqrsum,
ImageF::Create(kEncTileDim + 4, kEncTileDim + 4));
JXL_ASSIGN_OR_RETURN(sqrsum_00,
ImageF::Create(kEncTileDim / 4, kEncTileDim / 4));
JXL_ASSIGN_OR_RETURN(
sqrsum_22, ImageF::Create(kEncTileDim / 4 + 1, kEncTileDim / 4 + 1));
return true;
}
ImageF laplacian_sqrsum;
@ -37,11 +41,11 @@ struct ArControlFieldHeuristics {
temp_images.resize(num_threads);
}
void RunRect(const CompressParams& cparams, const FrameHeader& frame_header,
const Rect& block_rect, const Image3F& opsin,
const Rect& opsin_rect, const ImageF& quant_field,
const AcStrategyImage& ac_strategy, ImageB* epf_sharpness,
size_t thread);
Status RunRect(const CompressParams& cparams, const FrameHeader& frame_header,
const Rect& block_rect, const Image3F& opsin,
const Rect& opsin_rect, const ImageF& quant_field,
const AcStrategyImage& ac_strategy, ImageB* epf_sharpness,
size_t thread);
std::vector<TempImages> temp_images;
};

Просмотреть файл

@ -5,9 +5,7 @@
#include "lib/jxl/enc_butteraugli_comparator.h"
#include <algorithm>
#include <vector>
#include "lib/jxl/base/status.h"
#include "lib/jxl/enc_image_bundle.h"
namespace jxl {
@ -24,9 +22,8 @@ Status JxlButteraugliComparator::SetReferenceImage(const ImageBundle& ref) {
/*pool=*/nullptr, &store, &ref_linear_srgb)) {
return false;
}
comparator_.reset(
new ButteraugliComparator(ref_linear_srgb->color(), params_));
JXL_ASSIGN_OR_RETURN(comparator_, ButteraugliComparator::Make(
ref_linear_srgb->color(), params_));
xsize_ = ref.xsize();
ysize_ = ref.ysize();
return true;
@ -34,7 +31,8 @@ Status JxlButteraugliComparator::SetReferenceImage(const ImageBundle& ref) {
Status JxlButteraugliComparator::SetLinearReferenceImage(
const Image3F& linear) {
comparator_.reset(new ButteraugliComparator(linear, params_));
JXL_ASSIGN_OR_RETURN(comparator_,
ButteraugliComparator::Make(linear, params_));
xsize_ = linear.xsize();
ysize_ = linear.ysize();
return true;
@ -58,8 +56,9 @@ Status JxlButteraugliComparator::CompareWith(const ImageBundle& actual,
return false;
}
ImageF temp_diffmap(xsize_, ysize_);
comparator_->Diffmap(actual_linear_srgb->color(), temp_diffmap);
JXL_ASSIGN_OR_RETURN(ImageF temp_diffmap, ImageF::Create(xsize_, ysize_));
JXL_RETURN_IF_ERROR(
comparator_->Diffmap(actual_linear_srgb->color(), temp_diffmap));
if (score != nullptr) {
*score = ButteraugliScoreFromDiffmap(temp_diffmap, &params_);
@ -79,29 +78,4 @@ float JxlButteraugliComparator::BadQualityScore() const {
return ButteraugliFuzzyInverse(0.5);
}
float ButteraugliDistance(const ImageBundle& rgb0, const ImageBundle& rgb1,
const ButteraugliParams& params,
const JxlCmsInterface& cms, ImageF* distmap,
ThreadPool* pool, bool ignore_alpha) {
JxlButteraugliComparator comparator(params, cms);
return ComputeScore(rgb0, rgb1, &comparator, cms, distmap, pool,
ignore_alpha);
}
float ButteraugliDistance(const std::vector<ImageBundle>& frames0,
const std::vector<ImageBundle>& frames1,
const ButteraugliParams& params,
const JxlCmsInterface& cms, ImageF* distmap,
ThreadPool* pool) {
JxlButteraugliComparator comparator(params, cms);
JXL_ASSERT(frames0.size() == frames1.size());
float max_dist = 0.0f;
for (size_t i = 0; i < frames0.size(); ++i) {
max_dist = std::max(
max_dist,
ComputeScore(frames0[i], frames1[i], &comparator, cms, distmap, pool));
}
return max_dist;
}
} // namespace jxl

Просмотреть файл

@ -10,9 +10,7 @@
#include <stddef.h>
#include <memory>
#include <vector>
#include "lib/jxl/base/data_parallel.h"
#include "lib/jxl/base/status.h"
#include "lib/jxl/butteraugli/butteraugli.h"
#include "lib/jxl/enc_comparator.h"
@ -43,20 +41,6 @@ class JxlButteraugliComparator : public Comparator {
size_t ysize_ = 0;
};
// Returns the butteraugli distance between rgb0 and rgb1.
// If distmap is not null, it must be the same size as rgb0 and rgb1.
float ButteraugliDistance(const ImageBundle& rgb0, const ImageBundle& rgb1,
const ButteraugliParams& params,
const JxlCmsInterface& cms, ImageF* distmap = nullptr,
ThreadPool* pool = nullptr,
bool ignore_alpha = false);
float ButteraugliDistance(const std::vector<ImageBundle>& frames0,
const std::vector<ImageBundle>& frames1,
const ButteraugliParams& params,
const JxlCmsInterface& cms, ImageF* distmap = nullptr,
ThreadPool* pool = nullptr);
} // namespace jxl
#endif // LIB_JXL_ENC_BUTTERAUGLI_COMPARATOR_H_

50
third_party/jpeg-xl/lib/jxl/enc_cache.cc поставляемый
Просмотреть файл

@ -8,15 +8,14 @@
#include <stddef.h>
#include <stdint.h>
#include <type_traits>
#include <memory>
#include "lib/jxl/ac_strategy.h"
#include "lib/jxl/base/common.h"
#include "lib/jxl/base/compiler_specific.h"
#include "lib/jxl/base/span.h"
#include "lib/jxl/base/status.h"
#include "lib/jxl/color_encoding_internal.h"
#include "lib/jxl/compressed_dc.h"
#include "lib/jxl/dct_scales.h"
#include "lib/jxl/dct_util.h"
#include "lib/jxl/dec_frame.h"
#include "lib/jxl/enc_aux_out.h"
@ -50,8 +49,11 @@ Status InitializePassesEncoder(const FrameHeader& frame_header,
for (size_t i = enc_state->coeffs.size();
i < frame_header.passes.num_passes; i++) {
// Allocate enough coefficients for each group on every row.
enc_state->coeffs.emplace_back(make_unique<ACImageT<int32_t>>(
kGroupDim * kGroupDim, shared.frame_dim.num_groups));
JXL_ASSIGN_OR_RETURN(
std::unique_ptr<ACImageT<int32_t>> coeffs,
ACImageT<int32_t>::Make(kGroupDim * kGroupDim,
shared.frame_dim.num_groups));
enc_state->coeffs.emplace_back(std::move(coeffs));
}
}
while (enc_state->coeffs.size() > frame_header.passes.num_passes) {
@ -65,7 +67,9 @@ Status InitializePassesEncoder(const FrameHeader& frame_header,
shared.quantizer.RecomputeFromGlobalScale();
}
Image3F dc(shared.frame_dim.xsize_blocks, shared.frame_dim.ysize_blocks);
JXL_ASSIGN_OR_RETURN(Image3F dc,
Image3F::Create(shared.frame_dim.xsize_blocks,
shared.frame_dim.ysize_blocks));
JXL_RETURN_IF_ERROR(RunOnPool(
pool, 0, shared.frame_dim.num_groups, ThreadPool::NoInit,
[&](size_t group_idx, size_t _) {
@ -120,7 +124,8 @@ Status InitializePassesEncoder(const FrameHeader& frame_header,
std::vector<ImageF> extra_channels;
extra_channels.reserve(ib.metadata()->extra_channel_info.size());
for (size_t i = 0; i < ib.metadata()->extra_channel_info.size(); i++) {
extra_channels.emplace_back(ib.xsize(), ib.ysize());
JXL_ASSIGN_OR_RETURN(ImageF ch, ImageF::Create(ib.xsize(), ib.ysize()));
extra_channels.emplace_back(std::move(ch));
// Must initialize the image with data to not affect blending with
// uninitialized memory.
// TODO(lode): dc_level must copy and use the real extra channels
@ -168,32 +173,41 @@ Status InitializePassesEncoder(const FrameHeader& frame_header,
// outputs multiple frames, this assumption could be wrong.
const Image3F& dc_frame =
dec_state->shared->dc_frames[frame_header.dc_level];
shared.dc_storage = Image3F(dc_frame.xsize(), dc_frame.ysize());
JXL_ASSIGN_OR_RETURN(shared.dc_storage,
Image3F::Create(dc_frame.xsize(), dc_frame.ysize()));
CopyImageTo(dc_frame, &shared.dc_storage);
ZeroFillImage(&shared.quant_dc);
shared.dc = &shared.dc_storage;
JXL_CHECK(encoded_size == 0);
} else {
std::atomic<bool> has_error{false};
auto compute_dc_coeffs = [&](int group_index, int /* thread */) {
if (has_error) return;
const Rect r = enc_state->shared.frame_dim.DCGroupRect(group_index);
int modular_group_index = group_index;
if (enc_state->streaming_mode) {
JXL_ASSERT(group_index == 0);
modular_group_index = enc_state->dc_group_index;
}
modular_frame_encoder->AddVarDCTDC(
frame_header, dc, r, modular_group_index,
enc_state->cparams.speed_tier < SpeedTier::kFalcon, enc_state,
/*jpeg_transcode=*/false);
if (!modular_frame_encoder->AddVarDCTDC(
frame_header, dc, r, modular_group_index,
enc_state->cparams.speed_tier < SpeedTier::kFalcon, enc_state,
/*jpeg_transcode=*/false)) {
has_error = true;
return;
}
};
JXL_RETURN_IF_ERROR(RunOnPool(pool, 0, shared.frame_dim.num_dc_groups,
ThreadPool::NoInit, compute_dc_coeffs,
"Compute DC coeffs"));
if (has_error) return JXL_FAILURE("Compute DC coeffs failed");
// TODO(veluca): this is only useful in tests and if inspection is enabled.
if (!(frame_header.flags & FrameHeader::kSkipAdaptiveDCSmoothing)) {
AdaptiveDCSmoothing(shared.quantizer.MulDC(), &shared.dc_storage, pool);
JXL_RETURN_IF_ERROR(AdaptiveDCSmoothing(shared.quantizer.MulDC(),
&shared.dc_storage, pool));
}
}
std::atomic<bool> has_error{false};
auto compute_ac_meta = [&](int group_index, int /* thread */) {
const Rect r = enc_state->shared.frame_dim.DCGroupRect(group_index);
int modular_group_index = group_index;
@ -201,13 +215,17 @@ Status InitializePassesEncoder(const FrameHeader& frame_header,
JXL_ASSERT(group_index == 0);
modular_group_index = enc_state->dc_group_index;
}
modular_frame_encoder->AddACMetadata(r, modular_group_index,
/*jpeg_transcode=*/false, enc_state);
if (!modular_frame_encoder->AddACMetadata(r, modular_group_index,
/*jpeg_transcode=*/false,
enc_state)) {
has_error = true;
return;
}
};
JXL_RETURN_IF_ERROR(RunOnPool(pool, 0, shared.frame_dim.num_dc_groups,
ThreadPool::NoInit, compute_ac_meta,
"Compute AC Metadata"));
if (has_error) return JXL_FAILURE("Compute AC Metadata failed");
return true;
}

Просмотреть файл

@ -9,7 +9,6 @@
#include <stdlib.h>
#include <algorithm>
#include <array>
#include <cmath>
#undef HWY_TARGET_INCLUDE
@ -18,18 +17,13 @@
#include <hwy/foreach_target.h>
#include <hwy/highway.h>
#include "lib/jxl/base/bits.h"
#include "lib/jxl/base/common.h"
#include "lib/jxl/base/span.h"
#include "lib/jxl/base/status.h"
#include "lib/jxl/cms/opsin_params.h"
#include "lib/jxl/dec_transforms-inl.h"
#include "lib/jxl/enc_aux_out.h"
#include "lib/jxl/enc_params.h"
#include "lib/jxl/enc_transforms-inl.h"
#include "lib/jxl/entropy_coder.h"
#include "lib/jxl/image_ops.h"
#include "lib/jxl/modular/encoding/encoding.h"
#include "lib/jxl/quantizer.h"
#include "lib/jxl/simd_util.h"
HWY_BEFORE_NAMESPACE();
@ -149,7 +143,8 @@ int32_t FindBestMultiplier(const float* values_m, const float* values_s,
// Derivatives are approximate due to the high amount of noise in the exact
// derivatives.
for (size_t i = 0; i < 20; i++) {
float dfpeps, dfmeps;
float dfpeps;
float dfmeps;
float df = fn.Compute(x, eps, &dfpeps, &dfmeps);
float ddf = (dfpeps - dfmeps) / (2 * eps);
float kExperimentalInsignificantStabilizer = 0.85;
@ -175,12 +170,13 @@ int32_t FindBestMultiplier(const float* values_m, const float* values_s,
return std::max(-128.0f, std::min(127.0f, roundf(x)));
}
void InitDCStorage(size_t num_blocks, ImageF* dc_values) {
Status InitDCStorage(size_t num_blocks, ImageF* dc_values) {
// First row: Y channel
// Second row: X channel
// Third row: Y channel
// Fourth row: B channel
*dc_values = ImageF(RoundUpTo(num_blocks, Lanes(df)), 4);
JXL_ASSIGN_OR_RETURN(*dc_values,
ImageF::Create(RoundUpTo(num_blocks, Lanes(df)), 4));
JXL_ASSERT(dc_values->xsize() != 0);
// Zero-fill the last lanes
@ -190,6 +186,7 @@ void InitDCStorage(size_t num_blocks, ImageF* dc_values) {
dc_values->Row(y)[x] = 0;
}
}
return true;
}
void ComputeTile(const Image3F& opsin, const Rect& opsin_rect,
@ -352,11 +349,11 @@ namespace jxl {
HWY_EXPORT(InitDCStorage);
HWY_EXPORT(ComputeTile);
void CfLHeuristics::Init(const Rect& rect) {
Status CfLHeuristics::Init(const Rect& rect) {
size_t xsize_blocks = rect.xsize() / kBlockDim;
size_t ysize_blocks = rect.ysize() / kBlockDim;
HWY_DYNAMIC_DISPATCH(InitDCStorage)
(xsize_blocks * ysize_blocks, &dc_values);
return HWY_DYNAMIC_DISPATCH(InitDCStorage)(xsize_blocks * ysize_blocks,
&dc_values);
}
void CfLHeuristics::ComputeTile(const Rect& r, const Image3F& opsin,

Просмотреть файл

@ -29,7 +29,7 @@ void ColorCorrelationMapEncodeDC(const ColorCorrelationMap& map,
AuxOut* aux_out);
struct CfLHeuristics {
void Init(const Rect& rect);
Status Init(const Rect& rect);
void PrepareForThreads(size_t num_threads) {
mem = hwy::AllocateAligned<float>(num_threads * ItemsPerThread());

1
third_party/jpeg-xl/lib/jxl/enc_cluster.h поставляемый
Просмотреть файл

@ -15,6 +15,7 @@
#include <vector>
#include "lib/jxl/ans_params.h"
#include "lib/jxl/base/common.h"
#include "lib/jxl/enc_ans_params.h"
namespace jxl {

27
third_party/jpeg-xl/lib/jxl/enc_comparator.cc поставляемый
Просмотреть файл

@ -66,9 +66,10 @@ float ComputeScoreImpl(const ImageBundle& rgb0, const ImageBundle& rgb1,
} // namespace
float ComputeScore(const ImageBundle& rgb0, const ImageBundle& rgb1,
Comparator* comparator, const JxlCmsInterface& cms,
ImageF* diffmap, ThreadPool* pool, bool ignore_alpha) {
Status ComputeScore(const ImageBundle& rgb0, const ImageBundle& rgb1,
Comparator* comparator, const JxlCmsInterface& cms,
float* score, ImageF* diffmap, ThreadPool* pool,
bool ignore_alpha) {
// Convert to linear sRGB (unless already in that space)
ImageMetadata metadata0 = *rgb0.metadata();
ImageBundle store0(&metadata0);
@ -83,25 +84,28 @@ float ComputeScore(const ImageBundle& rgb0, const ImageBundle& rgb1,
// No alpha: skip blending, only need a single call to Butteraugli.
if (ignore_alpha || (!rgb0.HasAlpha() && !rgb1.HasAlpha())) {
return ComputeScoreImpl(*linear_srgb0, *linear_srgb1, comparator, diffmap);
*score =
ComputeScoreImpl(*linear_srgb0, *linear_srgb1, comparator, diffmap);
return true;
}
// Blend on black and white backgrounds
const float black = 0.0f;
ImageBundle blended_black0 = linear_srgb0->Copy();
ImageBundle blended_black1 = linear_srgb1->Copy();
JXL_ASSIGN_OR_RETURN(ImageBundle blended_black0, linear_srgb0->Copy());
JXL_ASSIGN_OR_RETURN(ImageBundle blended_black1, linear_srgb1->Copy());
AlphaBlend(black, &blended_black0);
AlphaBlend(black, &blended_black1);
const float white = 1.0f;
ImageBundle blended_white0 = linear_srgb0->Copy();
ImageBundle blended_white1 = linear_srgb1->Copy();
JXL_ASSIGN_OR_RETURN(ImageBundle blended_white0, linear_srgb0->Copy());
JXL_ASSIGN_OR_RETURN(ImageBundle blended_white1, linear_srgb1->Copy());
AlphaBlend(white, &blended_white0);
AlphaBlend(white, &blended_white1);
ImageF diffmap_black, diffmap_white;
ImageF diffmap_black;
ImageF diffmap_white;
const float dist_black = ComputeScoreImpl(blended_black0, blended_black1,
comparator, &diffmap_black);
const float dist_white = ComputeScoreImpl(blended_white0, blended_white1,
@ -111,7 +115,7 @@ float ComputeScore(const ImageBundle& rgb0, const ImageBundle& rgb1,
if (diffmap != nullptr) {
const size_t xsize = rgb0.xsize();
const size_t ysize = rgb0.ysize();
*diffmap = ImageF(xsize, ysize);
JXL_ASSIGN_OR_RETURN(*diffmap, ImageF::Create(xsize, ysize));
for (size_t y = 0; y < ysize; ++y) {
const float* JXL_RESTRICT row_black = diffmap_black.ConstRow(y);
const float* JXL_RESTRICT row_white = diffmap_white.ConstRow(y);
@ -121,7 +125,8 @@ float ComputeScore(const ImageBundle& rgb0, const ImageBundle& rgb1,
}
}
}
return std::max(dist_black, dist_white);
*score = std::max(dist_black, dist_white);
return true;
}
} // namespace jxl

Просмотреть файл

@ -43,10 +43,10 @@ class Comparator {
// Computes the score given images in any RGB color model, optionally with
// alpha channel.
float ComputeScore(const ImageBundle& rgb0, const ImageBundle& rgb1,
Comparator* comparator, const JxlCmsInterface& cms,
ImageF* diffmap = nullptr, ThreadPool* pool = nullptr,
bool ignore_alpha = false);
Status ComputeScore(const ImageBundle& rgb0, const ImageBundle& rgb1,
Comparator* comparator, const JxlCmsInterface& cms,
float* score, ImageF* diffmap = nullptr,
ThreadPool* pool = nullptr, bool ignore_alpha = false);
} // namespace jxl

Просмотреть файл

@ -18,6 +18,7 @@
#include "lib/jxl/enc_ans.h"
#include "lib/jxl/enc_aux_out.h"
#include "lib/jxl/entropy_coder.h"
#include "lib/jxl/fields.h"
#include "lib/jxl/pack_signed.h"
namespace jxl {

Просмотреть файл

@ -18,32 +18,29 @@ namespace jxl {
namespace {
template <typename From>
Plane<float> ConvertToFloat(const Plane<From>& from) {
StatusOr<Image3F> ConvertToFloat(const Image3<From>& from) {
float factor = 1.0f / std::numeric_limits<From>::max();
if (std::is_same<From, double>::value || std::is_same<From, float>::value) {
factor = 1.0f;
}
Plane<float> to(from.xsize(), from.ysize());
for (size_t y = 0; y < from.ysize(); ++y) {
const From* const JXL_RESTRICT row_from = from.Row(y);
float* const JXL_RESTRICT row_to = to.Row(y);
for (size_t x = 0; x < from.xsize(); ++x) {
row_to[x] = row_from[x] * factor;
JXL_ASSIGN_OR_RETURN(Image3F to, Image3F::Create(from.xsize(), from.ysize()));
for (size_t c = 0; c < 3; ++c) {
for (size_t y = 0; y < from.ysize(); ++y) {
const From* const JXL_RESTRICT row_from = from.ConstPlaneRow(c, y);
float* const JXL_RESTRICT row_to = to.PlaneRow(c, y);
for (size_t x = 0; x < from.xsize(); ++x) {
row_to[x] = row_from[x] * factor;
}
}
}
return to;
}
template <typename From>
Image3F ConvertToFloat(const Image3<From>& from) {
return Image3F(ConvertToFloat(from.Plane(0)), ConvertToFloat(from.Plane(1)),
ConvertToFloat(from.Plane(2)));
}
template <typename T>
void DumpImageT(const CompressParams& cparams, const char* label,
const ColorEncoding& color_encoding, const Image3<T>& image) {
if (!cparams.debug_image) return;
Image3F float_image = ConvertToFloat(image);
Status DumpImageT(const CompressParams& cparams, const char* label,
const ColorEncoding& color_encoding, const Image3<T>& image) {
if (!cparams.debug_image) return true;
JXL_ASSIGN_OR_RETURN(Image3F float_image, ConvertToFloat(image));
JxlColorEncoding color = color_encoding.ToExternal();
size_t num_pixels = 3 * image.xsize() * image.ysize();
std::vector<uint16_t> pixels(num_pixels);
@ -53,18 +50,20 @@ void DumpImageT(const CompressParams& cparams, const char* label,
}
JXL_CHECK(ConvertChannelsToExternal(
channels, 3, 16, false, JXL_BIG_ENDIAN, 6 * image.xsize(), nullptr,
&pixels[0], 2 * num_pixels, PixelCallback(), Orientation::kIdentity));
pixels.data(), 2 * num_pixels, PixelCallback(), Orientation::kIdentity));
(*cparams.debug_image)(cparams.debug_image_opaque, label, image.xsize(),
image.ysize(), &color, &pixels[0]);
image.ysize(), &color, pixels.data());
return true;
}
template <typename T>
void DumpPlaneNormalizedT(const CompressParams& cparams, const char* label,
const Plane<T>& image) {
Status DumpPlaneNormalizedT(const CompressParams& cparams, const char* label,
const Plane<T>& image) {
T min;
T max;
ImageMinMax(image, &min, &max);
Image3B normalized(image.xsize(), image.ysize());
JXL_ASSIGN_OR_RETURN(Image3B normalized,
Image3B::Create(image.xsize(), image.ysize()));
for (size_t c = 0; c < 3; ++c) {
float mul = min == max ? 0 : (255.0f / (max - min));
for (size_t y = 0; y < image.ysize(); ++y) {
@ -75,41 +74,42 @@ void DumpPlaneNormalizedT(const CompressParams& cparams, const char* label,
}
}
}
DumpImageT(cparams, label, ColorEncoding::SRGB(), normalized);
return DumpImageT(cparams, label, ColorEncoding::SRGB(), normalized);
}
} // namespace
void DumpImage(const CompressParams& cparams, const char* label,
const Image3<float>& image) {
DumpImageT(cparams, label, ColorEncoding::SRGB(), image);
Status DumpImage(const CompressParams& cparams, const char* label,
const Image3<float>& image) {
return DumpImageT(cparams, label, ColorEncoding::SRGB(), image);
}
void DumpImage(const CompressParams& cparams, const char* label,
const Image3<uint8_t>& image) {
DumpImageT(cparams, label, ColorEncoding::SRGB(), image);
Status DumpImage(const CompressParams& cparams, const char* label,
const Image3<uint8_t>& image) {
return DumpImageT(cparams, label, ColorEncoding::SRGB(), image);
}
void DumpXybImage(const CompressParams& cparams, const char* label,
const Image3F& image) {
if (!cparams.debug_image) return;
Status DumpXybImage(const CompressParams& cparams, const char* label,
const Image3F& image) {
if (!cparams.debug_image) return true;
Image3F linear(image.xsize(), image.ysize());
JXL_ASSIGN_OR_RETURN(Image3F linear,
Image3F::Create(image.xsize(), image.ysize()));
OpsinParams opsin_params;
opsin_params.Init(kDefaultIntensityTarget);
OpsinToLinear(image, Rect(linear), nullptr, &linear, opsin_params);
DumpImageT(cparams, label, ColorEncoding::LinearSRGB(), linear);
return DumpImageT(cparams, label, ColorEncoding::LinearSRGB(), linear);
}
void DumpPlaneNormalized(const CompressParams& cparams, const char* label,
const Plane<float>& image) {
DumpPlaneNormalizedT(cparams, label, image);
Status DumpPlaneNormalized(const CompressParams& cparams, const char* label,
const Plane<float>& image) {
return DumpPlaneNormalizedT(cparams, label, image);
}
void DumpPlaneNormalized(const CompressParams& cparams, const char* label,
const Plane<uint8_t>& image) {
DumpPlaneNormalizedT(cparams, label, image);
Status DumpPlaneNormalized(const CompressParams& cparams, const char* label,
const Plane<uint8_t>& image) {
return DumpPlaneNormalizedT(cparams, label, image);
}
} // namespace jxl

20
third_party/jpeg-xl/lib/jxl/enc_debug_image.h поставляемый
Просмотреть файл

@ -16,16 +16,16 @@
namespace jxl {
void DumpImage(const CompressParams& cparams, const char* label,
const Image3<float>& image);
void DumpImage(const CompressParams& cparams, const char* label,
const Image3<uint8_t>& image);
void DumpXybImage(const CompressParams& cparams, const char* label,
const Image3<float>& image);
void DumpPlaneNormalized(const CompressParams& cparams, const char* label,
const Plane<float>& image);
void DumpPlaneNormalized(const CompressParams& cparams, const char* label,
const Plane<uint8_t>& image);
Status DumpImage(const CompressParams& cparams, const char* label,
const Image3<float>& image);
Status DumpImage(const CompressParams& cparams, const char* label,
const Image3<uint8_t>& image);
Status DumpXybImage(const CompressParams& cparams, const char* label,
const Image3<float>& image);
Status DumpPlaneNormalized(const CompressParams& cparams, const char* label,
const Plane<float>& image);
Status DumpPlaneNormalized(const CompressParams& cparams, const char* label,
const Plane<uint8_t>& image);
// Used to skip image creation if they won't be written to debug directory.
static inline bool WantDebugOutput(const CompressParams& cparams) {

Просмотреть файл

@ -26,7 +26,6 @@
#include "lib/jxl/base/status.h"
#include "lib/jxl/convolve.h"
#include "lib/jxl/enc_linalg.h"
#include "lib/jxl/enc_optimize.h"
#include "lib/jxl/image.h"
#include "lib/jxl/image_ops.h"
@ -44,14 +43,16 @@ using hwy::HWY_NAMESPACE::Add;
using hwy::HWY_NAMESPACE::Mul;
using hwy::HWY_NAMESPACE::Sub;
ImageF SumOfSquareDifferences(const Image3F& forig, const Image3F& smooth,
ThreadPool* pool) {
StatusOr<ImageF> SumOfSquareDifferences(const Image3F& forig,
const Image3F& smooth,
ThreadPool* pool) {
const HWY_FULL(float) d;
const auto color_coef0 = Set(d, 0.0f);
const auto color_coef1 = Set(d, 10.0f);
const auto color_coef2 = Set(d, 0.0f);
ImageF sum_of_squares(forig.xsize(), forig.ysize());
JXL_ASSIGN_OR_RETURN(ImageF sum_of_squares,
ImageF::Create(forig.xsize(), forig.ysize()));
JXL_CHECK(RunOnPool(
pool, 0, forig.ysize(), ThreadPool::NoInit,
[&](const uint32_t task, size_t thread) {
@ -142,11 +143,12 @@ const WeightsSeparable5& WeightsSeparable5Gaussian3() {
return weights;
}
ImageF ComputeEnergyImage(const Image3F& orig, Image3F* smooth,
ThreadPool* pool) {
StatusOr<ImageF> ComputeEnergyImage(const Image3F& orig, Image3F* smooth,
ThreadPool* pool) {
// Prepare guidance images for dot selection.
Image3F forig(orig.xsize(), orig.ysize());
*smooth = Image3F(orig.xsize(), orig.ysize());
JXL_ASSIGN_OR_RETURN(Image3F forig,
Image3F::Create(orig.xsize(), orig.ysize()));
JXL_ASSIGN_OR_RETURN(*smooth, Image3F::Create(orig.xsize(), orig.ysize()));
Rect rect(orig);
const auto& weights1 = WeightsSeparable5Gaussian0_65();
@ -266,7 +268,10 @@ struct ConnectedComponent {
Rect BoundingRectangle(const std::vector<Pixel>& pixels) {
JXL_ASSERT(!pixels.empty());
int low_x, high_x, low_y, high_y;
int low_x;
int high_x;
int low_y;
int high_y;
low_x = high_x = pixels[0].x;
low_y = high_y = pixels[0].y;
for (const Pixel& p : pixels) {
@ -278,11 +283,13 @@ Rect BoundingRectangle(const std::vector<Pixel>& pixels) {
return Rect(low_x, low_y, high_x - low_x + 1, high_y - low_y + 1);
}
std::vector<ConnectedComponent> FindCC(const ImageF& energy, double t_low,
double t_high, uint32_t maxWindow,
double minScore) {
StatusOr<std::vector<ConnectedComponent>> FindCC(const ImageF& energy,
double t_low, double t_high,
uint32_t maxWindow,
double minScore) {
const int kExtraRect = 4;
ImageF img(energy.xsize(), energy.ysize());
JXL_ASSIGN_OR_RETURN(ImageF img,
ImageF::Create(energy.xsize(), energy.ysize()));
CopyImageTo(energy, &img);
std::vector<ConnectedComponent> ans;
for (size_t y = 0; y < img.ysize(); y++) {
@ -328,7 +335,8 @@ void ComputeDotLosses(GaussianEllipse* ellipse, const ConnectedComponent& cc,
const double kIntensityR = 0.0; // 0.015;
const double kSigmaR = 0.0; // 0.01;
const double kZeroEpsilon = 0.1; // Tolerance to consider a value negative
double ct = cos(ellipse->angle), st = sin(ellipse->angle);
double ct = cos(ellipse->angle);
double st = sin(ellipse->angle);
const std::array<double, 3> channelGains{{1.0, 1.0, 1.0}};
int N = 0;
ellipse->l1_loss = 0.0;
@ -450,14 +458,16 @@ GaussianEllipse FitGaussianFast(const ConnectedComponent& cc,
ans.intensity[j] = kScaleMult[j] * color[j];
}
ImageD Sigma(2, 2), D(1, 2), U(2, 2);
Sigma.Row(0)[0] = m2[0] - m1[0] * m1[0];
Sigma.Row(1)[1] = m2[2] - m1[1] * m1[1];
Sigma.Row(0)[1] = Sigma.Row(1)[0] = m2[1] - m1[0] * m1[1];
ConvertToDiagonal(Sigma, &D, &U);
const double* JXL_RESTRICT d = D.ConstRow(0);
const double* JXL_RESTRICT u = U.ConstRow(1);
int p1 = 0, p2 = 1;
Matrix2x2 Sigma;
Vector2 d;
Matrix2x2 U;
Sigma[0][0] = m2[0] - m1[0] * m1[0];
Sigma[1][1] = m2[2] - m1[1] * m1[1];
Sigma[0][1] = Sigma[1][0] = m2[1] - m1[0] * m1[1];
ConvertToDiagonal(Sigma, d, U);
Vector2& u = U[1];
int p1 = 0;
int p2 = 1;
if (d[0] < d[1]) std::swap(p1, p2);
ans.sigma_x = kSigmaMult * d[p1];
ans.sigma_y = kSigmaMult * d[p2];
@ -466,7 +476,8 @@ GaussianEllipse FitGaussianFast(const ConnectedComponent& cc,
ans.bgColor = bgColor;
if (leastSqIntensity) {
GaussianEllipse* ellipse = &ans;
double ct = cos(ans.angle), st = sin(ans.angle);
double ct = cos(ans.angle);
double st = sin(ans.angle);
// Estimate intensity with least squares (fixed background)
for (int c = 0; c < 3; c++) {
double gg = 0.0;
@ -522,14 +533,16 @@ GaussianEllipse FitGaussian(const ConnectedComponent& cc, const ImageF& energy,
} // namespace
std::vector<PatchInfo> DetectGaussianEllipses(
StatusOr<std::vector<PatchInfo>> DetectGaussianEllipses(
const Image3F& opsin, const GaussianDetectParams& params,
const EllipseQuantParams& qParams, ThreadPool* pool) {
std::vector<PatchInfo> dots;
Image3F smooth(opsin.xsize(), opsin.ysize());
ImageF energy = ComputeEnergyImage(opsin, &smooth, pool);
std::vector<ConnectedComponent> components = FindCC(
energy, params.t_low, params.t_high, params.maxWinSize, params.minScore);
JXL_ASSIGN_OR_RETURN(Image3F smooth,
Image3F::Create(opsin.xsize(), opsin.ysize()));
JXL_ASSIGN_OR_RETURN(ImageF energy, ComputeEnergyImage(opsin, &smooth, pool));
JXL_ASSIGN_OR_RETURN(std::vector<ConnectedComponent> components,
FindCC(energy, params.t_low, params.t_high,
params.maxWinSize, params.minScore));
size_t numCC =
std::min(params.maxCC, (components.size() * params.percCC) / 100);
if (components.size() > numCC) {

Просмотреть файл

@ -14,7 +14,6 @@
#include <vector>
#include "lib/jxl/base/data_parallel.h"
#include "lib/jxl/dec_patch_dictionary.h"
#include "lib/jxl/enc_patch_dictionary.h"
#include "lib/jxl/image.h"
@ -58,7 +57,7 @@ struct EllipseQuantParams {
};
// Detects dots in XYB image.
std::vector<PatchInfo> DetectGaussianEllipses(
StatusOr<std::vector<PatchInfo>> DetectGaussianEllipses(
const Image3F& opsin, const GaussianDetectParams& params,
const EllipseQuantParams& qParams, ThreadPool* pool);

Просмотреть файл

@ -9,17 +9,12 @@
#include <string.h>
#include <array>
#include <utility>
#include "lib/jxl/base/override.h"
#include "lib/jxl/base/status.h"
#include "lib/jxl/chroma_from_luma.h"
#include "lib/jxl/dec_bit_reader.h"
#include "lib/jxl/dec_xyb.h"
#include "lib/jxl/enc_bit_writer.h"
#include "lib/jxl/enc_detect_dots.h"
#include "lib/jxl/enc_params.h"
#include "lib/jxl/enc_xyb.h"
#include "lib/jxl/image.h"
namespace jxl {
@ -39,10 +34,9 @@ const std::array<double, 3> kEllipseMaxIntensity{{0.05, 1.0, 0.4}};
const std::array<size_t, 3> kEllipseIntensityQ{{10, 36, 10}};
} // namespace
std::vector<PatchInfo> FindDotDictionary(const CompressParams& cparams,
const Image3F& opsin,
const ColorCorrelationMap& cmap,
ThreadPool* pool) {
StatusOr<std::vector<PatchInfo>> FindDotDictionary(
const CompressParams& cparams, const Image3F& opsin,
const ColorCorrelationMap& cmap, ThreadPool* pool) {
if (ApplyOverride(cparams.dots,
cparams.butteraugli_distance >= kMinButteraugliForDots)) {
GaussianDetectParams ellipse_params;
@ -66,6 +60,7 @@ std::vector<PatchInfo> FindDotDictionary(const CompressParams& cparams,
return DetectGaussianEllipses(opsin, ellipse_params, qParams, pool);
}
return {};
std::vector<PatchInfo> nothing;
return nothing;
}
} // namespace jxl

Просмотреть файл

@ -15,19 +15,15 @@
#include "lib/jxl/base/status.h"
#include "lib/jxl/chroma_from_luma.h"
#include "lib/jxl/dec_bit_reader.h"
#include "lib/jxl/dec_patch_dictionary.h"
#include "lib/jxl/enc_bit_writer.h"
#include "lib/jxl/enc_params.h"
#include "lib/jxl/enc_patch_dictionary.h"
#include "lib/jxl/image.h"
namespace jxl {
std::vector<PatchInfo> FindDotDictionary(const CompressParams& cparams,
const Image3F& opsin,
const ColorCorrelationMap& cmap,
ThreadPool* pool);
StatusOr<std::vector<PatchInfo>> FindDotDictionary(
const CompressParams& cparams, const Image3F& opsin,
const ColorCorrelationMap& cmap, ThreadPool* pool);
} // namespace jxl

Просмотреть файл

@ -8,14 +8,9 @@
#include <jxl/types.h>
#include <string.h>
#include <algorithm>
#include <array>
#include <atomic>
#include <functional>
#include <utility>
#include <vector>
#include "lib/jxl/alpha.h"
#include "lib/jxl/base/byte_order.h"
#include "lib/jxl/base/common.h"
#include "lib/jxl/base/float.h"
@ -114,7 +109,7 @@ Status ConvertFromExternalNoSizeCheck(const uint8_t* data, size_t xsize,
color_channels, format.num_channels);
}
Image3F color(xsize, ysize);
JXL_ASSIGN_OR_RETURN(Image3F color, Image3F::Create(xsize, ysize));
for (size_t c = 0; c < color_channels; ++c) {
JXL_RETURN_IF_ERROR(ConvertFromExternalNoSizeCheck(
data, xsize, ysize, stride, bits_per_sample, format, c, pool,
@ -129,7 +124,7 @@ Status ConvertFromExternalNoSizeCheck(const uint8_t* data, size_t xsize,
// Passing an interleaved image with an alpha channel to an image that doesn't
// have alpha channel just discards the passed alpha channel.
if (has_alpha && ib->HasAlpha()) {
ImageF alpha(xsize, ysize);
JXL_ASSIGN_OR_RETURN(ImageF alpha, ImageF::Create(xsize, ysize));
JXL_RETURN_IF_ERROR(ConvertFromExternalNoSizeCheck(
data, xsize, ysize, stride, bits_per_sample, format,
format.num_channels - 1, pool, &alpha));
@ -137,7 +132,7 @@ Status ConvertFromExternalNoSizeCheck(const uint8_t* data, size_t xsize,
} else if (!has_alpha && ib->HasAlpha()) {
// if alpha is not passed, but it is expected, then assume
// it is all-opaque
ImageF alpha(xsize, ysize);
JXL_ASSIGN_OR_RETURN(ImageF alpha, ImageF::Create(xsize, ysize));
FillImage(1.0f, &alpha);
ib->SetAlpha(std::move(alpha));
}
@ -184,7 +179,7 @@ Status ConvertFromExternal(Span<const uint8_t> bytes, size_t xsize,
color_channels, format.num_channels);
}
Image3F color(xsize, ysize);
JXL_ASSIGN_OR_RETURN(Image3F color, Image3F::Create(xsize, ysize));
for (size_t c = 0; c < color_channels; ++c) {
JXL_RETURN_IF_ERROR(ConvertFromExternal(bytes.data(), bytes.size(), xsize,
ysize, bits_per_sample, format, c,
@ -199,7 +194,7 @@ Status ConvertFromExternal(Span<const uint8_t> bytes, size_t xsize,
// Passing an interleaved image with an alpha channel to an image that doesn't
// have alpha channel just discards the passed alpha channel.
if (has_alpha && ib->HasAlpha()) {
ImageF alpha(xsize, ysize);
JXL_ASSIGN_OR_RETURN(ImageF alpha, ImageF::Create(xsize, ysize));
JXL_RETURN_IF_ERROR(ConvertFromExternal(
bytes.data(), bytes.size(), xsize, ysize, bits_per_sample, format,
format.num_channels - 1, pool, &alpha));
@ -207,7 +202,7 @@ Status ConvertFromExternal(Span<const uint8_t> bytes, size_t xsize,
} else if (!has_alpha && ib->HasAlpha()) {
// if alpha is not passed, but it is expected, then assume
// it is all-opaque
ImageF alpha(xsize, ysize);
JXL_ASSIGN_OR_RETURN(ImageF alpha, ImageF::Create(xsize, ysize));
FillImage(1.0f, &alpha);
ib->SetAlpha(std::move(alpha));
}

Просмотреть файл

@ -3735,10 +3735,13 @@ JxlFastLosslessFrameState* LLPrepare(JxlChunkedFrameInputSource input,
const void* buffer =
input.get_color_channel_data_at(input.opaque, x0, y0, xs, ys, &stride);
auto rgba = reinterpret_cast<const unsigned char*>(buffer);
int y_begin = std::max<int>(0, ys - 2 * effort) / 2;
int y_count = std::min<int>(num_rows, y0 + ys - y_begin - 1);
int y_begin_group =
std::max<ssize_t>(
0, static_cast<ssize_t>(ys) - static_cast<ssize_t>(num_rows)) /
2;
int y_count = std::min<int>(num_rows, ys - y_begin_group);
int x_max = xs / kChunkSize * kChunkSize;
CollectSamples(rgba, 0, y_begin, x_max, stride, y_count, raw_counts,
CollectSamples(rgba, 0, y_begin_group, x_max, stride, y_count, raw_counts,
lz77_counts, onegroup, !collided, bitdepth, nb_chans,
big_endian, lookup.data());
input.release_buffer(input.opaque, buffer);

280
third_party/jpeg-xl/lib/jxl/enc_frame.cc поставляемый
Просмотреть файл

@ -12,13 +12,13 @@
#include <array>
#include <atomic>
#include <cmath>
#include <limits>
#include <memory>
#include <numeric>
#include <utility>
#include <vector>
#include "lib/jxl/ac_context.h"
#include "lib/jxl/ac_strategy.h"
#include "lib/jxl/ans_params.h"
#include "lib/jxl/base/bits.h"
#include "lib/jxl/base/common.h"
#include "lib/jxl/base/compiler_specific.h"
@ -31,7 +31,6 @@
#include "lib/jxl/coeff_order_fwd.h"
#include "lib/jxl/color_encoding_internal.h"
#include "lib/jxl/common.h" // kMaxNumPasses
#include "lib/jxl/compressed_dc.h"
#include "lib/jxl/dct_util.h"
#include "lib/jxl/dec_external_image.h"
#include "lib/jxl/enc_ac_strategy.h"
@ -47,7 +46,6 @@
#include "lib/jxl/enc_entropy_coder.h"
#include "lib/jxl/enc_external_image.h"
#include "lib/jxl/enc_fields.h"
#include "lib/jxl/enc_gaborish.h"
#include "lib/jxl/enc_group.h"
#include "lib/jxl/enc_heuristics.h"
#include "lib/jxl/enc_modular.h"
@ -285,7 +283,8 @@ Status LoopFilterFromParams(const CompressParams& cparams, bool streaming_mode,
if (frame_header->encoding == FrameEncoding::kModular &&
!cparams.IsLossless()) {
// TODO(veluca): this formula is nonsense.
loop_filter->epf_sigma_for_modular = cparams.butteraugli_distance;
loop_filter->epf_sigma_for_modular =
std::max(cparams.butteraugli_distance, 1.0f);
}
if (frame_header->encoding == FrameEncoding::kModular &&
cparams.lossy_palette) {
@ -539,7 +538,7 @@ struct PixelStatsForChromacityAdjustment {
float dx = 0;
float db = 0;
float exposed_blue = 0;
float CalcPlane(const ImageF* JXL_RESTRICT plane, const Rect& rect) const {
static float CalcPlane(const ImageF* JXL_RESTRICT plane, const Rect& rect) {
float xmax = 0;
float ymax = 0;
for (size_t ty = 1; ty < rect.ysize(); ++ty) {
@ -583,7 +582,7 @@ struct PixelStatsForChromacityAdjustment {
dx = CalcPlane(&opsin->Plane(0), rect);
CalcExposedBlue(&opsin->Plane(1), &opsin->Plane(2), rect);
}
int HowMuchIsXChannelPixelized() {
int HowMuchIsXChannelPixelized() const {
if (dx >= 0.03) {
return 2;
}
@ -592,7 +591,7 @@ struct PixelStatsForChromacityAdjustment {
}
return 0;
}
int HowMuchIsBChannelPixelized() {
int HowMuchIsBChannelPixelized() const {
int add = exposed_blue >= 0.13 ? 1 : 0;
if (db > 0.38) {
return 2 + add;
@ -682,12 +681,12 @@ void ComputeNoiseParams(const CompressParams& cparams, bool streaming_mode,
}
}
void DownsampleColorChannels(const CompressParams& cparams,
const FrameHeader& frame_header,
bool color_is_jpeg, Image3F* opsin) {
Status DownsampleColorChannels(const CompressParams& cparams,
const FrameHeader& frame_header,
bool color_is_jpeg, Image3F* opsin) {
if (color_is_jpeg || frame_header.upsampling == 1 ||
cparams.already_downsampled) {
return;
return true;
}
if (frame_header.encoding == FrameEncoding::kVarDCT &&
frame_header.upsampling == 2) {
@ -698,16 +697,18 @@ void DownsampleColorChannels(const CompressParams& cparams,
// TODO(lode): DownsampleImage2_Iterative is currently too slow to
// be used for squirrel, make it faster, and / or enable it only for
// kitten.
DownsampleImage2_Iterative(opsin);
JXL_RETURN_IF_ERROR(DownsampleImage2_Iterative(opsin));
} else {
DownsampleImage2_Sharper(opsin);
JXL_RETURN_IF_ERROR(DownsampleImage2_Sharper(opsin));
}
} else {
DownsampleImage(opsin, frame_header.upsampling);
JXL_ASSIGN_OR_RETURN(*opsin,
DownsampleImage(*opsin, frame_header.upsampling));
}
if (frame_header.encoding == FrameEncoding::kVarDCT) {
PadImageToBlockMultipleInPlace(opsin);
}
return true;
}
template <typename V, typename R>
@ -741,14 +742,17 @@ Status ComputeJPEGTranscodingData(const jpeg::JPEGData& jpeg_data,
const size_t ysize_blocks = frame_dim.ysize_blocks;
// no-op chroma from luma
shared.cmap = ColorCorrelationMap(xsize, ysize, false);
JXL_ASSIGN_OR_RETURN(shared.cmap,
ColorCorrelationMap::Create(xsize, ysize, false));
shared.ac_strategy.FillDCT8();
FillImage(uint8_t(0), &shared.epf_sharpness);
enc_state->coeffs.clear();
while (enc_state->coeffs.size() < enc_state->passes.size()) {
enc_state->coeffs.emplace_back(make_unique<ACImageT<int32_t>>(
kGroupDim * kGroupDim, frame_dim.num_groups));
JXL_ASSIGN_OR_RETURN(
std::unique_ptr<ACImageT<int32_t>> coeffs,
ACImageT<int32_t>::Make(kGroupDim * kGroupDim, frame_dim.num_groups));
enc_state->coeffs.emplace_back(std::move(coeffs));
}
// convert JPEG quantization table to a Quantizer object
@ -779,7 +783,8 @@ Status ComputeJPEGTranscodingData(const jpeg::JPEGData& jpeg_data,
1.0f / dcquantization[2]};
qe[AcStrategy::Type::DCT] = QuantEncoding::RAW(qt);
DequantMatricesSetCustom(&shared.matrices, qe, enc_modular);
JXL_RETURN_IF_ERROR(
DequantMatricesSetCustom(&shared.matrices, qe, enc_modular));
// Ensure that InvGlobalScale() is 1.
shared.quantizer = Quantizer(&shared.matrices, 1, kGlobalScaleDenom);
@ -844,7 +849,8 @@ Status ComputeJPEGTranscodingData(const jpeg::JPEGData& jpeg_data,
kScale * row_s[x * kDCTBlockSize + coeffpos] +
(kOffset - kBase * kScale) * scaled_m;
if (std::abs(scaled_m) > 1e-8f) {
float from, to;
float from;
float to;
if (scaled_m > 0) {
from = (scaled_s - kZeroThresh) / scaled_m;
to = (scaled_s + kZeroThresh) / scaled_m;
@ -889,7 +895,7 @@ Status ComputeJPEGTranscodingData(const jpeg::JPEGData& jpeg_data,
}
}
Image3F dc = Image3F(xsize_blocks, ysize_blocks);
JXL_ASSIGN_OR_RETURN(Image3F dc, Image3F::Create(xsize_blocks, ysize_blocks));
if (!frame_header.chroma_subsampling.Is444()) {
ZeroFillImage(&dc);
for (auto& coeff : enc_state->coeffs) {
@ -1024,18 +1030,27 @@ Status ComputeJPEGTranscodingData(const jpeg::JPEGData& jpeg_data,
*std::max_element(ctx_map.begin(), ctx_map.end()) + 1;
// disable DC frame for now
std::atomic<bool> has_error{false};
auto compute_dc_coeffs = [&](const uint32_t group_index,
size_t /* thread */) {
if (has_error) return;
const Rect r = enc_state->shared.frame_dim.DCGroupRect(group_index);
enc_modular->AddVarDCTDC(frame_header, dc, r, group_index,
/*nl_dc=*/false, enc_state,
/*jpeg_transcode=*/true);
enc_modular->AddACMetadata(r, group_index, /*jpeg_transcode=*/true,
enc_state);
if (!enc_modular->AddVarDCTDC(frame_header, dc, r, group_index,
/*nl_dc=*/false, enc_state,
/*jpeg_transcode=*/true)) {
has_error = true;
return;
}
if (!enc_modular->AddACMetadata(r, group_index, /*jpeg_transcode=*/true,
enc_state)) {
has_error = true;
return;
}
};
JXL_RETURN_IF_ERROR(RunOnPool(pool, 0, shared.frame_dim.num_dc_groups,
ThreadPool::NoInit, compute_dc_coeffs,
"Compute DC coeffs"));
if (has_error) return JXL_FAILURE("Compute DC coeffs failed");
return true;
}
@ -1077,10 +1092,12 @@ void ComputeAllCoeffOrders(PassesEncoderState& enc_state,
// Working area for TokenizeCoefficients (per-group!)
struct EncCache {
// Allocates memory when first called.
void InitOnce() {
Status InitOnce() {
if (num_nzeroes.xsize() == 0) {
num_nzeroes = Image3I(kGroupDimInBlocks, kGroupDimInBlocks);
JXL_ASSIGN_OR_RETURN(
num_nzeroes, Image3I::Create(kGroupDimInBlocks, kGroupDimInBlocks));
}
return true;
}
// TokenizeCoefficients
Image3I num_nzeroes;
@ -1095,8 +1112,10 @@ Status TokenizeAllCoefficients(const FrameHeader& frame_header,
group_caches.resize(num_threads);
return true;
};
std::atomic<bool> has_error{false};
const auto tokenize_group = [&](const uint32_t group_index,
const size_t thread) {
if (has_error) return;
// Tokenize coefficients.
const Rect rect = shared.frame_dim.BlockGroupRect(group_index);
for (size_t idx_pass = 0; idx_pass < enc_state->passes.size(); idx_pass++) {
@ -1107,7 +1126,10 @@ Status TokenizeAllCoefficients(const FrameHeader& frame_header,
enc_state->coeffs[idx_pass]->PlaneRow(2, group_index, 0).ptr32,
};
// Ensure group cache is initialized.
group_caches[thread].InitOnce();
if (!group_caches[thread].InitOnce()) {
has_error = true;
return;
}
TokenizeCoefficients(
&shared.coeff_orders[idx_pass * shared.coeff_order_size], rect,
ac_rows, shared.ac_strategy, frame_header.chroma_subsampling,
@ -1116,8 +1138,11 @@ Status TokenizeAllCoefficients(const FrameHeader& frame_header,
shared.raw_quant_field, shared.block_ctx_map);
}
};
return RunOnPool(pool, 0, shared.frame_dim.num_groups, tokenize_group_init,
tokenize_group, "TokenizeGroup");
JXL_RETURN_IF_ERROR(RunOnPool(pool, 0, shared.frame_dim.num_groups,
tokenize_group_init, tokenize_group,
"TokenizeGroup"));
if (has_error) return JXL_FAILURE("TokenizeGroup failed");
return true;
}
Status EncodeGlobalDCInfo(const PassesSharedState& shared, BitWriter* writer,
@ -1308,35 +1333,43 @@ Status EncodeGroups(const FrameHeader& frame_header,
enc_state, get_output(global_ac_index), enc_modular, aux_out));
}
std::atomic<int> num_errors{0};
std::atomic<bool> has_error{false};
const auto process_group = [&](const uint32_t group_index,
const size_t thread) {
if (has_error) return;
AuxOut* my_aux_out = aux_outs[thread].get();
size_t ac_group_id =
enc_state->streaming_mode
? enc_modular->ComputeStreamingAbsoluteAcGroupId(
enc_state->dc_group_index, group_index, shared.frame_dim)
: group_index;
for (size_t i = 0; i < num_passes; i++) {
JXL_DEBUG_V(2, "Encoding AC group %u [abs %" PRIuS "] pass %" PRIuS,
group_index, ac_group_id, i);
if (frame_header.encoding == FrameEncoding::kVarDCT) {
if (!EncodeGroupTokenizedCoefficients(
group_index, i, enc_state->histogram_idx[group_index],
*enc_state, ac_group_code(i, group_index), my_aux_out)) {
num_errors.fetch_add(1, std::memory_order_relaxed);
has_error = true;
return;
}
}
// Write all modular encoded data (color?, alpha, depth, extra channels)
if (!enc_modular->EncodeStream(
ac_group_code(i, group_index), my_aux_out, kLayerModularAcGroup,
ModularStreamId::ModularAC(group_index, i))) {
num_errors.fetch_add(1, std::memory_order_relaxed);
ModularStreamId::ModularAC(ac_group_id, i))) {
has_error = true;
return;
}
}
};
JXL_RETURN_IF_ERROR(RunOnPool(pool, 0, num_groups, resize_aux_outs,
process_group, "EncodeGroupCoefficients"));
if (has_error) return JXL_FAILURE("EncodeGroupCoefficients failed");
// Resizing aux_outs to 0 also Assimilates the array.
static_cast<void>(resize_aux_outs(0));
JXL_RETURN_IF_ERROR(num_errors.load(std::memory_order_relaxed) == 0);
for (BitWriter& bw : *group_codes) {
BitWriter::Allotment allotment(&bw, 8);
@ -1360,29 +1393,39 @@ Status ComputeEncodingData(
PassesSharedState& shared = enc_state.shared;
shared.metadata = metadata;
if (enc_state.streaming_mode) {
shared.frame_dim.Set(xsize, ysize, /*group_size_shift=*/1,
/*maxhshift=*/0, /*maxvshift=*/0,
/*modular_mode=*/false, /*upsampling=*/1);
shared.frame_dim.Set(
xsize, ysize, frame_header.group_size_shift,
/*max_hshift=*/0, /*max_vshift=*/0,
mutable_frame_header.encoding == FrameEncoding::kModular,
/*upsampling=*/1);
} else {
shared.frame_dim = frame_header.ToFrameDimensions();
}
shared.image_features.patches.SetPassesSharedState(&shared);
const FrameDimensions& frame_dim = shared.frame_dim;
shared.ac_strategy =
AcStrategyImage(frame_dim.xsize_blocks, frame_dim.ysize_blocks);
shared.raw_quant_field =
ImageI(frame_dim.xsize_blocks, frame_dim.ysize_blocks);
shared.epf_sharpness = ImageB(frame_dim.xsize_blocks, frame_dim.ysize_blocks);
shared.cmap = ColorCorrelationMap(frame_dim.xsize, frame_dim.ysize);
JXL_ASSIGN_OR_RETURN(
shared.ac_strategy,
AcStrategyImage::Create(frame_dim.xsize_blocks, frame_dim.ysize_blocks));
JXL_ASSIGN_OR_RETURN(
shared.raw_quant_field,
ImageI::Create(frame_dim.xsize_blocks, frame_dim.ysize_blocks));
JXL_ASSIGN_OR_RETURN(
shared.epf_sharpness,
ImageB::Create(frame_dim.xsize_blocks, frame_dim.ysize_blocks));
JXL_ASSIGN_OR_RETURN(shared.cmap, ColorCorrelationMap::Create(
frame_dim.xsize, frame_dim.ysize));
shared.coeff_order_size = kCoeffOrderMaxSize;
if (frame_header.encoding == FrameEncoding::kVarDCT) {
shared.coeff_orders.resize(frame_header.passes.num_passes *
kCoeffOrderMaxSize);
}
shared.quant_dc = ImageB(frame_dim.xsize_blocks, frame_dim.ysize_blocks);
shared.dc_storage = Image3F(frame_dim.xsize_blocks, frame_dim.ysize_blocks);
JXL_ASSIGN_OR_RETURN(shared.quant_dc, ImageB::Create(frame_dim.xsize_blocks,
frame_dim.ysize_blocks));
JXL_ASSIGN_OR_RETURN(
shared.dc_storage,
Image3F::Create(frame_dim.xsize_blocks, frame_dim.ysize_blocks));
shared.dc = &shared.dc_storage;
const size_t num_extra_channels = metadata->m.num_extra_channels;
@ -1397,16 +1440,19 @@ Status ComputeEncodingData(
// computing inverse Gaborish and adaptive quantization map.
int max_border = enc_state.streaming_mode ? kBlockDim : 0;
Rect frame_rect(0, 0, frame_data.xsize, frame_data.ysize);
Rect patch_rect = Rect(x0, y0, xsize, ysize).Extend(max_border, frame_rect);
Rect frame_area_rect = Rect(x0, y0, xsize, ysize);
Rect patch_rect = frame_area_rect.Extend(max_border, frame_rect);
JXL_ASSERT(patch_rect.IsInside(frame_rect));
// Allocating a large enough image avoids a copy when padding.
Image3F color(RoundUpToBlockDim(patch_rect.xsize()),
RoundUpToBlockDim(patch_rect.ysize()));
JXL_ASSIGN_OR_RETURN(Image3F color,
Image3F::Create(RoundUpToBlockDim(patch_rect.xsize()),
RoundUpToBlockDim(patch_rect.ysize())));
color.ShrinkTo(patch_rect.xsize(), patch_rect.ysize());
std::vector<ImageF> extra_channels(num_extra_channels);
for (auto& extra_channel : extra_channels) {
extra_channel = jxl::ImageF(patch_rect.xsize(), patch_rect.ysize());
JXL_ASSIGN_OR_RETURN(
extra_channel, ImageF::Create(patch_rect.xsize(), patch_rect.ysize()));
}
ImageF* alpha = alpha_eci ? &extra_channels[alpha_idx] : nullptr;
ImageF* black = black_eci ? &extra_channels[black_idx] : nullptr;
@ -1432,7 +1478,9 @@ Status ComputeEncodingData(
frame_info.ib_needs_color_transform) {
if (frame_header.encoding == FrameEncoding::kVarDCT &&
cparams.speed_tier <= SpeedTier::kKitten) {
linear_storage = Image3F(patch_rect.xsize(), patch_rect.ysize());
JXL_ASSIGN_OR_RETURN(
linear_storage,
Image3F::Create(patch_rect.xsize(), patch_rect.ysize()));
linear = &linear_storage;
}
ToXYB(c_enc, metadata->m.IntensityTarget(), black, pool, &color, cms,
@ -1446,7 +1494,7 @@ Status ComputeEncodingData(
bool lossless = cparams.IsLossless();
if (alpha && !alpha_eci->alpha_associated &&
frame_header.frame_type == FrameType::kRegularFrame &&
!ApplyOverride(cparams.keep_invisible, lossless) &&
!ApplyOverride(cparams.keep_invisible, true) &&
cparams.ec_resampling == cparams.resampling) {
// simplify invisible pixels
SimplifyInvisible(&color, *alpha, lossless);
@ -1467,15 +1515,17 @@ Status ComputeEncodingData(
&mutable_frame_header);
}
ComputeNoiseParams(cparams, enc_state.streaming_mode, !!jpeg_data, color,
bool has_jpeg_data = (jpeg_data != nullptr);
ComputeNoiseParams(cparams, enc_state.streaming_mode, has_jpeg_data, color,
frame_dim, &mutable_frame_header,
&shared.image_features.noise_params);
DownsampleColorChannels(cparams, frame_header, !!jpeg_data, &color);
JXL_RETURN_IF_ERROR(
DownsampleColorChannels(cparams, frame_header, has_jpeg_data, &color));
if (cparams.ec_resampling != 1 && !cparams.already_downsampled) {
for (ImageF& ec : extra_channels) {
DownsampleImage(&ec, cparams.ec_resampling);
JXL_ASSIGN_OR_RETURN(ec, DownsampleImage(ec, cparams.ec_resampling));
}
}
@ -1505,15 +1555,21 @@ Status ComputeEncodingData(
TokenizeAllCoefficients(frame_header, pool, &enc_state));
}
if (!enc_state.streaming_mode) {
if (cparams.modular_mode || !extra_channels.empty()) {
JXL_RETURN_IF_ERROR(enc_modular.ComputeEncodingData(
frame_header, metadata->m, &color, extra_channels, &enc_state, cms,
pool, aux_out, /*do_color=*/cparams.modular_mode));
}
JXL_RETURN_IF_ERROR(enc_modular.ComputeTree(pool));
JXL_RETURN_IF_ERROR(enc_modular.ComputeTokens(pool));
if (cparams.modular_mode || !extra_channels.empty()) {
JXL_RETURN_IF_ERROR(enc_modular.ComputeEncodingData(
frame_header, metadata->m, &color, extra_channels, group_rect,
frame_dim, frame_area_rect, &enc_state, cms, pool, aux_out,
/*do_color=*/cparams.modular_mode));
}
if (!enc_state.streaming_mode) {
if (cparams.speed_tier < SpeedTier::kTortoise ||
!cparams.ModularPartIsLossless() || cparams.responsive ||
!cparams.custom_fixed_tree.empty()) {
// Use local trees if doing lossless modular, unless at very slow speeds.
JXL_RETURN_IF_ERROR(enc_modular.ComputeTree(pool));
JXL_RETURN_IF_ERROR(enc_modular.ComputeTokens(pool));
}
mutable_frame_header.UpdateFlag(shared.image_features.patches.HasAny(),
FrameHeader::kPatches);
mutable_frame_header.UpdateFlag(shared.image_features.splines.HasAny(),
@ -1526,6 +1582,7 @@ Status ComputeEncodingData(
const size_t group_index = enc_state.dc_group_index;
enc_modular.ClearStreamData(ModularStreamId::VarDCTDC(group_index));
enc_modular.ClearStreamData(ModularStreamId::ACMetadata(group_index));
enc_modular.ClearModularStreamData();
}
return true;
}
@ -1614,6 +1671,25 @@ bool CanDoStreamingEncoding(const CompressParams& cparams,
const FrameInfo& frame_info,
const CodecMetadata& metadata,
const JxlEncoderChunkedFrameAdapter& frame_data) {
if (cparams.buffering == 0) {
return false;
}
if (cparams.buffering == -1) {
if (cparams.speed_tier < SpeedTier::kTortoise) return false;
if (cparams.speed_tier < SpeedTier::kSquirrel &&
cparams.butteraugli_distance > 0.5f) {
return false;
}
if (cparams.speed_tier == SpeedTier::kSquirrel &&
cparams.butteraugli_distance >= 3.f) {
return false;
}
}
// TODO(veluca): handle different values of `buffering`.
if (frame_data.xsize <= 2048 && frame_data.ysize <= 2048) {
return false;
}
if (frame_data.IsJPEG()) {
return false;
}
@ -1629,34 +1705,24 @@ bool CanDoStreamingEncoding(const CompressParams& cparams,
if (cparams.max_error_mode) {
return false;
}
if (cparams.color_transform != ColorTransform::kXYB) {
return false;
if (!cparams.ModularPartIsLossless() || cparams.responsive > 0) {
if (metadata.m.num_extra_channels > 0 || cparams.modular_mode) {
return false;
}
}
if (cparams.modular_mode) {
return false;
}
if (metadata.m.num_extra_channels > 0) {
return false;
}
if (cparams.buffering == 0) {
return false;
}
if (cparams.buffering == 1 && frame_data.xsize <= 2048 &&
frame_data.ysize <= 2048) {
return false;
}
if (frame_data.xsize <= 256 && frame_data.ysize <= 256) {
ColorTransform ok_color_transform =
cparams.modular_mode ? ColorTransform::kNone : ColorTransform::kXYB;
if (cparams.color_transform != ok_color_transform) {
return false;
}
return true;
}
void ComputePermutationForStreaming(size_t xsize, size_t ysize,
size_t num_passes,
size_t group_size, size_t num_passes,
std::vector<coeff_order_t>& permutation,
std::vector<size_t>& dc_group_order) {
// This is only valid in VarDCT mode, otherwise there can be group shift.
const size_t group_size = 256;
const size_t dc_group_size = group_size * kBlockDim;
const size_t group_xsize = DivCeil(xsize, group_size);
const size_t group_ysize = DivCeil(ysize, group_size);
@ -1864,14 +1930,13 @@ Status EncodeFrameStreaming(const CompressParams& cparams,
frame_info, jpeg_data.get(), true,
&frame_header));
const size_t num_passes = enc_state.progressive_splitter.GetNumPasses();
ModularFrameEncoder enc_modular(frame_header, cparams);
ModularFrameEncoder enc_modular(frame_header, cparams, true);
std::vector<coeff_order_t> permutation;
std::vector<size_t> dc_group_order;
ComputePermutationForStreaming(frame_data.xsize, frame_data.ysize, num_passes,
permutation, dc_group_order);
size_t group_size = frame_header.ToFrameDimensions().group_dim;
ComputePermutationForStreaming(frame_data.xsize, frame_data.ysize, group_size,
num_passes, permutation, dc_group_order);
enc_state.shared.num_histograms = dc_group_order.size();
// This is only valid in VarDCT mode, otherwise there can be group shift.
size_t group_size = 256;
size_t dc_group_size = group_size * kBlockDim;
size_t dc_group_xsize = DivCeil(frame_data.xsize, dc_group_size);
size_t min_dc_global_size = 0;
@ -1931,9 +1996,13 @@ Status EncodeFrameStreaming(const CompressParams& cparams,
JXL_RETURN_IF_ERROR(
OutputGroups(std::move(group_codes), &group_sizes, output_processor));
}
JXL_RETURN_IF_ERROR(OutputAcGlobal(enc_state,
frame_header.ToFrameDimensions(),
&group_sizes, output_processor, aux_out));
if (frame_header.encoding == FrameEncoding::kVarDCT) {
JXL_RETURN_IF_ERROR(
OutputAcGlobal(enc_state, frame_header.ToFrameDimensions(),
&group_sizes, output_processor, aux_out));
} else {
group_sizes.push_back(0);
}
JXL_ASSERT(group_sizes.size() == permutation.size());
size_t end_pos = output_processor->CurrentPosition();
output_processor->Seek(start_pos);
@ -1975,7 +2044,7 @@ Status EncodeFrameOneShot(const CompressParams& cparams,
frame_info, jpeg_data.get(), false,
&frame_header));
const size_t num_passes = enc_state.progressive_splitter.GetNumPasses();
ModularFrameEncoder enc_modular(frame_header, cparams);
ModularFrameEncoder enc_modular(frame_header, cparams, false);
JXL_RETURN_IF_ERROR(ComputeEncodingData(
cparams, frame_info, metadata, frame_data, jpeg_data.get(), 0, 0,
frame_data.xsize, frame_data.ysize, cms, pool, frame_header, enc_modular,
@ -2008,15 +2077,21 @@ Status EncodeFrame(const CompressParams& cparams_orig,
JxlEncoderOutputProcessorWrapper* output_processor,
AuxOut* aux_out) {
CompressParams cparams = cparams_orig;
if (cparams.speed_tier == SpeedTier::kGlacier && !cparams.IsLossless()) {
cparams.speed_tier = SpeedTier::kTortoise;
if (cparams.speed_tier == SpeedTier::kTectonicPlate &&
!cparams.IsLossless()) {
cparams.speed_tier = SpeedTier::kGlacier;
}
if (cparams.speed_tier == SpeedTier::kGlacier) {
// Lightning mode is handled externally, so switch to Thunder mode to handle
// potentially weird cases.
if (cparams.speed_tier == SpeedTier::kLightning) {
cparams.speed_tier = SpeedTier::kThunder;
}
if (cparams.speed_tier == SpeedTier::kTectonicPlate) {
std::vector<CompressParams> all_params;
std::vector<size_t> size;
CompressParams cparams_attempt = cparams_orig;
cparams_attempt.speed_tier = SpeedTier::kTortoise;
cparams_attempt.speed_tier = SpeedTier::kGlacier;
cparams_attempt.options.max_properties = 4;
for (float x : {0.0f, 80.f}) {
@ -2054,11 +2129,12 @@ Status EncodeFrame(const CompressParams& cparams_orig,
size.resize(all_params.size());
std::atomic<int> num_errors{0};
std::atomic<bool> has_error{false};
JXL_RETURN_IF_ERROR(RunOnPool(
pool, 0, all_params.size(), ThreadPool::NoInit,
[&](size_t task, size_t) {
if (has_error) return;
std::vector<uint8_t> output(64);
uint8_t* next_out = output.data();
size_t avail_out = output.size();
@ -2066,13 +2142,13 @@ Status EncodeFrame(const CompressParams& cparams_orig,
local_output.SetAvailOut(&next_out, &avail_out);
if (!EncodeFrame(all_params[task], frame_info, metadata, frame_data,
cms, nullptr, &local_output, aux_out)) {
num_errors.fetch_add(1, std::memory_order_relaxed);
has_error = true;
return;
}
size[task] = local_output.CurrentPosition();
},
"Compress kGlacier"));
JXL_RETURN_IF_ERROR(num_errors.load(std::memory_order_relaxed) == 0);
"Compress kTectonicPlate"));
if (has_error) return JXL_FAILURE("Compress kTectonicPlate failed");
size_t best_idx = 0;
for (size_t i = 1; i < all_params.size(); i++) {
@ -2156,7 +2232,7 @@ Status EncodeFrame(const CompressParams& cparams_orig,
size_t stride = ib.xsize() * num_channels * 4;
color.resize(ib.ysize() * stride);
JXL_RETURN_IF_ERROR(ConvertToExternal(
ib, /*bites_per_sample=*/32, /*float_out=*/true, num_channels,
ib, /*bits_per_sample=*/32, /*float_out=*/true, num_channels,
JXL_NATIVE_ENDIAN, stride, pool, color.data(), color.size(),
/*out_callback=*/{}, Orientation::kIdentity));
JxlPixelFormat format{num_channels, JXL_TYPE_FLOAT, JXL_NATIVE_ENDIAN, 0};
@ -2169,7 +2245,7 @@ Status EncodeFrame(const CompressParams& cparams_orig,
const ImageF* channel = &ib.extra_channels()[ec];
JXL_RETURN_IF_ERROR(ConvertChannelsToExternal(
&channel, 1,
/*bites_per_sample=*/32,
/*bits_per_sample=*/32,
/*float_out=*/true, JXL_NATIVE_ENDIAN, ec_stride, pool, ec_data.data(),
ec_data.size(), /*out_callback=*/{}, Orientation::kIdentity));
frame_data.SetFromBuffer(1 + ec, ec_data.data(), ec_data.size(), ec_format);

9
third_party/jpeg-xl/lib/jxl/enc_gaborish.cc поставляемый
Просмотреть файл

@ -15,8 +15,8 @@
namespace jxl {
void GaborishInverse(Image3F* in_out, const Rect& rect, float mul[3],
ThreadPool* pool) {
Status GaborishInverse(Image3F* in_out, const Rect& rect, const float mul[3],
ThreadPool* pool) {
WeightsSymmetric5 weights[3];
// Only an approximation. One or even two 3x3, and rank-1 (separable) 5x5
// are insufficient. The numbers here have been obtained by butteraugli
@ -47,7 +47,9 @@ void GaborishInverse(Image3F* in_out, const Rect& rect, float mul[3],
// Note that we cannot *allocate* a plane, as doing so might cause Image3F to
// have planes of different stride. Instead, we copy one plane in a temporary
// image and reuse the existing planes of the in/out image.
ImageF temp(in_out->Plane(2).xsize(), in_out->Plane(2).ysize());
ImageF temp;
JXL_ASSIGN_OR_RETURN(
temp, ImageF::Create(in_out->Plane(2).xsize(), in_out->Plane(2).ysize()));
CopyImageTo(in_out->Plane(2), &temp);
Rect xrect = rect.Extend(3, Rect(*in_out));
Symmetric5(in_out->Plane(0), xrect, weights[0], pool, &in_out->Plane(2),
@ -59,6 +61,7 @@ void GaborishInverse(Image3F* in_out, const Rect& rect, float mul[3],
in_out->Plane(0).Swap(in_out->Plane(1));
// 2 1 0
in_out->Plane(0).Swap(in_out->Plane(2));
return true;
}
} // namespace jxl

5
third_party/jpeg-xl/lib/jxl/enc_gaborish.h поставляемый
Просмотреть файл

@ -9,6 +9,7 @@
// Linear smoothing (3x3 convolution) for deblocking without too much blur.
#include "lib/jxl/base/data_parallel.h"
#include "lib/jxl/base/status.h"
#include "lib/jxl/image.h"
namespace jxl {
@ -16,8 +17,8 @@ namespace jxl {
// Used in encoder to reduce the impact of the decoder's smoothing.
// This is not exact. Works in-place to reduce memory use.
// The input is typically in XYB space.
void GaborishInverse(Image3F* in_out, const Rect& rect, float mul[3],
ThreadPool* pool);
Status GaborishInverse(Image3F* in_out, const Rect& rect, const float mul[3],
ThreadPool* pool);
} // namespace jxl

Просмотреть файл

@ -40,7 +40,7 @@ void ConvolveGaborish(const ImageF& in, float weight1, float weight2,
}
void TestRoundTrip(const Image3F& in, float max_l1) {
Image3F fwd(in.xsize(), in.ysize());
JXL_ASSIGN_OR_DIE(Image3F fwd, Image3F::Create(in.xsize(), in.ysize()));
ThreadPool* null_pool = nullptr;
ConvolveGaborish(in.Plane(0), 0, 0, null_pool, &fwd.Plane(0));
ConvolveGaborish(in.Plane(1), 0, 0, null_pool, &fwd.Plane(1));
@ -51,12 +51,12 @@ void TestRoundTrip(const Image3F& in, float max_l1) {
w,
w,
};
GaborishInverse(&fwd, Rect(fwd), weights, null_pool);
JXL_CHECK(GaborishInverse(&fwd, Rect(fwd), weights, null_pool));
JXL_ASSERT_OK(VerifyRelativeError(in, fwd, max_l1, 1E-4f, _));
}
TEST(GaborishTest, TestZero) {
Image3F in(20, 20);
JXL_ASSIGN_OR_DIE(Image3F in, Image3F::Create(20, 20));
ZeroFillImage(&in);
TestRoundTrip(in, 0.0f);
}
@ -64,7 +64,7 @@ TEST(GaborishTest, TestZero) {
// Disabled: large difference.
#if 0
TEST(GaborishTest, TestDirac) {
Image3F in(20, 20);
JXL_ASSIGN_OR_DIE(Image3F in, Image3F::Create(20, 20));
ZeroFillImage(&in);
in.PlaneRow(1, 10)[10] = 10.0f;
TestRoundTrip(in, 0.26f);
@ -72,7 +72,7 @@ TEST(GaborishTest, TestDirac) {
#endif
TEST(GaborishTest, TestFlat) {
Image3F in(20, 20);
JXL_ASSIGN_OR_DIE(Image3F in, Image3F::Create(20, 20));
FillImage(1.0f, &in);
TestRoundTrip(in, 1E-5f);
}

7
third_party/jpeg-xl/lib/jxl/enc_group.cc поставляемый
Просмотреть файл

@ -316,7 +316,7 @@ void QuantizeRoundtripYBlockAC(PassesEncoderState* enc_state, const size_t size,
float* JXL_RESTRICT inout,
int32_t* JXL_RESTRICT quantized) {
float thres_y[4] = {0.58f, 0.64f, 0.64f, 0.64f};
{
if (enc_state->cparams.speed_tier <= SpeedTier::kHare) {
int32_t max_quant = 0;
int quant_orig = *quant;
float val[3] = {enc_state->x_qm_multiplier, 1.0f,
@ -337,6 +337,11 @@ void QuantizeRoundtripYBlockAC(PassesEncoderState* enc_state, const size_t size,
max_quant = std::max(*quant, max_quant);
}
*quant = max_quant;
} else {
thres_y[0] = 0.56;
thres_y[1] = 0.62;
thres_y[2] = 0.62;
thres_y[3] = 0.62;
}
QuantizeBlockAC(quantizer, error_diffusion, 1, 1.0f, quant_kind, xsize, ysize,

171
third_party/jpeg-xl/lib/jxl/enc_heuristics.cc поставляемый
Просмотреть файл

@ -190,9 +190,9 @@ void FindBestBlockEntropyModel(const CompressParams& cparams, const ImageI& rqf,
namespace {
void FindBestDequantMatrices(const CompressParams& cparams,
ModularFrameEncoder* modular_frame_encoder,
DequantMatrices* dequant_matrices) {
Status FindBestDequantMatrices(const CompressParams& cparams,
ModularFrameEncoder* modular_frame_encoder,
DequantMatrices* dequant_matrices) {
// TODO(veluca): quant matrices for no-gaborish.
// TODO(veluca): heuristics for in-bitstream quant tables.
*dequant_matrices = DequantMatrices();
@ -204,13 +204,14 @@ void FindBestDequantMatrices(const CompressParams& cparams,
DctQuantWeightParams dct_params(weights);
std::vector<QuantEncoding> encodings(DequantMatrices::kNum,
QuantEncoding::DCT(dct_params));
DequantMatricesSetCustom(dequant_matrices, encodings,
modular_frame_encoder);
JXL_RETURN_IF_ERROR(DequantMatricesSetCustom(dequant_matrices, encodings,
modular_frame_encoder));
float dc_weights[3] = {1.0f / cparams.max_error[0],
1.0f / cparams.max_error[1],
1.0f / cparams.max_error[2]};
DequantMatricesSetCustomDC(dequant_matrices, dc_weights);
}
return true;
}
void StoreMin2(const float v, float& min1, float& min2) {
@ -226,9 +227,9 @@ void StoreMin2(const float v, float& min1, float& min2) {
void CreateMask(const ImageF& image, ImageF& mask) {
for (size_t y = 0; y < image.ysize(); y++) {
auto* row_n = y > 0 ? image.Row(y - 1) : image.Row(y);
auto* row_in = image.Row(y);
auto* row_s = y + 1 < image.ysize() ? image.Row(y + 1) : image.Row(y);
const auto* row_n = y > 0 ? image.Row(y - 1) : image.Row(y);
const auto* row_in = image.Row(y);
const auto* row_s = y + 1 < image.ysize() ? image.Row(y + 1) : image.Row(y);
auto* row_out = mask.Row(y);
for (size_t x = 0; x < image.xsize(); x++) {
// Center, west, east, north, south values and their absolute difference
@ -258,7 +259,7 @@ void CreateMask(const ImageF& image, ImageF& mask) {
// by the decoder. Ringing is slightly reduced by clamping the values of the
// resulting pixels within certain bounds of a small region in the original
// image.
void DownsampleImage2_Sharper(const ImageF& input, ImageF* output) {
Status DownsampleImage2_Sharper(const ImageF& input, ImageF* output) {
const int64_t kernelx = 12;
const int64_t kernely = 12;
@ -315,11 +316,12 @@ void DownsampleImage2_Sharper(const ImageF& input, ImageF* output) {
int64_t xsize = input.xsize();
int64_t ysize = input.ysize();
ImageF box_downsample(xsize, ysize);
JXL_ASSIGN_OR_RETURN(ImageF box_downsample, ImageF::Create(xsize, ysize));
CopyImageTo(input, &box_downsample);
DownsampleImage(&box_downsample, 2);
JXL_ASSIGN_OR_RETURN(box_downsample, DownsampleImage(box_downsample, 2));
ImageF mask(box_downsample.xsize(), box_downsample.ysize());
JXL_ASSIGN_OR_RETURN(ImageF mask, ImageF::Create(box_downsample.xsize(),
box_downsample.ysize()));
CreateMask(box_downsample, mask);
for (size_t y = 0; y < output->ysize(); y++) {
@ -379,50 +381,54 @@ void DownsampleImage2_Sharper(const ImageF& input, ImageF* output) {
}
}
}
return true;
}
} // namespace
void DownsampleImage2_Sharper(Image3F* opsin) {
Status DownsampleImage2_Sharper(Image3F* opsin) {
// Allocate extra space to avoid a reallocation when padding.
Image3F downsampled(DivCeil(opsin->xsize(), 2) + kBlockDim,
DivCeil(opsin->ysize(), 2) + kBlockDim);
JXL_ASSIGN_OR_RETURN(Image3F downsampled,
Image3F::Create(DivCeil(opsin->xsize(), 2) + kBlockDim,
DivCeil(opsin->ysize(), 2) + kBlockDim));
downsampled.ShrinkTo(downsampled.xsize() - kBlockDim,
downsampled.ysize() - kBlockDim);
for (size_t c = 0; c < 3; c++) {
DownsampleImage2_Sharper(opsin->Plane(c), &downsampled.Plane(c));
JXL_RETURN_IF_ERROR(
DownsampleImage2_Sharper(opsin->Plane(c), &downsampled.Plane(c)));
}
*opsin = std::move(downsampled);
return true;
}
namespace {
// The default upsampling kernels used by Upsampler in the decoder.
static const constexpr int64_t kSize = 5;
const constexpr int64_t kSize = 5;
static const float kernel00[25] = {
const float kernel00[25] = {
-0.01716200f, -0.03452303f, -0.04022174f, -0.02921014f, -0.00624645f,
-0.03452303f, 0.14111091f, 0.28896755f, 0.00278718f, -0.01610267f,
-0.04022174f, 0.28896755f, 0.56661550f, 0.03777607f, -0.01986694f,
-0.02921014f, 0.00278718f, 0.03777607f, -0.03144731f, -0.01185068f,
-0.00624645f, -0.01610267f, -0.01986694f, -0.01185068f, -0.00213539f,
};
static const float kernel01[25] = {
const float kernel01[25] = {
-0.00624645f, -0.01610267f, -0.01986694f, -0.01185068f, -0.00213539f,
-0.02921014f, 0.00278718f, 0.03777607f, -0.03144731f, -0.01185068f,
-0.04022174f, 0.28896755f, 0.56661550f, 0.03777607f, -0.01986694f,
-0.03452303f, 0.14111091f, 0.28896755f, 0.00278718f, -0.01610267f,
-0.01716200f, -0.03452303f, -0.04022174f, -0.02921014f, -0.00624645f,
};
static const float kernel10[25] = {
const float kernel10[25] = {
-0.00624645f, -0.02921014f, -0.04022174f, -0.03452303f, -0.01716200f,
-0.01610267f, 0.00278718f, 0.28896755f, 0.14111091f, -0.03452303f,
-0.01986694f, 0.03777607f, 0.56661550f, 0.28896755f, -0.04022174f,
-0.01185068f, -0.03144731f, 0.03777607f, 0.00278718f, -0.02921014f,
-0.00213539f, -0.01185068f, -0.01986694f, -0.01610267f, -0.00624645f,
};
static const float kernel11[25] = {
const float kernel11[25] = {
-0.00213539f, -0.01185068f, -0.01986694f, -0.01610267f, -0.00624645f,
-0.01185068f, -0.03144731f, 0.03777607f, 0.00278718f, -0.02921014f,
-0.01986694f, 0.03777607f, 0.56661550f, 0.28896755f, -0.04022174f,
@ -435,14 +441,14 @@ static const float kernel11[25] = {
// TODO(lode): use Upsampler instead. However, it requires pre-initialization
// and padding on the left side of the image which requires refactoring the
// other code using this.
static void UpsampleImage(const ImageF& input, ImageF* output) {
void UpsampleImage(const ImageF& input, ImageF* output) {
int64_t xsize = input.xsize();
int64_t ysize = input.ysize();
int64_t xsize2 = output->xsize();
int64_t ysize2 = output->ysize();
for (int64_t y = 0; y < ysize2; y++) {
for (int64_t x = 0; x < xsize2; x++) {
auto kernel = kernel00;
const auto* kernel = kernel00;
if ((x & 1) && (y & 1)) {
kernel = kernel11;
} else if (x & 1) {
@ -492,7 +498,7 @@ static void UpsampleImage(const ImageF& input, ImageF* output) {
// Returns the derivative of Upsampler, with respect to input pixel x2, y2, to
// output pixel x, y (ignoring the clamping).
float UpsamplerDeriv(int64_t x2, int64_t y2, int64_t x, int64_t y) {
auto kernel = kernel00;
const auto* kernel = kernel00;
if ((x & 1) && (y & 1)) {
kernel = kernel11;
} else if (x & 1) {
@ -599,9 +605,7 @@ void ReduceRinging(const ImageF& initial, const ImageF& mask, ImageF& down) {
for (int64_t xi = -1; xi < 2; xi++) {
int64_t x2 = (int64_t)x + xi;
int64_t y2 = (int64_t)y + yi;
if (x2 < 0 || y2 < 0 || x2 >= (int64_t)xsize2 ||
y2 >= (int64_t)ysize2)
continue;
if (x2 < 0 || y2 < 0 || x2 >= xsize2 || y2 >= ysize2) continue;
min = std::min<float>(min, initial.Row(y2)[x2]);
max = std::max<float>(max, initial.Row(y2)[x2]);
}
@ -625,32 +629,35 @@ void ReduceRinging(const ImageF& initial, const ImageF& mask, ImageF& down) {
}
// TODO(lode): move this to a separate file enc_downsample.cc
void DownsampleImage2_Iterative(const ImageF& orig, ImageF* output) {
Status DownsampleImage2_Iterative(const ImageF& orig, ImageF* output) {
int64_t xsize = orig.xsize();
int64_t ysize = orig.ysize();
int64_t xsize2 = DivCeil(orig.xsize(), 2);
int64_t ysize2 = DivCeil(orig.ysize(), 2);
ImageF box_downsample(xsize, ysize);
JXL_ASSIGN_OR_RETURN(ImageF box_downsample, ImageF::Create(xsize, ysize));
CopyImageTo(orig, &box_downsample);
DownsampleImage(&box_downsample, 2);
ImageF mask(box_downsample.xsize(), box_downsample.ysize());
JXL_ASSIGN_OR_RETURN(box_downsample, DownsampleImage(box_downsample, 2));
JXL_ASSIGN_OR_RETURN(ImageF mask, ImageF::Create(box_downsample.xsize(),
box_downsample.ysize()));
CreateMask(box_downsample, mask);
output->ShrinkTo(xsize2, ysize2);
// Initial result image using the sharper downsampling.
// Allocate extra space to avoid a reallocation when padding.
ImageF initial(DivCeil(orig.xsize(), 2) + kBlockDim,
DivCeil(orig.ysize(), 2) + kBlockDim);
JXL_ASSIGN_OR_RETURN(ImageF initial,
ImageF::Create(DivCeil(orig.xsize(), 2) + kBlockDim,
DivCeil(orig.ysize(), 2) + kBlockDim));
initial.ShrinkTo(initial.xsize() - kBlockDim, initial.ysize() - kBlockDim);
DownsampleImage2_Sharper(orig, &initial);
JXL_RETURN_IF_ERROR(DownsampleImage2_Sharper(orig, &initial));
ImageF down(initial.xsize(), initial.ysize());
JXL_ASSIGN_OR_RETURN(ImageF down,
ImageF::Create(initial.xsize(), initial.ysize()));
CopyImageTo(initial, &down);
ImageF up(xsize, ysize);
ImageF corr(xsize, ysize);
ImageF corr2(xsize2, ysize2);
JXL_ASSIGN_OR_RETURN(ImageF up, ImageF::Create(xsize, ysize));
JXL_ASSIGN_OR_RETURN(ImageF corr, ImageF::Create(xsize, ysize));
JXL_ASSIGN_OR_RETURN(ImageF corr2, ImageF::Create(xsize2, ysize2));
// In the weights map, relatively higher values will allow less ringing but
// also less sharpness. With all constant values, it optimizes equally
@ -659,25 +666,25 @@ void DownsampleImage2_Iterative(const ImageF& orig, ImageF* output) {
// TODO(lode): Make use of the weights field for anti-ringing and clamping,
// the values are all set to 1 for now, but it is intended to be used for
// reducing ringing based on the mask, and taking clamping into account.
ImageF weights(xsize, ysize);
JXL_ASSIGN_OR_RETURN(ImageF weights, ImageF::Create(xsize, ysize));
for (size_t y = 0; y < weights.ysize(); y++) {
auto* row = weights.Row(y);
for (size_t x = 0; x < weights.xsize(); x++) {
row[x] = 1;
}
}
ImageF weights2(xsize2, ysize2);
JXL_ASSIGN_OR_RETURN(ImageF weights2, ImageF::Create(xsize2, ysize2));
AntiUpsample(weights, &weights2);
const size_t num_it = 3;
for (size_t it = 0; it < num_it; ++it) {
UpsampleImage(down, &up);
corr = LinComb<float>(1, orig, -1, up);
JXL_ASSIGN_OR_RETURN(corr, LinComb<float>(1, orig, -1, up));
ElwiseMul(corr, weights, &corr);
AntiUpsample(corr, &corr2);
ElwiseDiv(corr2, weights2, &corr2);
down = LinComb<float>(1, down, 1, corr2);
JXL_ASSIGN_OR_RETURN(down, LinComb<float>(1, down, 1, corr2));
}
ReduceRinging(initial, mask, down);
@ -690,32 +697,40 @@ void DownsampleImage2_Iterative(const ImageF& orig, ImageF* output) {
output->Row(y)[x] = v;
}
}
return true;
}
} // namespace
void DownsampleImage2_Iterative(Image3F* opsin) {
Status DownsampleImage2_Iterative(Image3F* opsin) {
// Allocate extra space to avoid a reallocation when padding.
Image3F downsampled(DivCeil(opsin->xsize(), 2) + kBlockDim,
DivCeil(opsin->ysize(), 2) + kBlockDim);
JXL_ASSIGN_OR_RETURN(Image3F downsampled,
Image3F::Create(DivCeil(opsin->xsize(), 2) + kBlockDim,
DivCeil(opsin->ysize(), 2) + kBlockDim));
downsampled.ShrinkTo(downsampled.xsize() - kBlockDim,
downsampled.ysize() - kBlockDim);
Image3F rgb(opsin->xsize(), opsin->ysize());
JXL_ASSIGN_OR_RETURN(Image3F rgb,
Image3F::Create(opsin->xsize(), opsin->ysize()));
OpsinParams opsin_params; // TODO(user): use the ones that are actually used
opsin_params.Init(kDefaultIntensityTarget);
OpsinToLinear(*opsin, Rect(rgb), nullptr, &rgb, opsin_params);
ImageF mask(opsin->xsize(), opsin->ysize());
JXL_ASSIGN_OR_RETURN(ImageF mask,
ImageF::Create(opsin->xsize(), opsin->ysize()));
ButteraugliParams butter_params;
ButteraugliComparator butter(rgb, butter_params);
butter.Mask(&mask);
ImageF mask_fuzzy(opsin->xsize(), opsin->ysize());
JXL_ASSIGN_OR_RETURN(std::unique_ptr<ButteraugliComparator> butter,
ButteraugliComparator::Make(rgb, butter_params));
JXL_RETURN_IF_ERROR(butter->Mask(&mask));
JXL_ASSIGN_OR_RETURN(ImageF mask_fuzzy,
ImageF::Create(opsin->xsize(), opsin->ysize()));
for (size_t c = 0; c < 3; c++) {
DownsampleImage2_Iterative(opsin->Plane(c), &downsampled.Plane(c));
JXL_RETURN_IF_ERROR(
DownsampleImage2_Iterative(opsin->Plane(c), &downsampled.Plane(c)));
}
*opsin = std::move(downsampled);
return true;
}
Status LossyFrameHeuristics(const FrameHeader& frame_header,
@ -739,10 +754,11 @@ Status LossyFrameHeuristics(const FrameHeader& frame_header,
BlockCtxMap& block_ctx_map = shared.block_ctx_map;
// Find and subtract splines.
if (cparams.custom_splines.HasAny()) {
image_features.splines = cparams.custom_splines;
}
if (!streaming_mode && cparams.speed_tier <= SpeedTier::kSquirrel) {
if (cparams.custom_splines.HasAny()) {
image_features.splines = cparams.custom_splines;
} else {
if (!cparams.custom_splines.HasAny()) {
image_features.splines = FindSplines(*opsin);
}
JXL_RETURN_IF_ERROR(image_features.splines.InitializeDrawCache(
@ -754,7 +770,8 @@ Status LossyFrameHeuristics(const FrameHeader& frame_header,
if (!streaming_mode &&
ApplyOverride(cparams.patches,
cparams.speed_tier <= SpeedTier::kSquirrel)) {
FindBestPatchDictionary(*opsin, enc_state, cms, pool, aux_out);
JXL_RETURN_IF_ERROR(
FindBestPatchDictionary(*opsin, enc_state, cms, pool, aux_out));
PatchDictionaryEncoder::SubtractFrom(image_features.patches, opsin);
}
@ -791,10 +808,12 @@ Status LossyFrameHeuristics(const FrameHeader& frame_header,
// on simple heuristics in FindBestAcStrategy, or set a constant for Falcon
// mode.
if (cparams.speed_tier > SpeedTier::kHare) {
initial_quant_field =
ImageF(frame_dim.xsize_blocks, frame_dim.ysize_blocks);
initial_quant_masking =
ImageF(frame_dim.xsize_blocks, frame_dim.ysize_blocks);
JXL_ASSIGN_OR_RETURN(
initial_quant_field,
ImageF::Create(frame_dim.xsize_blocks, frame_dim.ysize_blocks));
JXL_ASSIGN_OR_RETURN(
initial_quant_masking,
ImageF::Create(frame_dim.xsize_blocks, frame_dim.ysize_blocks));
float q = 0.79 / cparams.butteraugli_distance;
FillImage(q, &initial_quant_field);
FillImage(1.0f / (q + 0.001f), &initial_quant_masking);
@ -805,9 +824,11 @@ Status LossyFrameHeuristics(const FrameHeader& frame_header,
if (!frame_header.loop_filter.gab) {
butteraugli_distance_for_iqf *= 0.73f;
}
initial_quant_field = InitialQuantField(
butteraugli_distance_for_iqf, *opsin, rect, pool, 1.0f,
&initial_quant_masking, &initial_quant_masking1x1);
JXL_ASSIGN_OR_RETURN(
initial_quant_field,
InitialQuantField(butteraugli_distance_for_iqf, *opsin, rect, pool,
1.0f, &initial_quant_masking,
&initial_quant_masking1x1));
float q = 0.39 / cparams.butteraugli_distance;
quantizer.ComputeGlobalScaleAndQuant(quant_dc, q, 0);
}
@ -822,18 +843,21 @@ Status LossyFrameHeuristics(const FrameHeader& frame_header,
0.99406123118127299f,
0.99719338015886894f,
};
GaborishInverse(opsin, rect, weight, pool);
JXL_RETURN_IF_ERROR(GaborishInverse(opsin, rect, weight, pool));
}
if (initialize_global_state) {
FindBestDequantMatrices(cparams, modular_frame_encoder, &matrices);
JXL_RETURN_IF_ERROR(
FindBestDequantMatrices(cparams, modular_frame_encoder, &matrices));
}
cfl_heuristics.Init(rect);
JXL_RETURN_IF_ERROR(cfl_heuristics.Init(rect));
acs_heuristics.Init(*opsin, rect, initial_quant_field, initial_quant_masking,
initial_quant_masking1x1, &matrices);
std::atomic<bool> has_error{false};
auto process_tile = [&](const uint32_t tid, const size_t thread) {
if (has_error) return;
size_t n_enc_tiles = DivCeil(frame_dim.xsize_blocks, kEncTileDimInBlocks);
size_t tx = tid % n_enc_tiles;
size_t ty = tid / n_enc_tiles;
@ -860,9 +884,12 @@ Status LossyFrameHeuristics(const FrameHeader& frame_header,
// Choose amount of post-processing smoothing.
// TODO(veluca): should this go *after* AdjustQuantField?
ar_heuristics.RunRect(cparams, frame_header, r, *opsin, rect,
initial_quant_field, ac_strategy, &epf_sharpness,
thread);
if (!ar_heuristics.RunRect(cparams, frame_header, r, *opsin, rect,
initial_quant_field, ac_strategy, &epf_sharpness,
thread)) {
has_error = true;
return;
}
// Always set the initial quant field, so we can compute the CfL map with
// more accuracy. The initial quant field might change in slower modes, but
@ -889,13 +916,15 @@ Status LossyFrameHeuristics(const FrameHeader& frame_header,
return true;
},
process_tile, "Enc Heuristics"));
if (has_error) return JXL_FAILURE("Enc Heuristics failed");
acs_heuristics.Finalize(frame_dim, ac_strategy, aux_out);
JXL_RETURN_IF_ERROR(acs_heuristics.Finalize(frame_dim, ac_strategy, aux_out));
// Refine quantization levels.
if (!streaming_mode) {
FindBestQuantizer(frame_header, original_pixels, *opsin,
initial_quant_field, enc_state, cms, pool, aux_out);
JXL_RETURN_IF_ERROR(FindBestQuantizer(frame_header, original_pixels, *opsin,
initial_quant_field, enc_state, cms,
pool, aux_out));
}
// Choose a context model that depends on the amount of quantization for AC.

Просмотреть файл

@ -38,8 +38,8 @@ Status LossyFrameHeuristics(const FrameHeader& frame_header,
void FindBestBlockEntropyModel(PassesEncoderState& enc_state);
void DownsampleImage2_Iterative(Image3F* output);
void DownsampleImage2_Sharper(Image3F* opsin);
Status DownsampleImage2_Iterative(Image3F* opsin);
Status DownsampleImage2_Sharper(Image3F* opsin);
} // namespace jxl

Просмотреть файл

@ -13,6 +13,7 @@
#include <vector>
#include "lib/jxl/base/byte_order.h"
#include "lib/jxl/color_encoding_internal.h"
#include "lib/jxl/enc_ans.h"
#include "lib/jxl/enc_aux_out.h"
#include "lib/jxl/fields.h"

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше