summaryrefslogtreecommitdiffstats
path: root/third_party/jpeg-xl/lib/jxl/color_encoding_internal.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/jpeg-xl/lib/jxl/color_encoding_internal.cc')
-rw-r--r--third_party/jpeg-xl/lib/jxl/color_encoding_internal.cc208
1 files changed, 208 insertions, 0 deletions
diff --git a/third_party/jpeg-xl/lib/jxl/color_encoding_internal.cc b/third_party/jpeg-xl/lib/jxl/color_encoding_internal.cc
new file mode 100644
index 0000000000..19273dad3c
--- /dev/null
+++ b/third_party/jpeg-xl/lib/jxl/color_encoding_internal.cc
@@ -0,0 +1,208 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "lib/jxl/color_encoding_internal.h"
+
+#include <array>
+
+#include "lib/jxl/base/common.h"
+#include "lib/jxl/cms/color_encoding_cms.h"
+#include "lib/jxl/cms/jxl_cms_internal.h"
+#include "lib/jxl/fields.h"
+#include "lib/jxl/pack_signed.h"
+
+namespace jxl {
+
+bool CustomTransferFunction::SetImplicit() {
+ if (nonserialized_color_space == ColorSpace::kXYB) {
+ if (!storage_.SetGamma(1.0 / 3)) JXL_ASSERT(false);
+ return true;
+ }
+ return false;
+}
+
+std::array<ColorEncoding, 2> ColorEncoding::CreateC2(Primaries pr,
+ TransferFunction tf) {
+ std::array<ColorEncoding, 2> c2;
+
+ ColorEncoding* c_rgb = c2.data() + 0;
+ c_rgb->SetColorSpace(ColorSpace::kRGB);
+ c_rgb->storage_.white_point = WhitePoint::kD65;
+ c_rgb->storage_.primaries = pr;
+ c_rgb->storage_.tf.SetTransferFunction(tf);
+ JXL_CHECK(c_rgb->CreateICC());
+
+ ColorEncoding* c_gray = c2.data() + 1;
+ c_gray->SetColorSpace(ColorSpace::kGray);
+ c_gray->storage_.white_point = WhitePoint::kD65;
+ c_gray->storage_.primaries = pr;
+ c_gray->storage_.tf.SetTransferFunction(tf);
+ JXL_CHECK(c_gray->CreateICC());
+
+ return c2;
+}
+
+const ColorEncoding& ColorEncoding::SRGB(bool is_gray) {
+ static std::array<ColorEncoding, 2> c2 =
+ CreateC2(Primaries::kSRGB, TransferFunction::kSRGB);
+ return c2[is_gray];
+}
+const ColorEncoding& ColorEncoding::LinearSRGB(bool is_gray) {
+ static std::array<ColorEncoding, 2> c2 =
+ CreateC2(Primaries::kSRGB, TransferFunction::kLinear);
+ return c2[is_gray];
+}
+
+Status ColorEncoding::SetWhitePointType(const WhitePoint& wp) {
+ JXL_DASSERT(storage_.have_fields);
+ storage_.white_point = wp;
+ return true;
+}
+
+Status ColorEncoding::SetPrimariesType(const Primaries& p) {
+ JXL_DASSERT(storage_.have_fields);
+ JXL_ASSERT(HasPrimaries());
+ storage_.primaries = p;
+ return true;
+}
+
+void ColorEncoding::DecideIfWantICC(const JxlCmsInterface& cms) {
+ if (storage_.icc.empty()) return;
+
+ JxlColorEncoding c;
+ JXL_BOOL cmyk;
+ if (!cms.set_fields_from_icc(cms.set_fields_data, storage_.icc.data(),
+ storage_.icc.size(), &c, &cmyk)) {
+ return;
+ }
+ if (cmyk) return;
+
+ std::vector<uint8_t> icc;
+ if (!MaybeCreateProfile(c, &icc)) return;
+
+ want_icc_ = false;
+}
+
+Customxy::Customxy() { Bundle::Init(this); }
+Status Customxy::VisitFields(Visitor* JXL_RESTRICT visitor) {
+ uint32_t ux = PackSigned(storage_.x);
+ JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Bits(19), BitsOffset(19, 524288),
+ BitsOffset(20, 1048576),
+ BitsOffset(21, 2097152), 0, &ux));
+ storage_.x = UnpackSigned(ux);
+ uint32_t uy = PackSigned(storage_.y);
+ JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Bits(19), BitsOffset(19, 524288),
+ BitsOffset(20, 1048576),
+ BitsOffset(21, 2097152), 0, &uy));
+ storage_.y = UnpackSigned(uy);
+ return true;
+}
+
+CustomTransferFunction::CustomTransferFunction() { Bundle::Init(this); }
+Status CustomTransferFunction::VisitFields(Visitor* JXL_RESTRICT visitor) {
+ if (visitor->Conditional(!SetImplicit())) {
+ JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &storage_.have_gamma));
+
+ if (visitor->Conditional(storage_.have_gamma)) {
+ // Gamma is represented as a 24-bit int, the exponent used is
+ // gamma_ / 1e7. Valid values are (0, 1]. On the low end side, we also
+ // limit it to kMaxGamma/1e7.
+ JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(
+ 24, ::jxl::cms::CustomTransferFunction::kGammaMul, &storage_.gamma));
+ if (storage_.gamma > ::jxl::cms::CustomTransferFunction::kGammaMul ||
+ static_cast<uint64_t>(storage_.gamma) *
+ ::jxl::cms::CustomTransferFunction::kMaxGamma <
+ ::jxl::cms::CustomTransferFunction::kGammaMul) {
+ return JXL_FAILURE("Invalid gamma %u", storage_.gamma);
+ }
+ }
+
+ if (visitor->Conditional(!storage_.have_gamma)) {
+ JXL_QUIET_RETURN_IF_ERROR(
+ visitor->Enum(TransferFunction::kSRGB, &storage_.transfer_function));
+ }
+ }
+
+ return true;
+}
+
+ColorEncoding::ColorEncoding() { Bundle::Init(this); }
+Status ColorEncoding::VisitFields(Visitor* JXL_RESTRICT visitor) {
+ if (visitor->AllDefault(*this, &all_default)) {
+ // Overwrite all serialized fields, but not any nonserialized_*.
+ visitor->SetDefault(this);
+ return true;
+ }
+
+ JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &want_icc_));
+
+ // Always send even if want_icc_ because this affects decoding.
+ // We can skip the white point/primaries because they do not.
+ JXL_QUIET_RETURN_IF_ERROR(
+ visitor->Enum(ColorSpace::kRGB, &storage_.color_space));
+
+ if (visitor->Conditional(!WantICC())) {
+ // Serialize enums. NOTE: we set the defaults to the most common values so
+ // ImageMetadata.all_default is true in the common case.
+
+ if (visitor->Conditional(!ImplicitWhitePoint())) {
+ JXL_QUIET_RETURN_IF_ERROR(
+ visitor->Enum(WhitePoint::kD65, &storage_.white_point));
+ if (visitor->Conditional(storage_.white_point == WhitePoint::kCustom)) {
+ white_.storage_ = storage_.white;
+ JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&white_));
+ storage_.white = white_.storage_;
+ }
+ }
+
+ if (visitor->Conditional(HasPrimaries())) {
+ JXL_QUIET_RETURN_IF_ERROR(
+ visitor->Enum(Primaries::kSRGB, &storage_.primaries));
+ if (visitor->Conditional(storage_.primaries == Primaries::kCustom)) {
+ red_.storage_ = storage_.red;
+ JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&red_));
+ storage_.red = red_.storage_;
+ green_.storage_ = storage_.green;
+ JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&green_));
+ storage_.green = green_.storage_;
+ blue_.storage_ = storage_.blue;
+ JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&blue_));
+ storage_.blue = blue_.storage_;
+ }
+ }
+
+ tf_.nonserialized_color_space = storage_.color_space;
+ tf_.storage_ = storage_.tf;
+ JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&tf_));
+ storage_.tf = tf_.storage_;
+
+ JXL_QUIET_RETURN_IF_ERROR(
+ visitor->Enum(RenderingIntent::kRelative, &storage_.rendering_intent));
+
+ // We didn't have ICC, so all fields should be known.
+ if (storage_.color_space == ColorSpace::kUnknown ||
+ storage_.tf.IsUnknown()) {
+ return JXL_FAILURE(
+ "No ICC but cs %u and tf %u%s",
+ static_cast<unsigned int>(storage_.color_space),
+ storage_.tf.have_gamma
+ ? 0
+ : static_cast<unsigned int>(storage_.tf.transfer_function),
+ storage_.tf.have_gamma ? "(gamma)" : "");
+ }
+
+ JXL_RETURN_IF_ERROR(CreateICC());
+ }
+
+ if (WantICC() && visitor->IsReading()) {
+ // Haven't called SetICC() yet, do nothing.
+ } else {
+ if (ICC().empty()) return JXL_FAILURE("Empty ICC");
+ }
+
+ return true;
+}
+
+} // namespace jxl