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