Coverage Report

Created: 2022-08-24 06:06

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