image_bundle.h (8767B)
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 #ifndef LIB_JXL_IMAGE_BUNDLE_H_ 7 #define LIB_JXL_IMAGE_BUNDLE_H_ 8 9 // The main image or frame consists of a bundle of associated images. 10 11 #include <jxl/cms_interface.h> 12 #include <stddef.h> 13 #include <stdint.h> 14 15 #include <memory> 16 #include <string> 17 #include <utility> 18 #include <vector> 19 20 #include "lib/jxl/base/common.h" 21 #include "lib/jxl/base/data_parallel.h" 22 #include "lib/jxl/base/status.h" 23 #include "lib/jxl/color_encoding_internal.h" 24 #include "lib/jxl/common.h" // JPEGXL_ENABLE_TRANSCODE_JPEG 25 #include "lib/jxl/frame_header.h" 26 #include "lib/jxl/image.h" 27 #include "lib/jxl/image_metadata.h" 28 #include "lib/jxl/image_ops.h" 29 #include "lib/jxl/jpeg/jpeg_data.h" 30 31 namespace jxl { 32 33 // A bundle of color/alpha/depth/plane images. 34 class ImageBundle { 35 public: 36 // Uninitialized state for use as output parameter. 37 ImageBundle() : metadata_(nullptr) {} 38 // Caller is responsible for setting metadata before calling Set*. 39 explicit ImageBundle(const ImageMetadata* metadata) : metadata_(metadata) {} 40 41 // Move-only (allows storing in std::vector). 42 ImageBundle(ImageBundle&&) = default; 43 ImageBundle& operator=(ImageBundle&&) = default; 44 45 StatusOr<ImageBundle> Copy() const { 46 ImageBundle copy(metadata_); 47 JXL_ASSIGN_OR_RETURN(copy.color_, 48 Image3F::Create(color_.xsize(), color_.ysize())); 49 CopyImageTo(color_, ©.color_); 50 copy.c_current_ = c_current_; 51 copy.extra_channels_.reserve(extra_channels_.size()); 52 for (const ImageF& plane : extra_channels_) { 53 JXL_ASSIGN_OR_RETURN(ImageF ec, 54 ImageF::Create(plane.xsize(), plane.ysize())); 55 CopyImageTo(plane, &ec); 56 copy.extra_channels_.emplace_back(std::move(ec)); 57 } 58 59 copy.jpeg_data = 60 jpeg_data ? make_unique<jpeg::JPEGData>(*jpeg_data) : nullptr; 61 copy.color_transform = color_transform; 62 copy.chroma_subsampling = chroma_subsampling; 63 64 return copy; 65 } 66 67 // -- SIZE 68 69 size_t xsize() const { 70 if (IsJPEG()) return jpeg_data->width; 71 if (color_.xsize() != 0) return color_.xsize(); 72 return extra_channels_.empty() ? 0 : extra_channels_[0].xsize(); 73 } 74 size_t ysize() const { 75 if (IsJPEG()) return jpeg_data->height; 76 if (color_.ysize() != 0) return color_.ysize(); 77 return extra_channels_.empty() ? 0 : extra_channels_[0].ysize(); 78 } 79 void ShrinkTo(size_t xsize, size_t ysize); 80 81 // sizes taking orientation into account 82 size_t oriented_xsize() const { 83 if (static_cast<uint32_t>(metadata_->GetOrientation()) > 4) { 84 return ysize(); 85 } else { 86 return xsize(); 87 } 88 } 89 size_t oriented_ysize() const { 90 if (static_cast<uint32_t>(metadata_->GetOrientation()) > 4) { 91 return xsize(); 92 } else { 93 return ysize(); 94 } 95 } 96 97 // -- COLOR 98 99 // Whether color() is valid/usable. Returns true in most cases. Even images 100 // with spot colors (one example of when !planes().empty()) typically have a 101 // part that can be converted to RGB. 102 bool HasColor() const { return color_.xsize() != 0; } 103 104 // For resetting the size when switching from a reference to main frame. 105 void RemoveColor() { color_ = Image3F(); } 106 107 // Do not use if !HasColor(). 108 const Image3F& color() const { 109 // If this fails, Set* was not called - perhaps because decoding failed? 110 JXL_DASSERT(HasColor()); 111 return color_; 112 } 113 114 // Do not use if !HasColor(). 115 Image3F* color() { 116 JXL_DASSERT(HasColor()); 117 return &color_; 118 } 119 120 // If c_current.IsGray(), all planes must be identical. NOTE: c_current is 121 // independent of metadata()->color_encoding, which is the original, whereas 122 // a decoder might return pixels in a different c_current. 123 // This only sets the color channels, you must also make extra channels 124 // match the amount that is in the metadata. 125 void SetFromImage(Image3F&& color, const ColorEncoding& c_current); 126 127 // -- COLOR ENCODING 128 129 const ColorEncoding& c_current() const { return c_current_; } 130 131 // Returns whether the color image has identical planes. Once established by 132 // Set*, remains unchanged until a subsequent Set* or TransformTo. 133 bool IsGray() const { return c_current_.IsGray(); } 134 135 bool IsSRGB() const { return c_current_.IsSRGB(); } 136 bool IsLinearSRGB() const { return c_current_.IsLinearSRGB(); } 137 138 // Set the c_current profile without doing any transformation, e.g. if the 139 // transformation was already applied. 140 void OverrideProfile(const ColorEncoding& new_c_current) { 141 c_current_ = new_c_current; 142 } 143 144 // TODO(lode): TransformTo and CopyTo are implemented in enc_image_bundle.cc, 145 // move these functions out of this header file and class, to 146 // enc_image_bundle.h. 147 148 // Transforms color to c_desired and sets c_current to c_desired. Alpha and 149 // metadata remains unchanged. 150 Status TransformTo(const ColorEncoding& c_desired, const JxlCmsInterface& cms, 151 ThreadPool* pool = nullptr); 152 // Copies this:rect, converts to c_desired, and allocates+fills out. 153 Status CopyTo(const Rect& rect, const ColorEncoding& c_desired, 154 const JxlCmsInterface& cms, Image3F* out, 155 ThreadPool* pool = nullptr) const; 156 157 // Detect 'real' bit depth, which can be lower than nominal bit depth 158 // (this is common in PNG), returns 'real' bit depth 159 size_t DetectRealBitdepth() const; 160 161 // -- ALPHA 162 163 void SetAlpha(ImageF&& alpha); 164 bool HasAlpha() const { 165 return metadata_->Find(ExtraChannel::kAlpha) != nullptr; 166 } 167 bool AlphaIsPremultiplied() const { 168 const ExtraChannelInfo* eci = metadata_->Find(ExtraChannel::kAlpha); 169 return (eci == nullptr) ? false : eci->alpha_associated; 170 } 171 const ImageF& alpha() const; 172 ImageF* alpha(); 173 174 // -- EXTRA CHANNELS 175 bool HasBlack() const { 176 return metadata_->Find(ExtraChannel::kBlack) != nullptr; 177 } 178 const ImageF& black() const; 179 180 // Extra channels of unknown interpretation (e.g. spot colors). 181 void SetExtraChannels(std::vector<ImageF>&& extra_channels); 182 void ClearExtraChannels() { extra_channels_.clear(); } 183 bool HasExtraChannels() const { return !extra_channels_.empty(); } 184 const std::vector<ImageF>& extra_channels() const { return extra_channels_; } 185 std::vector<ImageF>& extra_channels() { return extra_channels_; } 186 187 const ImageMetadata* metadata() const { return metadata_; } 188 189 void VerifyMetadata() const; 190 191 void SetDecodedBytes(size_t decoded_bytes) { decoded_bytes_ = decoded_bytes; } 192 size_t decoded_bytes() const { return decoded_bytes_; } 193 194 // -- JPEG transcoding: 195 196 // Returns true if image does or will represent quantized DCT-8 coefficients, 197 // stored in 8x8 pixel regions. 198 bool IsJPEG() const { 199 #if JPEGXL_ENABLE_TRANSCODE_JPEG 200 return jpeg_data != nullptr; 201 #else // JPEGXL_ENABLE_TRANSCODE_JPEG 202 return false; 203 #endif // JPEGXL_ENABLE_TRANSCODE_JPEG 204 } 205 206 std::unique_ptr<jpeg::JPEGData> jpeg_data; 207 // these fields are used to signal the input JPEG color space 208 // NOTE: JPEG doesn't actually provide a way to determine whether YCbCr was 209 // applied or not. 210 ColorTransform color_transform = ColorTransform::kNone; 211 YCbCrChromaSubsampling chroma_subsampling; 212 213 FrameOrigin origin{0, 0}; 214 215 // Animation-related information, corresponding to the timecode and duration 216 // fields of the jxl::AnimationFrame of the jxl::FrameHeader. 217 // TODO(lode): ImageBundle is used here to carry the information from 218 // jxl::FrameHeader, consider instead passing a jxl::FrameHeader directly to 219 // EncodeFrame or having a field of that type here. 220 uint32_t duration = 0; 221 uint32_t timecode = 0; 222 223 // TODO(lode): these fields do not match the JXL frame header, it should be 224 // possible to specify up to 4 (3 if nonzero duration) slots to save this 225 // frame as reference (see save_as_reference). 226 bool use_for_next_frame = false; 227 bool blend = false; 228 BlendMode blendmode = BlendMode::kBlend; 229 230 std::string name; 231 232 private: 233 // Called after any Set* to ensure their sizes are compatible. 234 void VerifySizes() const; 235 236 // Required for TransformTo so that an ImageBundle is self-sufficient. Always 237 // points to the same thing, but cannot be const-pointer because that prevents 238 // the compiler from generating a move ctor. 239 const ImageMetadata* metadata_; 240 241 // Initialized by Set*: 242 Image3F color_; // If empty, planes_ is not; all planes equal if IsGray(). 243 ColorEncoding c_current_; // of color_ 244 245 // Initialized by SetPlanes; size = ImageMetadata.num_extra_channels 246 std::vector<ImageF> extra_channels_; 247 248 // How many bytes of the input were actually read. 249 size_t decoded_bytes_ = 0; 250 }; 251 252 } // namespace jxl 253 254 #endif // LIB_JXL_IMAGE_BUNDLE_H_