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_CODEC_IN_OUT_H_
7 #define LIB_JXL_CODEC_IN_OUT_H_
8 
9 // Holds inputs/outputs for decoding/encoding images.
10 
11 #include <stddef.h>
12 
13 #include <utility>
14 #include <vector>
15 
16 #include "lib/jxl/base/data_parallel.h"
17 #include "lib/jxl/common.h"
18 #include "lib/jxl/frame_header.h"
19 #include "lib/jxl/headers.h"
20 #include "lib/jxl/image.h"
21 #include "lib/jxl/image_bundle.h"
22 #include "lib/jxl/luminance.h"
23 
24 namespace jxl {
25 
26 // Per-channel interval, used to convert between (full-range) external and
27 // (bounded or unbounded) temp values. See external_image.cc for the definitions
28 // of temp/external.
29 struct CodecInterval {
30   CodecInterval() = default;
CodecIntervalCodecInterval31   constexpr CodecInterval(float min, float max) : min(min), width(max - min) {}
32   // Defaults for temp.
33   float min = 0.0f;
34   float width = 1.0f;
35 };
36 
37 struct SizeConstraints {
38   // Upper limit on pixel dimensions/area, enforced by VerifyDimensions
39   // (called from decoders). Fuzzers set smaller values to limit memory use.
40   uint32_t dec_max_xsize = 0xFFFFFFFFu;
41   uint32_t dec_max_ysize = 0xFFFFFFFFu;
42   uint64_t dec_max_pixels = 0xFFFFFFFFu;  // Might be up to ~0ull
43 };
44 
45 template <typename T,
46           class = typename std::enable_if<std::is_unsigned<T>::value>::type>
VerifyDimensions(const SizeConstraints * constraints,T xs,T ys)47 Status VerifyDimensions(const SizeConstraints* constraints, T xs, T ys) {
48   if (!constraints) return true;
49 
50   if (xs == 0 || ys == 0) return JXL_FAILURE("Empty image.");
51   if (xs > constraints->dec_max_xsize) return JXL_FAILURE("Image too wide.");
52   if (ys > constraints->dec_max_ysize) return JXL_FAILURE("Image too tall.");
53 
54   const uint64_t num_pixels = static_cast<uint64_t>(xs) * ys;
55   if (num_pixels > constraints->dec_max_pixels) {
56     return JXL_FAILURE("Image too big.");
57   }
58 
59   return true;
60 }
61 
62 using CodecIntervals = std::array<CodecInterval, 4>;  // RGB[A] or Y[A]
63 
64 // Optional text/EXIF metadata.
65 struct Blobs {
66   PaddedBytes exif;
67   PaddedBytes iptc;
68   PaddedBytes jumbf;
69   PaddedBytes xmp;
70 };
71 
72 // For Codec::kJPG, convert between JPEG and pixels or between JPEG and
73 // quantized DCT coefficients
74 // For pixel data, the nominal range is 0..1.
75 enum class DecodeTarget { kPixels, kQuantizedCoeffs };
76 
77 // Holds a preview, a main image or one or more frames, plus the inputs/outputs
78 // to/from decoding/encoding.
79 class CodecInOut {
80  public:
CodecInOut()81   CodecInOut() : preview_frame(&metadata.m) {
82     frames.reserve(1);
83     frames.emplace_back(&metadata.m);
84   }
85 
86   // Move-only.
87   CodecInOut(CodecInOut&&) = default;
88   CodecInOut& operator=(CodecInOut&&) = default;
89 
LastStillFrame()90   size_t LastStillFrame() const {
91     JXL_DASSERT(frames.size() > 0);
92     size_t last = 0;
93     for (size_t i = 0; i < frames.size(); i++) {
94       last = i;
95       if (frames[i].duration > 0) break;
96     }
97     return last;
98   }
99 
Main()100   ImageBundle& Main() { return frames[LastStillFrame()]; }
Main()101   const ImageBundle& Main() const { return frames[LastStillFrame()]; }
102 
103   // If c_current.IsGray(), all planes must be identical.
SetFromImage(Image3F && color,const ColorEncoding & c_current)104   void SetFromImage(Image3F&& color, const ColorEncoding& c_current) {
105     Main().SetFromImage(std::move(color), c_current);
106     SetIntensityTarget(this);
107     SetSize(Main().xsize(), Main().ysize());
108   }
109 
SetSize(size_t xsize,size_t ysize)110   void SetSize(size_t xsize, size_t ysize) {
111     JXL_CHECK(metadata.size.Set(xsize, ysize));
112   }
113 
CheckMetadata()114   void CheckMetadata() const {
115     JXL_CHECK(metadata.m.bit_depth.bits_per_sample != 0);
116     JXL_CHECK(!metadata.m.color_encoding.ICC().empty());
117 
118     if (preview_frame.xsize() != 0) preview_frame.VerifyMetadata();
119     JXL_CHECK(preview_frame.metadata() == &metadata.m);
120 
121     for (const ImageBundle& ib : frames) {
122       ib.VerifyMetadata();
123       JXL_CHECK(ib.metadata() == &metadata.m);
124     }
125   }
126 
xsize()127   size_t xsize() const { return metadata.size.xsize(); }
ysize()128   size_t ysize() const { return metadata.size.ysize(); }
ShrinkTo(size_t xsize,size_t ysize)129   void ShrinkTo(size_t xsize, size_t ysize) {
130     // preview is unaffected.
131     for (ImageBundle& ib : frames) {
132       ib.ShrinkTo(xsize, ysize);
133     }
134     SetSize(xsize, ysize);
135   }
136 
137   // Calls TransformTo for each ImageBundle (preview/frames).
138   Status TransformTo(const ColorEncoding& c_desired,
139                      ThreadPool* pool = nullptr) {
140     if (metadata.m.have_preview) {
141       JXL_RETURN_IF_ERROR(preview_frame.TransformTo(c_desired, pool));
142     }
143     for (ImageBundle& ib : frames) {
144       JXL_RETURN_IF_ERROR(ib.TransformTo(c_desired, pool));
145     }
146     return true;
147   }
148   // Calls PremultiplyAlpha for each ImageBundle (preview/frames).
PremultiplyAlpha()149   void PremultiplyAlpha() {
150     ExtraChannelInfo* eci = metadata.m.Find(ExtraChannel::kAlpha);
151     if (eci == nullptr || eci->alpha_associated) return;  // nothing to do
152     if (metadata.m.have_preview) {
153       preview_frame.PremultiplyAlpha();
154     }
155     for (ImageBundle& ib : frames) {
156       ib.PremultiplyAlpha();
157     }
158     eci->alpha_associated = true;
159     return;
160   }
161 
162   // -- DECODER INPUT:
163 
164   SizeConstraints constraints;
165   // Decode to pixels or keep JPEG as quantized DCT coefficients
166   DecodeTarget dec_target = DecodeTarget::kPixels;
167 
168   // Intended white luminance, in nits (cd/m^2).
169   // It is used by codecs that do not know the absolute luminance of their
170   // images. For those codecs, decoders map from white to this luminance. There
171   // is no other way of knowing the target brightness for those codecs - depends
172   // on source material. 709 typically targets 100 nits, BT.2100 PQ up to 10K,
173   // but HDR content is more typically mastered to 4K nits. Codecs that do know
174   // the absolute luminance of their images will typically ignore it as a
175   // decoder input. The corresponding decoder output and encoder input is the
176   // intensity target in the metadata. ALL decoders MUST set that metadata
177   // appropriately, but it does not have to be identical to this hint. Encoders
178   // for codecs that do not encode absolute luminance levels should use that
179   // metadata to decide on what to map to white. Encoders for codecs that *do*
180   // encode absolute luminance levels may use it to decide on encoding values,
181   // but not in a way that would affect the range of interpreted luminance.
182   //
183   // 0 means that it is up to the codec to decide on a reasonable value to use.
184 
185   float target_nits = 0;
186 
187   // -- DECODER OUTPUT:
188 
189   // Total number of pixels decoded (may differ from #frames * xsize * ysize
190   // if frames are cropped)
191   uint64_t dec_pixels = 0;
192 
193   // -- DECODER OUTPUT, ENCODER INPUT:
194 
195   // Metadata stored into / retrieved from bitstreams.
196 
197   Blobs blobs;
198 
199   CodecMetadata metadata;  // applies to preview and all frames
200 
201   // If metadata.have_preview:
202   ImageBundle preview_frame;
203 
204   std::vector<ImageBundle> frames;  // size=1 if !metadata.have_animation
205 
206   bool use_sjpeg = false;
207   // If the image should be written to a JPEG, use this quality for encoding.
208   size_t jpeg_quality;
209 };
210 
211 }  // namespace jxl
212 
213 #endif  // LIB_JXL_CODEC_IN_OUT_H_
214