// Copyright (c) the JPEG XL Project Authors. All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file.
namespace jxl {
BitDepth::BitDepth() { Bundle::Init(this); }
Status BitDepth::VisitFields(Visitor* JXL_RESTRICT visitor) {
JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &floating_point_sample)); // The same fields (bits_per_sample and exponent_bits_per_sample) are read // in a different way depending on floating_point_sample's value. It's still // default-initialized correctly so using visitor->Conditional is not // required. if (!floating_point_sample) {
JXL_QUIET_RETURN_IF_ERROR(visitor->U32(
Val(8), Val(10), Val(12), BitsOffset(6, 1), 8, &bits_per_sample));
exponent_bits_per_sample = 0;
} else {
JXL_QUIET_RETURN_IF_ERROR(visitor->U32(
Val(32), Val(16), Val(24), BitsOffset(6, 1), 32, &bits_per_sample)); // The encoded value is exponent_bits_per_sample - 1, encoded in 3 bits // so the value can be in range [1, 8]. const uint32_t offset = 1;
exponent_bits_per_sample -= offset;
JXL_QUIET_RETURN_IF_ERROR(
visitor->Bits(4, 8 - offset, &exponent_bits_per_sample));
exponent_bits_per_sample += offset;
}
// Error-checking for floating point ranges. if (floating_point_sample) { if (exponent_bits_per_sample < 2 || exponent_bits_per_sample > 8) { return JXL_FAILURE("Invalid exponent_bits_per_sample: %u",
exponent_bits_per_sample);
} int mantissa_bits = static_cast<int>(bits_per_sample) - exponent_bits_per_sample - 1; if (mantissa_bits < 2 || mantissa_bits > 23) { return JXL_FAILURE("Invalid bits_per_sample: %u", bits_per_sample);
}
} else { if (bits_per_sample > 31) { return JXL_FAILURE("Invalid bits_per_sample: %u", bits_per_sample);
}
} returntrue;
}
#if JXL_DEBUG_V_LEVEL >= 1
std::string BitDepth::DebugString() const {
std::ostringstream os;
os << (floating_point_sample ? "F" : "U");
os << bits_per_sample; if (floating_point_sample) os << "." << exponent_bits_per_sample; return os.str();
} #endif
CustomTransformData::CustomTransformData() { Bundle::Init(this); }
Status CustomTransformData::VisitFields(Visitor* JXL_RESTRICT visitor) { if (visitor->AllDefault(*this, &all_default)) { // Overwrite all serialized fields, but not any nonserialized_*.
visitor->SetDefault(this); returntrue;
} if (visitor->Conditional(nonserialized_xyb_encoded)) {
JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&opsin_inverse_matrix));
}
JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(3, 0, &custom_weights_mask)); if (visitor->Conditional((custom_weights_mask & 0x1) != 0)) { // 4 5x5 kernels, but all of them can be obtained by symmetry from one, // which is symmetric along its main diagonal. The top-left kernel is // defined by // // 0 1 2 3 4 // 1 5 6 7 8 // 2 6 9 10 11 // 3 7 10 12 13 // 4 8 11 13 14 float constexpr kWeights2[15] = {
-0.01716200f, -0.03452303f, -0.04022174f, -0.02921014f, -0.00624645f,
0.14111091f, 0.28896755f, 0.00278718f, -0.01610267f, 0.56661550f,
0.03777607f, -0.01986694f, -0.03144731f, -0.01185068f, -0.00213539f}; for (size_t i = 0; i < 15; i++) {
JXL_QUIET_RETURN_IF_ERROR(
visitor->F16(kWeights2[i], &upsampling2_weights[i]));
}
} if (visitor->Conditional((custom_weights_mask & 0x2) != 0)) { // 16 5x5 kernels, but all of them can be obtained by symmetry from // three, two of which are symmetric along their main diagonals. The top // left 4 kernels are defined by // // 0 1 2 3 4 5 6 7 8 9 // 1 10 11 12 13 14 15 16 17 18 // 2 11 19 20 21 22 23 24 25 26 // 3 12 20 27 28 29 30 31 32 33 // 4 13 21 28 34 35 36 37 38 39 // // 5 14 22 29 35 40 41 42 43 44 // 6 15 23 30 36 41 45 46 47 48 // 7 16 24 31 37 42 46 49 50 51 // 8 17 25 32 38 43 47 50 52 53 // 9 18 26 33 39 44 48 51 53 54
constexpr float kWeights4[55] = {
-0.02419067f, -0.03491987f, -0.03693351f, -0.03094285f, -0.00529785f,
-0.01663432f, -0.03556863f, -0.03888905f, -0.03516850f, -0.00989469f,
0.23651958f, 0.33392945f, -0.01073543f, -0.01313181f, -0.03556694f,
0.13048175f, 0.40103025f, 0.03951150f, -0.02077584f, 0.46914198f,
-0.00209270f, -0.01484589f, -0.04064806f, 0.18942530f, 0.56279892f,
0.06674400f, -0.02335494f, -0.03551682f, -0.00754830f, -0.02267919f,
-0.02363578f, 0.00315804f, -0.03399098f, -0.01359519f, -0.00091653f,
-0.00335467f, -0.01163294f, -0.01610294f, -0.00974088f, -0.00191622f,
-0.01095446f, -0.03198464f, -0.04455121f, -0.02799790f, -0.00645912f,
0.06390599f, 0.22963888f, 0.00630981f, -0.01897349f, 0.67537268f,
0.08483369f, -0.02534994f, -0.02205197f, -0.01667999f, -0.00384443f}; for (size_t i = 0; i < 55; i++) {
JXL_QUIET_RETURN_IF_ERROR(
visitor->F16(kWeights4[i], &upsampling4_weights[i]));
}
} if (visitor->Conditional((custom_weights_mask & 0x4) != 0)) { // typo:off // 64 5x5 kernels, all of them can be obtained by symmetry from // 10, 4 of which are symmetric along their main diagonals. The top // left 16 kernels are defined by // 0 1 2 3 4 5 6 7 8 9 a b c d e f 10 11 12 13 // 1 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 // 2 15 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 // 3 16 28 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 // 4 17 29 3a 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59
ExtraChannelInfo::ExtraChannelInfo() { Bundle::Init(this); }
Status ExtraChannelInfo::VisitFields(Visitor* JXL_RESTRICT visitor) { if (visitor->AllDefault(*this, &all_default)) { // Overwrite all serialized fields, but not any nonserialized_*.
visitor->SetDefault(this); returntrue;
}
// General
JXL_QUIET_RETURN_IF_ERROR(visitor->Enum(ExtraChannel::kAlpha, &type));
// Conditional if (visitor->Conditional(type == ExtraChannel::kAlpha)) {
JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &alpha_associated));
} if (visitor->Conditional(type == ExtraChannel::kSpotColor)) { for (float& c : spot_color) {
JXL_QUIET_RETURN_IF_ERROR(visitor->F16(0, &c));
}
} if (visitor->Conditional(type == ExtraChannel::kCFA)) {
JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(1), Bits(2), BitsOffset(4, 3),
BitsOffset(8, 19), 1, &cfa_channel));
}
if (type == ExtraChannel::kUnknown ||
(static_cast<int>(ExtraChannel::kReserved0) <= static_cast<int>(type) && static_cast<int>(type) <= static_cast<int>(ExtraChannel::kReserved7))) { return JXL_FAILURE("Unknown extra channel (bits %u, shift %u, name '%s')\n",
bit_depth.bits_per_sample, dim_shift, name.c_str());
} returntrue;
}
#if JXL_DEBUG_V_LEVEL >= 1
std::string ExtraChannelInfo::DebugString() const {
std::ostringstream os;
os << (type == ExtraChannel::kAlpha ? "Alpha"
: type == ExtraChannel::kDepth ? "Depth"
: type == ExtraChannel::kSpotColor ? "Spot"
: type == ExtraChannel::kSelectionMask ? "Mask"
: type == ExtraChannel::kBlack ? "Black"
: type == ExtraChannel::kCFA ? "CFA"
: type == ExtraChannel::kThermal ? "Thermal"
: "Unknown"); if (type == ExtraChannel::kAlpha && alpha_associated) os << "(premul)";
os << " " << bit_depth.DebugString();
os << " shift: " << dim_shift; return os.str();
} #endif
ImageMetadata::ImageMetadata() { Bundle::Init(this); }
Status ImageMetadata::VisitFields(Visitor* JXL_RESTRICT visitor) { if (visitor->AllDefault(*this, &all_default)) { // Overwrite all serialized fields, but not any nonserialized_*.
visitor->SetDefault(this); returntrue;
}
// Bundle::AllDefault does not allow usage when reading (it may abort the // program when a codestream has invalid values), but when reading we // overwrite the extra_fields value, so do not need to call AllDefault. bool tone_mapping_default =
visitor->IsReading() ? false : Bundle::AllDefault(tone_mapping);
bool extra_fields = (orientation != 1 || have_preview || have_animation ||
have_intrinsic_size || !tone_mapping_default);
JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &extra_fields)); if (visitor->Conditional(extra_fields)) {
orientation--;
JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(3, 0, &orientation));
orientation++; // (No need for bounds checking because we read exactly 3 bits)
if (visitor->Conditional(num_extra_channels != 0)) { if (visitor->IsReading()) {
extra_channel_info.resize(num_extra_channels);
} for (ExtraChannelInfo& eci : extra_channel_info) {
JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&eci));
}
}
JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(true, &xyb_encoded));
JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&color_encoding)); if (visitor->Conditional(extra_fields)) {
JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&tone_mapping));
}
// Treat as if only the fields up to extra channels exist. if (visitor->IsReading() && nonserialized_only_parse_basic_info) { returntrue;
}
JXL_QUIET_RETURN_IF_ERROR(visitor->BeginExtensions(&extensions)); // Extensions: in chronological order of being added to the format. return visitor->EndExtensions();
}
OpsinInverseMatrix::OpsinInverseMatrix() { Bundle::Init(this); }
Status OpsinInverseMatrix::VisitFields(Visitor* JXL_RESTRICT visitor) { if (visitor->AllDefault(*this, &all_default)) { // Overwrite all serialized fields, but not any nonserialized_*.
visitor->SetDefault(this); returntrue;
} const Matrix3x3& default_inverse =
jxl::cms::DefaultInverseOpsinAbsorbanceMatrix(); for (int j = 0; j < 3; ++j) { for (int i = 0; i < 3; ++i) {
JXL_QUIET_RETURN_IF_ERROR(
visitor->F16(default_inverse[j][i], &inverse_matrix[j][i]));
}
} for (int i = 0; i < 3; ++i) {
JXL_QUIET_RETURN_IF_ERROR(visitor->F16(
jxl::cms::kNegOpsinAbsorbanceBiasRGB[i], &opsin_biases[i]));
} for (int i = 0; i < 4; ++i) {
JXL_QUIET_RETURN_IF_ERROR(
visitor->F16(kDefaultQuantBias[i], &quant_biases[i]));
} returntrue;
}
ToneMapping::ToneMapping() { Bundle::Init(this); }
Status ToneMapping::VisitFields(Visitor* JXL_RESTRICT visitor) { if (visitor->AllDefault(*this, &all_default)) { // Overwrite all serialized fields, but not any nonserialized_*.
visitor->SetDefault(this); returntrue;
}
void ImageMetadata::SetAlphaBits(uint32_t bits, bool alpha_is_premultiplied) {
std::vector<ExtraChannelInfo>& eciv = extra_channel_info;
ExtraChannelInfo* alpha = Find(ExtraChannel::kAlpha); if (bits == 0) { if (alpha != nullptr) { // Remove the alpha channel from the extra channel info. It's // theoretically possible that there are multiple, remove all in that // case. This ensure a next HasAlpha() will return false. constauto is_alpha = [](const ExtraChannelInfo& eci) { return eci.type == ExtraChannel::kAlpha;
};
eciv.erase(std::remove_if(eciv.begin(), eciv.end(), is_alpha),
eciv.end());
}
} else { if (alpha == nullptr) {
ExtraChannelInfo info;
info.type = ExtraChannel::kAlpha;
info.bit_depth.bits_per_sample = bits;
info.dim_shift = 0;
info.alpha_associated = alpha_is_premultiplied; // Prepend rather than append: in case there already are other extra // channels, prefer alpha channel to be listed first.
eciv.insert(eciv.begin(), info);
} else { // Ignores potential extra alpha channels, only sets to first one.
alpha->bit_depth.bits_per_sample = bits;
alpha->bit_depth.floating_point_sample = false;
alpha->bit_depth.exponent_bits_per_sample = 0;
alpha->alpha_associated = alpha_is_premultiplied;
}
}
num_extra_channels = extra_channel_info.size(); if (bits > 12) modular_16_bit_buffer_sufficient = false;
}
#if JXL_DEBUG_V_LEVEL >= 1
std::string ImageMetadata::DebugString() const {
std::ostringstream os;
os << bit_depth.DebugString(); if (modular_16_bit_buffer_sufficient) {
os << " (modular 16)";
}
os << (xyb_encoded ? " xyb encoded" : " orig profile");
os << " " << Description(color_encoding); if (num_extra_channels > 0) {
os << " extra channels:"; for (size_t i = 0; i < num_extra_channels; ++i) {
os << " (" << extra_channel_info[i].DebugString() << ")"; if (i + 1 < num_extra_channels) os << ",";
}
} if (have_preview) {
os << " preview: " << preview_size.xsize() << "x" << preview_size.ysize();
} if (orientation != 1) {
os << " orientation: " << orientation;
} return os.str();
}
std::string CodecMetadata::DebugString() const {
std::ostringstream os;
os << size.xsize() << "x" << size.ysize();
os << " " << m.DebugString(); return os.str();
} #endif
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.