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 #include "lib/jxl/size_constraints.h"
24
25 namespace jxl {
26
27 // Per-channel interval, used to convert between (full-range) external and
28 // (bounded or unbounded) temp values. See external_image.cc for the definitions
29 // of temp/external.
30 struct CodecInterval {
31 CodecInterval() = default;
CodecIntervalCodecInterval32 constexpr CodecInterval(float min, float max) : min(min), width(max - min) {}
33 // Defaults for temp.
34 float min = 0.0f;
35 float width = 1.0f;
36 };
37
38 template <typename T,
39 class = typename std::enable_if<std::is_unsigned<T>::value>::type>
VerifyDimensions(const SizeConstraints * constraints,T xs,T ys)40 Status VerifyDimensions(const SizeConstraints* constraints, T xs, T ys) {
41 if (!constraints) return true;
42
43 if (xs == 0 || ys == 0) return JXL_FAILURE("Empty image.");
44 if (xs > constraints->dec_max_xsize) return JXL_FAILURE("Image too wide.");
45 if (ys > constraints->dec_max_ysize) return JXL_FAILURE("Image too tall.");
46
47 const uint64_t num_pixels = static_cast<uint64_t>(xs) * ys;
48 if (num_pixels > constraints->dec_max_pixels) {
49 return JXL_FAILURE("Image too big.");
50 }
51
52 return true;
53 }
54
55 using CodecIntervals = std::array<CodecInterval, 4>; // RGB[A] or Y[A]
56
57 // Optional text/EXIF metadata.
58 struct Blobs {
59 PaddedBytes exif;
60 PaddedBytes iptc;
61 PaddedBytes jumbf;
62 PaddedBytes xmp;
63 };
64
65 // Holds a preview, a main image or one or more frames, plus the inputs/outputs
66 // to/from decoding/encoding.
67 class CodecInOut {
68 public:
CodecInOut()69 CodecInOut() : preview_frame(&metadata.m) {
70 frames.reserve(1);
71 frames.emplace_back(&metadata.m);
72 }
73
74 // Move-only.
75 CodecInOut(CodecInOut&&) = default;
76 CodecInOut& operator=(CodecInOut&&) = default;
77
LastStillFrame()78 size_t LastStillFrame() const {
79 JXL_DASSERT(frames.size() > 0);
80 size_t last = 0;
81 for (size_t i = 0; i < frames.size(); i++) {
82 last = i;
83 if (frames[i].duration > 0) break;
84 }
85 return last;
86 }
87
Main()88 ImageBundle& Main() { return frames[LastStillFrame()]; }
Main()89 const ImageBundle& Main() const { return frames[LastStillFrame()]; }
90
91 // If c_current.IsGray(), all planes must be identical.
SetFromImage(Image3F && color,const ColorEncoding & c_current)92 void SetFromImage(Image3F&& color, const ColorEncoding& c_current) {
93 Main().SetFromImage(std::move(color), c_current);
94 SetIntensityTarget(this);
95 SetSize(Main().xsize(), Main().ysize());
96 }
97
SetSize(size_t xsize,size_t ysize)98 void SetSize(size_t xsize, size_t ysize) {
99 JXL_CHECK(metadata.size.Set(xsize, ysize));
100 }
101
CheckMetadata()102 void CheckMetadata() const {
103 JXL_CHECK(metadata.m.bit_depth.bits_per_sample != 0);
104 JXL_CHECK(!metadata.m.color_encoding.ICC().empty());
105
106 if (preview_frame.xsize() != 0) preview_frame.VerifyMetadata();
107 JXL_CHECK(preview_frame.metadata() == &metadata.m);
108
109 for (const ImageBundle& ib : frames) {
110 ib.VerifyMetadata();
111 JXL_CHECK(ib.metadata() == &metadata.m);
112 }
113 }
114
xsize()115 size_t xsize() const { return metadata.size.xsize(); }
ysize()116 size_t ysize() const { return metadata.size.ysize(); }
ShrinkTo(size_t xsize,size_t ysize)117 void ShrinkTo(size_t xsize, size_t ysize) {
118 // preview is unaffected.
119 for (ImageBundle& ib : frames) {
120 ib.ShrinkTo(xsize, ysize);
121 }
122 SetSize(xsize, ysize);
123 }
124
125 // Calls TransformTo for each ImageBundle (preview/frames).
126 Status TransformTo(const ColorEncoding& c_desired, const JxlCmsInterface& cms,
127 ThreadPool* pool = nullptr) {
128 if (metadata.m.have_preview) {
129 JXL_RETURN_IF_ERROR(preview_frame.TransformTo(c_desired, cms, pool));
130 }
131 for (ImageBundle& ib : frames) {
132 JXL_RETURN_IF_ERROR(ib.TransformTo(c_desired, cms, pool));
133 }
134 return true;
135 }
136 // Calls PremultiplyAlpha for each ImageBundle (preview/frames).
PremultiplyAlpha()137 void PremultiplyAlpha() {
138 ExtraChannelInfo* eci = metadata.m.Find(ExtraChannel::kAlpha);
139 if (eci == nullptr || eci->alpha_associated) return; // nothing to do
140 if (metadata.m.have_preview) {
141 preview_frame.PremultiplyAlpha();
142 }
143 for (ImageBundle& ib : frames) {
144 ib.PremultiplyAlpha();
145 }
146 eci->alpha_associated = true;
147 return;
148 }
149
150 // -- DECODER INPUT:
151
152 SizeConstraints constraints;
153
154 // -- DECODER OUTPUT:
155
156 // Total number of pixels decoded (may differ from #frames * xsize * ysize
157 // if frames are cropped)
158 uint64_t dec_pixels = 0;
159
160 // -- DECODER OUTPUT, ENCODER INPUT:
161
162 // Metadata stored into / retrieved from bitstreams.
163
164 Blobs blobs;
165
166 CodecMetadata metadata; // applies to preview and all frames
167
168 // If metadata.have_preview:
169 ImageBundle preview_frame;
170
171 std::vector<ImageBundle> frames; // size=1 if !metadata.have_animation
172
173 bool use_sjpeg = false;
174 // If the image should be written to a JPEG, use this quality for encoding.
175 size_t jpeg_quality;
176 };
177
178 } // namespace jxl
179
180 #endif // LIB_JXL_CODEC_IN_OUT_H_
181