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