summaryrefslogtreecommitdiff
path: root/media/libjxl/src/lib/jxl/image_bundle.cc
diff options
context:
space:
mode:
Diffstat (limited to 'media/libjxl/src/lib/jxl/image_bundle.cc')
-rw-r--r--media/libjxl/src/lib/jxl/image_bundle.cc155
1 files changed, 155 insertions, 0 deletions
diff --git a/media/libjxl/src/lib/jxl/image_bundle.cc b/media/libjxl/src/lib/jxl/image_bundle.cc
new file mode 100644
index 0000000000..189b9768c3
--- /dev/null
+++ b/media/libjxl/src/lib/jxl/image_bundle.cc
@@ -0,0 +1,155 @@
+// 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/image_bundle.h"
+
+#include <limits>
+#include <utility>
+
+#include "lib/jxl/alpha.h"
+#include "lib/jxl/base/byte_order.h"
+#include "lib/jxl/base/padded_bytes.h"
+#include "lib/jxl/base/printf_macros.h"
+#include "lib/jxl/base/profiler.h"
+#include "lib/jxl/codec_in_out.h"
+#include "lib/jxl/color_management.h"
+#include "lib/jxl/fields.h"
+#include "lib/jxl/luminance.h"
+
+namespace jxl {
+
+void ImageBundle::ShrinkTo(size_t xsize, size_t ysize) {
+ if (HasColor()) color_.ShrinkTo(xsize, ysize);
+ for (ImageF& ec : extra_channels_) {
+ ec.ShrinkTo(xsize, ysize);
+ }
+}
+
+// Called by all other SetFrom*.
+void ImageBundle::SetFromImage(Image3F&& color,
+ const ColorEncoding& c_current) {
+ JXL_CHECK(color.xsize() != 0 && color.ysize() != 0);
+ JXL_CHECK(metadata_->color_encoding.IsGray() == c_current.IsGray());
+ color_ = std::move(color);
+ c_current_ = c_current;
+ VerifySizes();
+}
+
+void ImageBundle::VerifyMetadata() const {
+ JXL_CHECK(!c_current_.ICC().empty());
+ JXL_CHECK(metadata_->color_encoding.IsGray() == IsGray());
+
+ if (metadata_->HasAlpha() && alpha().xsize() == 0) {
+ JXL_ABORT("MD alpha_bits %u IB alpha %" PRIuS " x %" PRIuS "\n",
+ metadata_->GetAlphaBits(), alpha().xsize(), alpha().ysize());
+ }
+ const uint32_t alpha_bits = metadata_->GetAlphaBits();
+ JXL_CHECK(alpha_bits <= 32);
+
+ // metadata_->num_extra_channels may temporarily differ from
+ // extra_channels_.size(), e.g. after SetAlpha. They are synced by the next
+ // call to VisitFields.
+}
+
+void ImageBundle::VerifySizes() const {
+ const size_t xs = xsize();
+ const size_t ys = ysize();
+
+ if (HasExtraChannels()) {
+ JXL_CHECK(xs != 0 && ys != 0);
+ for (const ImageF& ec : extra_channels_) {
+ JXL_CHECK(ec.xsize() == xs);
+ JXL_CHECK(ec.ysize() == ys);
+ }
+ }
+}
+
+size_t ImageBundle::DetectRealBitdepth() const {
+ return metadata_->bit_depth.bits_per_sample;
+
+ // TODO(lode): let this function return lower bit depth if possible, e.g.
+ // return 8 bits in case the original image came from a 16-bit PNG that
+ // was in fact representable as 8-bit PNG. Ensure that the implementation
+ // returns 16 if e.g. two consecutive 16-bit values appeared in the original
+ // image (such as 32768 and 32769), take into account that e.g. the values
+ // 3-bit can represent is not a superset of the values 2-bit can represent,
+ // and there may be slight imprecisions in the floating point image.
+}
+
+const ImageF& ImageBundle::black() const {
+ JXL_ASSERT(HasBlack());
+ const size_t ec = metadata_->Find(ExtraChannel::kBlack) -
+ metadata_->extra_channel_info.data();
+ JXL_ASSERT(ec < extra_channels_.size());
+ return extra_channels_[ec];
+}
+const ImageF& ImageBundle::alpha() const {
+ JXL_ASSERT(HasAlpha());
+ const size_t ec = metadata_->Find(ExtraChannel::kAlpha) -
+ metadata_->extra_channel_info.data();
+ JXL_ASSERT(ec < extra_channels_.size());
+ return extra_channels_[ec];
+}
+ImageF* ImageBundle::alpha() {
+ JXL_ASSERT(HasAlpha());
+ const size_t ec = metadata_->Find(ExtraChannel::kAlpha) -
+ metadata_->extra_channel_info.data();
+ JXL_ASSERT(ec < extra_channels_.size());
+ return &extra_channels_[ec];
+}
+
+void ImageBundle::SetAlpha(ImageF&& alpha, bool alpha_is_premultiplied) {
+ const ExtraChannelInfo* eci = metadata_->Find(ExtraChannel::kAlpha);
+ // Must call SetAlphaBits first, otherwise we don't know which channel index
+ JXL_CHECK(eci != nullptr);
+ JXL_CHECK(alpha.xsize() != 0 && alpha.ysize() != 0);
+ JXL_CHECK(eci->alpha_associated == alpha_is_premultiplied);
+ if (extra_channels_.size() < metadata_->extra_channel_info.size()) {
+ // TODO(jon): get rid of this case
+ extra_channels_.insert(
+ extra_channels_.begin() + (eci - metadata_->extra_channel_info.data()),
+ std::move(alpha));
+ } else {
+ extra_channels_[eci - metadata_->extra_channel_info.data()] =
+ std::move(alpha);
+ }
+ // num_extra_channels is automatically set in visitor
+ VerifySizes();
+}
+void ImageBundle::PremultiplyAlpha() {
+ if (!HasAlpha()) return;
+ if (!HasColor()) return;
+ const ExtraChannelInfo* eci = metadata_->Find(ExtraChannel::kAlpha);
+ if (eci->alpha_associated) return; // already premultiplied
+ JXL_CHECK(color_.ysize() == alpha()->ysize());
+ JXL_CHECK(color_.xsize() == alpha()->xsize());
+ for (size_t y = 0; y < color_.ysize(); y++) {
+ ::jxl::PremultiplyAlpha(color_.PlaneRow(0, y), color_.PlaneRow(1, y),
+ color_.PlaneRow(2, y), alpha()->Row(y),
+ color_.xsize());
+ }
+}
+void ImageBundle::UnpremultiplyAlpha() {
+ if (!HasAlpha()) return;
+ if (!HasColor()) return;
+ const ExtraChannelInfo* eci = metadata_->Find(ExtraChannel::kAlpha);
+ if (!eci->alpha_associated) return; // already unpremultiplied
+ JXL_CHECK(color_.ysize() == alpha()->ysize());
+ JXL_CHECK(color_.xsize() == alpha()->xsize());
+ for (size_t y = 0; y < color_.ysize(); y++) {
+ ::jxl::UnpremultiplyAlpha(color_.PlaneRow(0, y), color_.PlaneRow(1, y),
+ color_.PlaneRow(2, y), alpha()->Row(y),
+ color_.xsize());
+ }
+}
+
+void ImageBundle::SetExtraChannels(std::vector<ImageF>&& extra_channels) {
+ for (const ImageF& plane : extra_channels) {
+ JXL_CHECK(plane.xsize() != 0 && plane.ysize() != 0);
+ }
+ extra_channels_ = std::move(extra_channels);
+ VerifySizes();
+}
+} // namespace jxl