/src/libjxl/lib/jxl/headers.cc
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 | | #include "lib/jxl/headers.h" |
7 | | |
8 | | #include <cstddef> |
9 | | #include <cstdint> |
10 | | #include <limits> |
11 | | |
12 | | #include "lib/jxl/base/compiler_specific.h" |
13 | | #include "lib/jxl/base/status.h" |
14 | | #include "lib/jxl/dec_bit_reader.h" |
15 | | #include "lib/jxl/field_encodings.h" |
16 | | #include "lib/jxl/fields.h" |
17 | | #include "lib/jxl/frame_dimensions.h" |
18 | | |
19 | | namespace jxl { |
20 | | namespace { |
21 | | |
22 | | struct Rational { |
23 | | constexpr explicit Rational(uint32_t num, uint32_t den) |
24 | 0 | : num(num), den(den) {} |
25 | | |
26 | | // Returns floor(multiplicand * rational). |
27 | 1.18M | constexpr uint32_t MulTruncate(uint32_t multiplicand) const { |
28 | 1.18M | return static_cast<uint64_t>(multiplicand) * num / den; |
29 | 1.18M | } |
30 | | |
31 | | uint32_t num; |
32 | | uint32_t den; |
33 | | }; |
34 | | |
35 | 1.18M | Rational FixedAspectRatios(uint32_t ratio) { |
36 | 1.18M | JXL_DASSERT(0 != ratio && ratio < 8); |
37 | | // Other candidates: 5/4, 7/5, 14/9, 16/10, 5/3, 21/9, 12/5 |
38 | 1.18M | constexpr Rational kRatios[7] = {Rational(1, 1), // square |
39 | 1.18M | Rational(12, 10), // |
40 | 1.18M | Rational(4, 3), // camera |
41 | 1.18M | Rational(3, 2), // mobile camera |
42 | 1.18M | Rational(16, 9), // camera/display |
43 | 1.18M | Rational(5, 4), // |
44 | 1.18M | Rational(2, 1)}; // |
45 | 1.18M | return kRatios[ratio - 1]; |
46 | 1.18M | } |
47 | | |
48 | 1.49k | uint32_t FindAspectRatio(uint32_t xsize, uint32_t ysize) { |
49 | 6.94k | for (uint32_t r = 1; r < 8; ++r) { |
50 | 6.42k | if (xsize == FixedAspectRatios(r).MulTruncate(ysize)) { |
51 | 972 | return r; |
52 | 972 | } |
53 | 6.42k | } |
54 | 519 | return 0; // Must send xsize instead |
55 | 1.49k | } |
56 | | |
57 | | } // namespace |
58 | | |
59 | 1.64M | size_t SizeHeader::xsize() const { |
60 | 1.64M | if (ratio_ != 0) { |
61 | 1.14M | return FixedAspectRatios(ratio_).MulTruncate( |
62 | 1.14M | static_cast<uint32_t>(ysize())); |
63 | 1.14M | } |
64 | 496k | return small_ ? ((xsize_div8_minus_1_ + 1) * 8) : xsize_; |
65 | 1.64M | } |
66 | | |
67 | 1.47k | Status SizeHeader::Set(size_t xsize64, size_t ysize64) { |
68 | 1.47k | constexpr size_t kDimensionCap = std::numeric_limits<uint32_t>::max(); |
69 | 1.47k | if (xsize64 > kDimensionCap || ysize64 > kDimensionCap) { |
70 | 0 | return JXL_FAILURE("Image too large"); |
71 | 0 | } |
72 | 1.47k | const uint32_t xsize32 = static_cast<uint32_t>(xsize64); |
73 | 1.47k | const uint32_t ysize32 = static_cast<uint32_t>(ysize64); |
74 | 1.47k | if (xsize64 == 0 || ysize64 == 0) return JXL_FAILURE("Empty image"); |
75 | 1.47k | ratio_ = FindAspectRatio(xsize32, ysize32); |
76 | 1.47k | small_ = ysize64 <= 256 && (ysize64 % kBlockDim) == 0 && |
77 | 1.47k | (ratio_ != 0 || (xsize64 <= 256 && (xsize64 % kBlockDim) == 0)); |
78 | 1.47k | if (small_) { |
79 | 347 | ysize_div8_minus_1_ = ysize32 / 8 - 1; |
80 | 1.13k | } else { |
81 | 1.13k | ysize_ = ysize32; |
82 | 1.13k | } |
83 | | |
84 | 1.47k | if (ratio_ == 0) { |
85 | 517 | if (small_) { |
86 | 108 | xsize_div8_minus_1_ = xsize32 / 8 - 1; |
87 | 409 | } else { |
88 | 409 | xsize_ = xsize32; |
89 | 409 | } |
90 | 517 | } |
91 | 1.47k | JXL_ENSURE(xsize() == xsize64); |
92 | 1.47k | JXL_ENSURE(ysize() == ysize64); |
93 | 1.47k | return true; |
94 | 1.47k | } |
95 | | |
96 | 12 | Status PreviewHeader::Set(size_t xsize64, size_t ysize64) { |
97 | 12 | const uint32_t xsize32 = static_cast<uint32_t>(xsize64); |
98 | 12 | const uint32_t ysize32 = static_cast<uint32_t>(ysize64); |
99 | 12 | if (xsize64 == 0 || ysize64 == 0) return JXL_FAILURE("Empty preview"); |
100 | 12 | div8_ = (xsize64 % kBlockDim) == 0 && (ysize64 % kBlockDim) == 0; |
101 | 12 | if (div8_) { |
102 | 5 | ysize_div8_ = ysize32 / 8; |
103 | 7 | } else { |
104 | 7 | ysize_ = ysize32; |
105 | 7 | } |
106 | | |
107 | 12 | ratio_ = FindAspectRatio(xsize32, ysize32); |
108 | 12 | if (ratio_ == 0) { |
109 | 2 | if (div8_) { |
110 | 1 | xsize_div8_ = xsize32 / 8; |
111 | 1 | } else { |
112 | 1 | xsize_ = xsize32; |
113 | 1 | } |
114 | 2 | } |
115 | 12 | JXL_ENSURE(xsize() == xsize64); |
116 | 12 | JXL_ENSURE(ysize() == ysize64); |
117 | 12 | return true; |
118 | 12 | } |
119 | | |
120 | 32.1k | size_t PreviewHeader::xsize() const { |
121 | 32.1k | if (ratio_ != 0) { |
122 | 27.6k | return FixedAspectRatios(ratio_).MulTruncate( |
123 | 27.6k | static_cast<uint32_t>(ysize())); |
124 | 27.6k | } |
125 | 4.55k | return div8_ ? (xsize_div8_ * 8) : xsize_; |
126 | 32.1k | } |
127 | | |
128 | 314k | SizeHeader::SizeHeader() { Bundle::Init(this); } |
129 | 820k | Status SizeHeader::VisitFields(Visitor* JXL_RESTRICT visitor) { |
130 | 820k | JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &small_)); |
131 | | |
132 | 820k | if (visitor->Conditional(small_)) { |
133 | 633k | JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(5, 0, &ysize_div8_minus_1_)); |
134 | 633k | } |
135 | 818k | if (visitor->Conditional(!small_)) { |
136 | | // (Could still be small, but non-multiple of 8.) |
137 | 534k | JXL_QUIET_RETURN_IF_ERROR(visitor->U32(BitsOffset(9, 1), BitsOffset(13, 1), |
138 | 534k | BitsOffset(18, 1), BitsOffset(30, 1), |
139 | 534k | 1, &ysize_)); |
140 | 534k | } |
141 | | |
142 | 813k | JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(3, 0, &ratio_)); |
143 | 807k | if (visitor->Conditional(ratio_ == 0 && small_)) { |
144 | 406k | JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(5, 0, &xsize_div8_minus_1_)); |
145 | 406k | } |
146 | 806k | if (visitor->Conditional(ratio_ == 0 && !small_)) { |
147 | 416k | JXL_QUIET_RETURN_IF_ERROR(visitor->U32(BitsOffset(9, 1), BitsOffset(13, 1), |
148 | 416k | BitsOffset(18, 1), BitsOffset(30, 1), |
149 | 416k | 1, &xsize_)); |
150 | 416k | } |
151 | | |
152 | 804k | return true; |
153 | 806k | } |
154 | | |
155 | 183k | PreviewHeader::PreviewHeader() { Bundle::Init(this); } |
156 | 261k | Status PreviewHeader::VisitFields(Visitor* JXL_RESTRICT visitor) { |
157 | 261k | JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &div8_)); |
158 | | |
159 | 260k | if (visitor->Conditional(div8_)) { |
160 | 242k | JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(16), Val(32), BitsOffset(5, 1), |
161 | 242k | BitsOffset(9, 33), 1, &ysize_div8_)); |
162 | 242k | } |
163 | 259k | if (visitor->Conditional(!div8_)) { |
164 | 235k | JXL_QUIET_RETURN_IF_ERROR(visitor->U32(BitsOffset(6, 1), BitsOffset(8, 65), |
165 | 235k | BitsOffset(10, 321), |
166 | 235k | BitsOffset(12, 1345), 1, &ysize_)); |
167 | 235k | } |
168 | | |
169 | 258k | JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(3, 0, &ratio_)); |
170 | 257k | if (visitor->Conditional(ratio_ == 0 && div8_)) { |
171 | 225k | JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(16), Val(32), BitsOffset(5, 1), |
172 | 225k | BitsOffset(9, 33), 1, &xsize_div8_)); |
173 | 225k | } |
174 | 256k | if (visitor->Conditional(ratio_ == 0 && !div8_)) { |
175 | 229k | JXL_QUIET_RETURN_IF_ERROR(visitor->U32(BitsOffset(6, 1), BitsOffset(8, 65), |
176 | 229k | BitsOffset(10, 321), |
177 | 229k | BitsOffset(12, 1345), 1, &xsize_)); |
178 | 229k | } |
179 | | |
180 | 256k | return true; |
181 | 256k | } |
182 | | |
183 | 183k | AnimationHeader::AnimationHeader() { Bundle::Init(this); } |
184 | 242k | Status AnimationHeader::VisitFields(Visitor* JXL_RESTRICT visitor) { |
185 | 242k | JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(100), Val(1000), BitsOffset(10, 1), |
186 | 242k | BitsOffset(30, 1), 1, &tps_numerator)); |
187 | 241k | JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(1), Val(1001), BitsOffset(8, 1), |
188 | 241k | BitsOffset(10, 1), 1, |
189 | 241k | &tps_denominator)); |
190 | | |
191 | 240k | JXL_QUIET_RETURN_IF_ERROR( |
192 | 240k | visitor->U32(Val(0), Bits(3), Bits(16), Bits(32), 0, &num_loops)); |
193 | | |
194 | 238k | JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &have_timecodes)); |
195 | 238k | return true; |
196 | 238k | } |
197 | | |
198 | | Status ReadSizeHeader(BitReader* JXL_RESTRICT reader, |
199 | 8 | SizeHeader* JXL_RESTRICT size) { |
200 | 8 | return Bundle::Read(reader, size); |
201 | 8 | } |
202 | | |
203 | | } // namespace jxl |