image_bundle.cc (4216B)
1 // Copyright (c) the JPEG XL Project Authors. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 #include "lib/jxl/image_bundle.h" 7 8 #include <limits> 9 #include <utility> 10 11 #include "lib/jxl/base/byte_order.h" 12 #include "lib/jxl/base/printf_macros.h" 13 #include "lib/jxl/fields.h" 14 15 namespace jxl { 16 17 void ImageBundle::ShrinkTo(size_t xsize, size_t ysize) { 18 if (HasColor()) color_.ShrinkTo(xsize, ysize); 19 for (ImageF& ec : extra_channels_) { 20 ec.ShrinkTo(xsize, ysize); 21 } 22 } 23 24 // Called by all other SetFrom*. 25 void ImageBundle::SetFromImage(Image3F&& color, 26 const ColorEncoding& c_current) { 27 JXL_CHECK(color.xsize() != 0 && color.ysize() != 0); 28 JXL_CHECK(metadata_->color_encoding.IsGray() == c_current.IsGray()); 29 color_ = std::move(color); 30 c_current_ = c_current; 31 VerifySizes(); 32 } 33 34 void ImageBundle::VerifyMetadata() const { 35 JXL_CHECK(!c_current_.ICC().empty()); 36 JXL_CHECK(metadata_->color_encoding.IsGray() == IsGray()); 37 38 if (metadata_->HasAlpha() && alpha().xsize() == 0) { 39 JXL_UNREACHABLE("MD alpha_bits %u IB alpha %" PRIuS " x %" PRIuS "\n", 40 metadata_->GetAlphaBits(), alpha().xsize(), 41 alpha().ysize()); 42 } 43 const uint32_t alpha_bits = metadata_->GetAlphaBits(); 44 JXL_CHECK(alpha_bits <= 32); 45 46 // metadata_->num_extra_channels may temporarily differ from 47 // extra_channels_.size(), e.g. after SetAlpha. They are synced by the next 48 // call to VisitFields. 49 } 50 51 void ImageBundle::VerifySizes() const { 52 const size_t xs = xsize(); 53 const size_t ys = ysize(); 54 55 if (HasExtraChannels()) { 56 JXL_CHECK(xs != 0 && ys != 0); 57 for (const ImageF& ec : extra_channels_) { 58 JXL_CHECK(ec.xsize() == xs); 59 JXL_CHECK(ec.ysize() == ys); 60 } 61 } 62 } 63 64 size_t ImageBundle::DetectRealBitdepth() const { 65 return metadata_->bit_depth.bits_per_sample; 66 67 // TODO(lode): let this function return lower bit depth if possible, e.g. 68 // return 8 bits in case the original image came from a 16-bit PNG that 69 // was in fact representable as 8-bit PNG. Ensure that the implementation 70 // returns 16 if e.g. two consecutive 16-bit values appeared in the original 71 // image (such as 32768 and 32769), take into account that e.g. the values 72 // 3-bit can represent is not a superset of the values 2-bit can represent, 73 // and there may be slight imprecisions in the floating point image. 74 } 75 76 const ImageF& ImageBundle::black() const { 77 JXL_ASSERT(HasBlack()); 78 const size_t ec = metadata_->Find(ExtraChannel::kBlack) - 79 metadata_->extra_channel_info.data(); 80 JXL_ASSERT(ec < extra_channels_.size()); 81 return extra_channels_[ec]; 82 } 83 const ImageF& ImageBundle::alpha() const { 84 JXL_ASSERT(HasAlpha()); 85 const size_t ec = metadata_->Find(ExtraChannel::kAlpha) - 86 metadata_->extra_channel_info.data(); 87 JXL_ASSERT(ec < extra_channels_.size()); 88 return extra_channels_[ec]; 89 } 90 ImageF* ImageBundle::alpha() { 91 JXL_ASSERT(HasAlpha()); 92 const size_t ec = metadata_->Find(ExtraChannel::kAlpha) - 93 metadata_->extra_channel_info.data(); 94 JXL_ASSERT(ec < extra_channels_.size()); 95 return &extra_channels_[ec]; 96 } 97 98 void ImageBundle::SetAlpha(ImageF&& alpha) { 99 const ExtraChannelInfo* eci = metadata_->Find(ExtraChannel::kAlpha); 100 // Must call SetAlphaBits first, otherwise we don't know which channel index 101 JXL_CHECK(eci != nullptr); 102 JXL_CHECK(alpha.xsize() != 0 && alpha.ysize() != 0); 103 if (extra_channels_.size() < metadata_->extra_channel_info.size()) { 104 // TODO(jon): get rid of this case 105 extra_channels_.insert( 106 extra_channels_.begin() + (eci - metadata_->extra_channel_info.data()), 107 std::move(alpha)); 108 } else { 109 extra_channels_[eci - metadata_->extra_channel_info.data()] = 110 std::move(alpha); 111 } 112 // num_extra_channels is automatically set in visitor 113 VerifySizes(); 114 } 115 116 void ImageBundle::SetExtraChannels(std::vector<ImageF>&& extra_channels) { 117 for (const ImageF& plane : extra_channels) { 118 JXL_CHECK(plane.xsize() != 0 && plane.ysize() != 0); 119 } 120 extra_channels_ = std::move(extra_channels); 121 VerifySizes(); 122 } 123 } // namespace jxl