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