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_COMMON_H_
7 #define LIB_JXL_COMMON_H_
8
9 // Shared constants and helper functions.
10
11 #include <inttypes.h>
12 #include <stddef.h>
13 #include <stdio.h>
14
15 #include <limits> // numeric_limits
16 #include <memory> // unique_ptr
17 #include <string>
18
19 #include "lib/jxl/base/compiler_specific.h"
20
21 #ifndef JXL_HIGH_PRECISION
22 #define JXL_HIGH_PRECISION 1
23 #endif
24
25 // Macro that defines whether support for decoding JXL files to JPEG is enabled.
26 #ifndef JPEGXL_ENABLE_TRANSCODE_JPEG
27 #define JPEGXL_ENABLE_TRANSCODE_JPEG 1
28 #endif // JPEGXL_ENABLE_TRANSCODE_JPEG
29
30 namespace jxl {
31 // Some enums and typedefs used by more than one header file.
32
33 constexpr size_t kBitsPerByte = 8; // more clear than CHAR_BIT
34
RoundUpBitsToByteMultiple(size_t bits)35 constexpr inline size_t RoundUpBitsToByteMultiple(size_t bits) {
36 return (bits + 7) & ~size_t(7);
37 }
38
RoundUpToBlockDim(size_t dim)39 constexpr inline size_t RoundUpToBlockDim(size_t dim) {
40 return (dim + 7) & ~size_t(7);
41 }
42
SafeAdd(const uint64_t a,const uint64_t b,uint64_t & sum)43 static inline bool JXL_MAYBE_UNUSED SafeAdd(const uint64_t a, const uint64_t b,
44 uint64_t& sum) {
45 sum = a + b;
46 return sum >= a; // no need to check b - either sum >= both or < both.
47 }
48
49 template <typename T1, typename T2>
DivCeil(T1 a,T2 b)50 constexpr inline T1 DivCeil(T1 a, T2 b) {
51 return (a + b - 1) / b;
52 }
53
54 // Works for any `align`; if a power of two, compiler emits ADD+AND.
RoundUpTo(size_t what,size_t align)55 constexpr inline size_t RoundUpTo(size_t what, size_t align) {
56 return DivCeil(what, align) * align;
57 }
58
59 constexpr double kPi = 3.14159265358979323846264338327950288;
60
61 // Reasonable default for sRGB, matches common monitors. We map white to this
62 // many nits (cd/m^2) by default. Butteraugli was tuned for 250 nits, which is
63 // very close.
64 static constexpr float kDefaultIntensityTarget = 255;
65
66 template <typename T>
Pi(T multiplier)67 constexpr T Pi(T multiplier) {
68 return static_cast<T>(multiplier * kPi);
69 }
70
71 // Block is the square grid of pixels to which an "energy compaction"
72 // transformation (e.g. DCT) is applied. Each block has its own AC quantizer.
73 constexpr size_t kBlockDim = 8;
74
75 constexpr size_t kDCTBlockSize = kBlockDim * kBlockDim;
76
77 constexpr size_t kGroupDim = 256;
78 static_assert(kGroupDim % kBlockDim == 0,
79 "Group dim should be divisible by block dim");
80 constexpr size_t kGroupDimInBlocks = kGroupDim / kBlockDim;
81
82 // Maximum number of passes in an image.
83 constexpr size_t kMaxNumPasses = 11;
84
85 // Maximum number of reference frames.
86 constexpr size_t kMaxNumReferenceFrames = 4;
87
88 // Dimensions of a frame, in pixels, and other derived dimensions.
89 // Computed from FrameHeader.
90 // TODO(veluca): add extra channels.
91 struct FrameDimensions {
SetFrameDimensions92 void Set(size_t xsize, size_t ysize, size_t group_size_shift,
93 size_t max_hshift, size_t max_vshift, bool modular_mode,
94 size_t upsampling) {
95 group_dim = (kGroupDim >> 1) << group_size_shift;
96 dc_group_dim = group_dim * kBlockDim;
97 xsize_upsampled = xsize;
98 ysize_upsampled = ysize;
99 this->xsize = DivCeil(xsize, upsampling);
100 this->ysize = DivCeil(ysize, upsampling);
101 xsize_blocks = DivCeil(this->xsize, kBlockDim << max_hshift) << max_hshift;
102 ysize_blocks = DivCeil(this->ysize, kBlockDim << max_vshift) << max_vshift;
103 xsize_padded = xsize_blocks * kBlockDim;
104 ysize_padded = ysize_blocks * kBlockDim;
105 if (modular_mode) {
106 // Modular mode doesn't have any padding.
107 xsize_padded = this->xsize;
108 ysize_padded = this->ysize;
109 }
110 xsize_upsampled_padded = xsize_padded * upsampling;
111 ysize_upsampled_padded = ysize_padded * upsampling;
112 xsize_groups = DivCeil(this->xsize, group_dim);
113 ysize_groups = DivCeil(this->ysize, group_dim);
114 xsize_dc_groups = DivCeil(xsize_blocks, group_dim);
115 ysize_dc_groups = DivCeil(ysize_blocks, group_dim);
116 num_groups = xsize_groups * ysize_groups;
117 num_dc_groups = xsize_dc_groups * ysize_dc_groups;
118 }
119
120 // Image size without any upsampling, i.e. original_size / upsampling.
121 size_t xsize;
122 size_t ysize;
123 // Original image size.
124 size_t xsize_upsampled;
125 size_t ysize_upsampled;
126 // Image size after upsampling the padded image.
127 size_t xsize_upsampled_padded;
128 size_t ysize_upsampled_padded;
129 // Image size after padding to a multiple of kBlockDim (if VarDCT mode).
130 size_t xsize_padded;
131 size_t ysize_padded;
132 // Image size in kBlockDim blocks.
133 size_t xsize_blocks;
134 size_t ysize_blocks;
135 // Image size in number of groups.
136 size_t xsize_groups;
137 size_t ysize_groups;
138 // Image size in number of DC groups.
139 size_t xsize_dc_groups;
140 size_t ysize_dc_groups;
141 // Number of AC or DC groups.
142 size_t num_groups;
143 size_t num_dc_groups;
144 // Size of a group.
145 size_t group_dim;
146 size_t dc_group_dim;
147 };
148
149 // Prior to C++14 (i.e. C++11): provide our own make_unique
150 #if __cplusplus < 201402L
151 template <typename T, typename... Args>
make_unique(Args &&...args)152 std::unique_ptr<T> make_unique(Args&&... args) {
153 return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
154 }
155 #else
156 using std::make_unique;
157 #endif
158
159 template <typename T>
Clamp1(T val,T low,T hi)160 JXL_INLINE T Clamp1(T val, T low, T hi) {
161 return val < low ? low : val > hi ? hi : val;
162 }
163
164 // Encodes non-negative (X) into (2 * X), negative (-X) into (2 * X - 1)
PackSigned(int32_t value)165 constexpr uint32_t PackSigned(int32_t value)
166 JXL_NO_SANITIZE("unsigned-integer-overflow") {
167 return (static_cast<uint32_t>(value) << 1) ^
168 ((static_cast<uint32_t>(~value) >> 31) - 1);
169 }
170
171 // Reverse to PackSigned, i.e. UnpackSigned(PackSigned(X)) == X.
172 // (((~value) & 1) - 1) is either 0 or 0xFF...FF and it will have an expected
173 // unsigned-integer-overflow.
UnpackSigned(size_t value)174 constexpr intptr_t UnpackSigned(size_t value)
175 JXL_NO_SANITIZE("unsigned-integer-overflow") {
176 return static_cast<intptr_t>((value >> 1) ^ (((~value) & 1) - 1));
177 }
178
179 // conversion from integer to string.
180 template <typename T>
ToString(T n)181 std::string ToString(T n) {
182 char data[32] = {};
183 if (T(0.1) != T(0)) {
184 // float
185 snprintf(data, sizeof(data), "%g", static_cast<double>(n));
186 } else if (T(-1) > T(0)) {
187 // unsigned
188 snprintf(data, sizeof(data), "%llu", static_cast<unsigned long long>(n));
189 } else {
190 // signed
191 snprintf(data, sizeof(data), "%lld", static_cast<long long>(n));
192 }
193 return data;
194 }
195 } // namespace jxl
196
197 #endif // LIB_JXL_COMMON_H_
198