/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 | 90.7k | constexpr uint32_t MulTruncate(uint32_t multiplicand) const { |
28 | 90.7k | return static_cast<uint64_t>(multiplicand) * num / den; |
29 | 90.7k | } |
30 | | |
31 | | uint32_t num; |
32 | | uint32_t den; |
33 | | }; |
34 | | |
35 | 90.7k | Rational FixedAspectRatios(uint32_t ratio) { |
36 | 90.7k | JXL_DASSERT(0 != ratio && ratio < 8); |
37 | | // Other candidates: 5/4, 7/5, 14/9, 16/10, 5/3, 21/9, 12/5 |
38 | 90.7k | constexpr Rational kRatios[7] = {Rational(1, 1), // square |
39 | 90.7k | Rational(12, 10), // |
40 | 90.7k | Rational(4, 3), // camera |
41 | 90.7k | Rational(3, 2), // mobile camera |
42 | 90.7k | Rational(16, 9), // camera/display |
43 | 90.7k | Rational(5, 4), // |
44 | 90.7k | Rational(2, 1)}; // |
45 | 90.7k | return kRatios[ratio - 1]; |
46 | 90.7k | } |
47 | | |
48 | 217 | uint32_t FindAspectRatio(uint32_t xsize, uint32_t ysize) { |
49 | 1.48k | for (uint32_t r = 1; r < 8; ++r) { |
50 | 1.32k | if (xsize == FixedAspectRatios(r).MulTruncate(ysize)) { |
51 | 52 | return r; |
52 | 52 | } |
53 | 1.32k | } |
54 | 165 | return 0; // Must send xsize instead |
55 | 217 | } |
56 | | |
57 | | } // namespace |
58 | | |
59 | 263k | size_t SizeHeader::xsize() const { |
60 | 263k | if (ratio_ != 0) { |
61 | 89.1k | return FixedAspectRatios(ratio_).MulTruncate( |
62 | 89.1k | static_cast<uint32_t>(ysize())); |
63 | 89.1k | } |
64 | 174k | return small_ ? ((xsize_div8_minus_1_ + 1) * 8) : xsize_; |
65 | 263k | } |
66 | | |
67 | 230 | Status SizeHeader::Set(size_t xsize64, size_t ysize64) { |
68 | 230 | constexpr size_t kDimensionCap = std::numeric_limits<uint32_t>::max(); |
69 | 230 | if (xsize64 > kDimensionCap || ysize64 > kDimensionCap) { |
70 | 0 | return JXL_FAILURE("Image too large"); |
71 | 0 | } |
72 | 230 | const uint32_t xsize32 = static_cast<uint32_t>(xsize64); |
73 | 230 | const uint32_t ysize32 = static_cast<uint32_t>(ysize64); |
74 | 230 | if (xsize64 == 0 || ysize64 == 0) return JXL_FAILURE("Empty image"); |
75 | 217 | ratio_ = FindAspectRatio(xsize32, ysize32); |
76 | 217 | small_ = ysize64 <= 256 && (ysize64 % kBlockDim) == 0 && |
77 | 217 | (ratio_ != 0 || (xsize64 <= 256 && (xsize64 % kBlockDim) == 0)); |
78 | 217 | if (small_) { |
79 | 39 | ysize_div8_minus_1_ = ysize32 / 8 - 1; |
80 | 178 | } else { |
81 | 178 | ysize_ = ysize32; |
82 | 178 | } |
83 | | |
84 | 217 | if (ratio_ == 0) { |
85 | 165 | if (small_) { |
86 | 22 | xsize_div8_minus_1_ = xsize32 / 8 - 1; |
87 | 143 | } else { |
88 | 143 | xsize_ = xsize32; |
89 | 143 | } |
90 | 165 | } |
91 | 217 | JXL_ENSURE(xsize() == xsize64); |
92 | 217 | JXL_ENSURE(ysize() == ysize64); |
93 | 217 | return true; |
94 | 217 | } |
95 | | |
96 | 0 | Status PreviewHeader::Set(size_t xsize64, size_t ysize64) { |
97 | 0 | const uint32_t xsize32 = static_cast<uint32_t>(xsize64); |
98 | 0 | const uint32_t ysize32 = static_cast<uint32_t>(ysize64); |
99 | 0 | if (xsize64 == 0 || ysize64 == 0) return JXL_FAILURE("Empty preview"); |
100 | 0 | div8_ = (xsize64 % kBlockDim) == 0 && (ysize64 % kBlockDim) == 0; |
101 | 0 | if (div8_) { |
102 | 0 | ysize_div8_ = ysize32 / 8; |
103 | 0 | } else { |
104 | 0 | ysize_ = ysize32; |
105 | 0 | } |
106 | |
|
107 | 0 | ratio_ = FindAspectRatio(xsize32, ysize32); |
108 | 0 | if (ratio_ == 0) { |
109 | 0 | if (div8_) { |
110 | 0 | xsize_div8_ = xsize32 / 8; |
111 | 0 | } else { |
112 | 0 | xsize_ = xsize32; |
113 | 0 | } |
114 | 0 | } |
115 | 0 | JXL_ENSURE(xsize() == xsize64); |
116 | 0 | JXL_ENSURE(ysize() == ysize64); |
117 | 0 | return true; |
118 | 0 | } |
119 | | |
120 | 372 | size_t PreviewHeader::xsize() const { |
121 | 372 | if (ratio_ != 0) { |
122 | 223 | return FixedAspectRatios(ratio_).MulTruncate( |
123 | 223 | static_cast<uint32_t>(ysize())); |
124 | 223 | } |
125 | 149 | return div8_ ? (xsize_div8_ * 8) : xsize_; |
126 | 372 | } |
127 | | |
128 | 73.8k | SizeHeader::SizeHeader() { Bundle::Init(this); } |
129 | 115k | Status SizeHeader::VisitFields(Visitor* JXL_RESTRICT visitor) { |
130 | 115k | JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &small_)); |
131 | | |
132 | 115k | if (visitor->Conditional(small_)) { |
133 | 106k | JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(5, 0, &ysize_div8_minus_1_)); |
134 | 106k | } |
135 | 115k | if (visitor->Conditional(!small_)) { |
136 | | // (Could still be small, but non-multiple of 8.) |
137 | 97.1k | JXL_QUIET_RETURN_IF_ERROR(visitor->U32(BitsOffset(9, 1), BitsOffset(13, 1), |
138 | 97.1k | BitsOffset(18, 1), BitsOffset(30, 1), |
139 | 97.1k | 1, &ysize_)); |
140 | 97.1k | } |
141 | | |
142 | 115k | JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(3, 0, &ratio_)); |
143 | 115k | if (visitor->Conditional(ratio_ == 0 && small_)) { |
144 | 99.8k | JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(5, 0, &xsize_div8_minus_1_)); |
145 | 99.8k | } |
146 | 115k | if (visitor->Conditional(ratio_ == 0 && !small_)) { |
147 | 92.4k | JXL_QUIET_RETURN_IF_ERROR(visitor->U32(BitsOffset(9, 1), BitsOffset(13, 1), |
148 | 92.4k | BitsOffset(18, 1), BitsOffset(30, 1), |
149 | 92.4k | 1, &xsize_)); |
150 | 92.4k | } |
151 | | |
152 | 115k | return true; |
153 | 115k | } |
154 | | |
155 | 44.0k | PreviewHeader::PreviewHeader() { Bundle::Init(this); } |
156 | 59.1k | Status PreviewHeader::VisitFields(Visitor* JXL_RESTRICT visitor) { |
157 | 59.1k | JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &div8_)); |
158 | | |
159 | 59.1k | if (visitor->Conditional(div8_)) { |
160 | 58.9k | JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(16), Val(32), BitsOffset(5, 1), |
161 | 58.9k | BitsOffset(9, 33), 1, &ysize_div8_)); |
162 | 58.9k | } |
163 | 59.1k | if (visitor->Conditional(!div8_)) { |
164 | 58.9k | JXL_QUIET_RETURN_IF_ERROR(visitor->U32(BitsOffset(6, 1), BitsOffset(8, 65), |
165 | 58.9k | BitsOffset(10, 321), |
166 | 58.9k | BitsOffset(12, 1345), 1, &ysize_)); |
167 | 58.9k | } |
168 | | |
169 | 59.1k | JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(3, 0, &ratio_)); |
170 | 59.1k | if (visitor->Conditional(ratio_ == 0 && div8_)) { |
171 | 58.8k | JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(16), Val(32), BitsOffset(5, 1), |
172 | 58.8k | BitsOffset(9, 33), 1, &xsize_div8_)); |
173 | 58.8k | } |
174 | 59.1k | if (visitor->Conditional(ratio_ == 0 && !div8_)) { |
175 | 58.8k | JXL_QUIET_RETURN_IF_ERROR(visitor->U32(BitsOffset(6, 1), BitsOffset(8, 65), |
176 | 58.8k | BitsOffset(10, 321), |
177 | 58.8k | BitsOffset(12, 1345), 1, &xsize_)); |
178 | 58.8k | } |
179 | | |
180 | 59.1k | return true; |
181 | 59.1k | } |
182 | | |
183 | 44.0k | AnimationHeader::AnimationHeader() { Bundle::Init(this); } |
184 | 59.2k | Status AnimationHeader::VisitFields(Visitor* JXL_RESTRICT visitor) { |
185 | 59.2k | JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(100), Val(1000), BitsOffset(10, 1), |
186 | 59.2k | BitsOffset(30, 1), 1, &tps_numerator)); |
187 | 59.2k | JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(1), Val(1001), BitsOffset(8, 1), |
188 | 59.2k | BitsOffset(10, 1), 1, |
189 | 59.2k | &tps_denominator)); |
190 | | |
191 | 59.2k | JXL_QUIET_RETURN_IF_ERROR( |
192 | 59.2k | visitor->U32(Val(0), Bits(3), Bits(16), Bits(32), 0, &num_loops)); |
193 | | |
194 | 59.2k | JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &have_timecodes)); |
195 | 59.2k | return true; |
196 | 59.2k | } |
197 | | |
198 | | Status ReadSizeHeader(BitReader* JXL_RESTRICT reader, |
199 | 0 | SizeHeader* JXL_RESTRICT size) { |
200 | 0 | return Bundle::Read(reader, size); |
201 | 0 | } |
202 | | |
203 | | } // namespace jxl |