/src/libjxl/lib/jxl/image.h
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 | | #ifndef LIB_JXL_IMAGE_H_ |
7 | | #define LIB_JXL_IMAGE_H_ |
8 | | |
9 | | // SIMD/multicore-friendly planar image representation with row accessors. |
10 | | |
11 | | #include <inttypes.h> |
12 | | #include <stddef.h> |
13 | | #include <stdint.h> |
14 | | #include <string.h> |
15 | | |
16 | | #include <algorithm> |
17 | | #include <sstream> |
18 | | #include <utility> // std::move |
19 | | |
20 | | #include "lib/jxl/base/cache_aligned.h" |
21 | | #include "lib/jxl/base/compiler_specific.h" |
22 | | #include "lib/jxl/base/status.h" |
23 | | #include "lib/jxl/common.h" |
24 | | |
25 | | namespace jxl { |
26 | | |
27 | | // Type-independent parts of Plane<> - reduces code duplication and facilitates |
28 | | // moving member function implementations to cc file. |
29 | | struct PlaneBase { |
30 | | PlaneBase() |
31 | | : xsize_(0), |
32 | | ysize_(0), |
33 | | orig_xsize_(0), |
34 | | orig_ysize_(0), |
35 | | bytes_per_row_(0), |
36 | 2.98M | bytes_(nullptr) {} |
37 | | PlaneBase(size_t xsize, size_t ysize, size_t sizeof_t); |
38 | | |
39 | | // Copy construction/assignment is forbidden to avoid inadvertent copies, |
40 | | // which can be very expensive. Use CopyImageTo() instead. |
41 | | PlaneBase(const PlaneBase& other) = delete; |
42 | | PlaneBase& operator=(const PlaneBase& other) = delete; |
43 | | |
44 | | // Move constructor (required for returning Image from function) |
45 | 1.28M | PlaneBase(PlaneBase&& other) noexcept = default; |
46 | | |
47 | | // Move assignment (required for std::vector) |
48 | 7.72M | PlaneBase& operator=(PlaneBase&& other) noexcept = default; |
49 | | |
50 | | void Swap(PlaneBase& other); |
51 | | |
52 | | // Useful for pre-allocating image with some padding for alignment purposes |
53 | | // and later reporting the actual valid dimensions. May also be used to |
54 | | // un-shrink the image. Caller is responsible for ensuring xsize/ysize are <= |
55 | | // the original dimensions. |
56 | 920 | void ShrinkTo(const size_t xsize, const size_t ysize) { |
57 | 920 | JXL_CHECK(xsize <= orig_xsize_); |
58 | 920 | JXL_CHECK(ysize <= orig_ysize_); |
59 | 920 | xsize_ = static_cast<uint32_t>(xsize); |
60 | 920 | ysize_ = static_cast<uint32_t>(ysize); |
61 | | // NOTE: we can't recompute bytes_per_row for more compact storage and |
62 | | // better locality because that would invalidate the image contents. |
63 | 920 | } |
64 | | |
65 | | // How many pixels. |
66 | 63.3M | JXL_INLINE size_t xsize() const { return xsize_; } |
67 | 20.3M | JXL_INLINE size_t ysize() const { return ysize_; } |
68 | | |
69 | | // NOTE: do not use this for copying rows - the valid xsize may be much less. |
70 | 13.8M | JXL_INLINE size_t bytes_per_row() const { return bytes_per_row_; } |
71 | | |
72 | | // Raw access to byte contents, for interfacing with other libraries. |
73 | | // Unsigned char instead of char to avoid surprises (sign extension). |
74 | 12.1M | JXL_INLINE uint8_t* bytes() { |
75 | 12.1M | void* p = bytes_.get(); |
76 | 12.1M | return static_cast<uint8_t * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(p, 64)); |
77 | 12.1M | } |
78 | 1.69M | JXL_INLINE const uint8_t* bytes() const { |
79 | 1.69M | const void* p = bytes_.get(); |
80 | 1.69M | return static_cast<const uint8_t * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(p, 64)); |
81 | 1.69M | } |
82 | | |
83 | | protected: |
84 | | // Returns pointer to the start of a row. |
85 | 369M | JXL_INLINE void* VoidRow(const size_t y) const { |
86 | | #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \ |
87 | | defined(THREAD_SANITIZER) |
88 | | if (y >= ysize_) { |
89 | | JXL_ABORT("Row(%" PRIu64 ") in (%u x %u) image\n", (uint64_t)y, xsize_, |
90 | | ysize_); |
91 | | } |
92 | | #endif |
93 | | |
94 | 369M | void* row = bytes_.get() + y * bytes_per_row_; |
95 | 369M | return JXL_ASSUME_ALIGNED(row, 64); |
96 | 369M | } |
97 | | |
98 | | enum class Padding { |
99 | | // Allow Load(d, row + x) for x = 0; x < xsize(); x += Lanes(d). Default. |
100 | | kRoundUp, |
101 | | // Allow LoadU(d, row + x) for x = xsize() - 1. This requires an extra |
102 | | // vector to be initialized. If done by default, this would suppress |
103 | | // legitimate msan warnings. We therefore require users to explicitly call |
104 | | // InitializePadding before using unaligned loads (e.g. convolution). |
105 | | kUnaligned |
106 | | }; |
107 | | |
108 | | // Initializes the minimum bytes required to suppress msan warnings from |
109 | | // legitimate (according to Padding mode) vector loads/stores on the right |
110 | | // border, where some lanes are uninitialized and assumed to be unused. |
111 | | void InitializePadding(size_t sizeof_t, Padding padding); |
112 | | |
113 | | // (Members are non-const to enable assignment during move-assignment.) |
114 | | uint32_t xsize_; // In valid pixels, not including any padding. |
115 | | uint32_t ysize_; |
116 | | uint32_t orig_xsize_; |
117 | | uint32_t orig_ysize_; |
118 | | size_t bytes_per_row_; // Includes padding. |
119 | | CacheAlignedUniquePtr bytes_; |
120 | | }; |
121 | | |
122 | | // Single channel, aligned rows separated by padding. T must be POD. |
123 | | // |
124 | | // 'Single channel' (one 2D array per channel) simplifies vectorization |
125 | | // (repeating the same operation on multiple adjacent components) without the |
126 | | // complexity of a hybrid layout (8 R, 8 G, 8 B, ...). In particular, clients |
127 | | // can easily iterate over all components in a row and Image requires no |
128 | | // knowledge of the pixel format beyond the component type "T". |
129 | | // |
130 | | // 'Aligned' means each row is aligned to the L1 cache line size. This prevents |
131 | | // false sharing between two threads operating on adjacent rows. |
132 | | // |
133 | | // 'Padding' is still relevant because vectors could potentially be larger than |
134 | | // a cache line. By rounding up row sizes to the vector size, we allow |
135 | | // reading/writing ALIGNED vectors whose first lane is a valid sample. This |
136 | | // avoids needing a separate loop to handle remaining unaligned lanes. |
137 | | // |
138 | | // This image layout could also be achieved with a vector and a row accessor |
139 | | // function, but a class wrapper with support for "deleter" allows wrapping |
140 | | // existing memory allocated by clients without copying the pixels. It also |
141 | | // provides convenient accessors for xsize/ysize, which shortens function |
142 | | // argument lists. Supports move-construction so it can be stored in containers. |
143 | | template <typename ComponentType> |
144 | | class Plane : public PlaneBase { |
145 | | public: |
146 | | using T = ComponentType; |
147 | | static constexpr size_t kNumPlanes = 1; |
148 | | |
149 | 2.98M | Plane() = default; Line | Count | Source | 149 | 786k | Plane() = default; |
jxl::Plane<unsigned char>::Plane() Line | Count | Source | 149 | 33.1k | Plane() = default; |
jxl::Plane<signed char>::Plane() Line | Count | Source | 149 | 22.0k | Plane() = default; |
jxl::Plane<float>::Plane() Line | Count | Source | 149 | 2.12M | Plane() = default; |
jxl::Plane<hwy::float16_t>::Plane() Line | Count | Source | 149 | 1.23k | Plane() = default; |
jxl::Plane<unsigned int>::Plane() Line | Count | Source | 149 | 8.50k | Plane() = default; |
jxl::Plane<short>::Plane() Line | Count | Source | 149 | 4.56k | Plane() = default; |
Unexecuted instantiation: jxl::Plane<double>::Plane() |
150 | | Plane(const size_t xsize, const size_t ysize) |
151 | 2.40M | : PlaneBase(xsize, ysize, sizeof(T)) {} jxl::Plane<int>::Plane(unsigned long, unsigned long) Line | Count | Source | 151 | 1.12M | : PlaneBase(xsize, ysize, sizeof(T)) {} |
jxl::Plane<float>::Plane(unsigned long, unsigned long) Line | Count | Source | 151 | 1.15M | : PlaneBase(xsize, ysize, sizeof(T)) {} |
jxl::Plane<hwy::float16_t>::Plane(unsigned long, unsigned long) Line | Count | Source | 151 | 1.23k | : PlaneBase(xsize, ysize, sizeof(T)) {} |
jxl::Plane<unsigned int>::Plane(unsigned long, unsigned long) Line | Count | Source | 151 | 8.50k | : PlaneBase(xsize, ysize, sizeof(T)) {} |
jxl::Plane<short>::Plane(unsigned long, unsigned long) Line | Count | Source | 151 | 4.56k | : PlaneBase(xsize, ysize, sizeof(T)) {} |
jxl::Plane<unsigned char>::Plane(unsigned long, unsigned long) Line | Count | Source | 151 | 72.8k | : PlaneBase(xsize, ysize, sizeof(T)) {} |
jxl::Plane<signed char>::Plane(unsigned long, unsigned long) Line | Count | Source | 151 | 48.3k | : PlaneBase(xsize, ysize, sizeof(T)) {} |
Unexecuted instantiation: jxl::Plane<double>::Plane(unsigned long, unsigned long) |
152 | | |
153 | | void InitializePaddingForUnalignedAccesses() { |
154 | | InitializePadding(sizeof(T), Padding::kUnaligned); |
155 | | } |
156 | | |
157 | 311M | JXL_INLINE T* Row(const size_t y) { return static_cast<T*>(VoidRow(y)); } Unexecuted instantiation: jxl::Plane<double>::Row(unsigned long) jxl::Plane<int>::Row(unsigned long) Line | Count | Source | 157 | 46.1M | JXL_INLINE T* Row(const size_t y) { return static_cast<T*>(VoidRow(y)); } |
jxl::Plane<unsigned char>::Row(unsigned long) Line | Count | Source | 157 | 913k | JXL_INLINE T* Row(const size_t y) { return static_cast<T*>(VoidRow(y)); } |
jxl::Plane<float>::Row(unsigned long) Line | Count | Source | 157 | 261M | JXL_INLINE T* Row(const size_t y) { return static_cast<T*>(VoidRow(y)); } |
jxl::Plane<hwy::float16_t>::Row(unsigned long) Line | Count | Source | 157 | 437k | JXL_INLINE T* Row(const size_t y) { return static_cast<T*>(VoidRow(y)); } |
jxl::Plane<unsigned int>::Row(unsigned long) Line | Count | Source | 157 | 2.04M | JXL_INLINE T* Row(const size_t y) { return static_cast<T*>(VoidRow(y)); } |
Unexecuted instantiation: jxl::Plane<short>::Row(unsigned long) jxl::Plane<signed char>::Row(unsigned long) Line | Count | Source | 157 | 293k | JXL_INLINE T* Row(const size_t y) { return static_cast<T*>(VoidRow(y)); } |
|
158 | | |
159 | | // Returns pointer to const (see above). |
160 | 57.6M | JXL_INLINE const T* Row(const size_t y) const { |
161 | 57.6M | return static_cast<const T*>(VoidRow(y)); |
162 | 57.6M | } Unexecuted instantiation: jxl::Plane<double>::Row(unsigned long) const jxl::Plane<float>::Row(unsigned long) const Line | Count | Source | 160 | 8.37M | JXL_INLINE const T* Row(const size_t y) const { | 161 | 8.37M | return static_cast<const T*>(VoidRow(y)); | 162 | 8.37M | } |
jxl::Plane<int>::Row(unsigned long) const Line | Count | Source | 160 | 49.2M | JXL_INLINE const T* Row(const size_t y) const { | 161 | 49.2M | return static_cast<const T*>(VoidRow(y)); | 162 | 49.2M | } |
Unexecuted instantiation: jxl::Plane<unsigned char>::Row(unsigned long) const |
163 | | |
164 | | // Documents that the access is const. |
165 | 8.18M | JXL_INLINE const T* ConstRow(const size_t y) const { |
166 | 8.18M | return static_cast<const T*>(VoidRow(y)); |
167 | 8.18M | } jxl::Plane<unsigned char>::ConstRow(unsigned long) const Line | Count | Source | 165 | 1.26M | JXL_INLINE const T* ConstRow(const size_t y) const { | 166 | 1.26M | return static_cast<const T*>(VoidRow(y)); | 167 | 1.26M | } |
jxl::Plane<float>::ConstRow(unsigned long) const Line | Count | Source | 165 | 4.66M | JXL_INLINE const T* ConstRow(const size_t y) const { | 166 | 4.66M | return static_cast<const T*>(VoidRow(y)); | 167 | 4.66M | } |
jxl::Plane<int>::ConstRow(unsigned long) const Line | Count | Source | 165 | 1.86M | JXL_INLINE const T* ConstRow(const size_t y) const { | 166 | 1.86M | return static_cast<const T*>(VoidRow(y)); | 167 | 1.86M | } |
jxl::Plane<signed char>::ConstRow(unsigned long) const Line | Count | Source | 165 | 389k | JXL_INLINE const T* ConstRow(const size_t y) const { | 166 | 389k | return static_cast<const T*>(VoidRow(y)); | 167 | 389k | } |
Unexecuted instantiation: jxl::Plane<double>::ConstRow(unsigned long) const |
168 | | |
169 | | // Returns number of pixels (some of which are padding) per row. Useful for |
170 | | // computing other rows via pointer arithmetic. WARNING: this must |
171 | | // NOT be used to determine xsize. |
172 | 3.25M | JXL_INLINE intptr_t PixelsPerRow() const { |
173 | 3.25M | return static_cast<intptr_t>(bytes_per_row_ / sizeof(T)); |
174 | 3.25M | } jxl::Plane<int>::PixelsPerRow() const Line | Count | Source | 172 | 2.82M | JXL_INLINE intptr_t PixelsPerRow() const { | 173 | 2.82M | return static_cast<intptr_t>(bytes_per_row_ / sizeof(T)); | 174 | 2.82M | } |
jxl::Plane<unsigned char>::PixelsPerRow() const Line | Count | Source | 172 | 28.0k | JXL_INLINE intptr_t PixelsPerRow() const { | 173 | 28.0k | return static_cast<intptr_t>(bytes_per_row_ / sizeof(T)); | 174 | 28.0k | } |
jxl::Plane<float>::PixelsPerRow() const Line | Count | Source | 172 | 400k | JXL_INLINE intptr_t PixelsPerRow() const { | 173 | 400k | return static_cast<intptr_t>(bytes_per_row_ / sizeof(T)); | 174 | 400k | } |
Unexecuted instantiation: jxl::Plane<short>::PixelsPerRow() const |
175 | | }; |
176 | | |
177 | | using ImageSB = Plane<int8_t>; |
178 | | using ImageB = Plane<uint8_t>; |
179 | | using ImageS = Plane<int16_t>; // signed integer or half-float |
180 | | using ImageU = Plane<uint16_t>; |
181 | | using ImageI = Plane<int32_t>; |
182 | | using ImageF = Plane<float>; |
183 | | using ImageD = Plane<double>; |
184 | | |
185 | | // Also works for Image3 and mixed argument types. |
186 | | template <class Image1, class Image2> |
187 | 448k | bool SameSize(const Image1& image1, const Image2& image2) { |
188 | 448k | return image1.xsize() == image2.xsize() && image1.ysize() == image2.ysize(); |
189 | 448k | } bool jxl::SameSize<jxl::RectT<unsigned long>, jxl::RectT<unsigned long> >(jxl::RectT<unsigned long> const&, jxl::RectT<unsigned long> const&) Line | Count | Source | 187 | 213k | bool SameSize(const Image1& image1, const Image2& image2) { | 188 | 213k | return image1.xsize() == image2.xsize() && image1.ysize() == image2.ysize(); | 189 | 213k | } |
bool jxl::SameSize<jxl::Plane<int>, jxl::Plane<int> >(jxl::Plane<int> const&, jxl::Plane<int> const&) Line | Count | Source | 187 | 1.45k | bool SameSize(const Image1& image1, const Image2& image2) { | 188 | 1.45k | return image1.xsize() == image2.xsize() && image1.ysize() == image2.ysize(); | 189 | 1.45k | } |
Unexecuted instantiation: bool jxl::SameSize<jxl::Plane<int>, jxl::Plane<float> >(jxl::Plane<int> const&, jxl::Plane<float> const&) Unexecuted instantiation: bool jxl::SameSize<jxl::RectT<unsigned long>, jxl::Image3<float> >(jxl::RectT<unsigned long> const&, jxl::Image3<float> const&) bool jxl::SameSize<jxl::RectT<unsigned long>, jxl::Plane<float> >(jxl::RectT<unsigned long> const&, jxl::Plane<float> const&) Line | Count | Source | 187 | 233k | bool SameSize(const Image1& image1, const Image2& image2) { | 188 | 233k | return image1.xsize() == image2.xsize() && image1.ysize() == image2.ysize(); | 189 | 233k | } |
bool jxl::SameSize<jxl::Plane<float>, jxl::Plane<float> >(jxl::Plane<float> const&, jxl::Plane<float> const&) Line | Count | Source | 187 | 184 | bool SameSize(const Image1& image1, const Image2& image2) { | 188 | 184 | return image1.xsize() == image2.xsize() && image1.ysize() == image2.ysize(); | 189 | 184 | } |
bool jxl::SameSize<jxl::ImageBundle, jxl::Image3<float> >(jxl::ImageBundle const&, jxl::Image3<float> const&) Line | Count | Source | 187 | 92 | bool SameSize(const Image1& image1, const Image2& image2) { | 188 | 92 | return image1.xsize() == image2.xsize() && image1.ysize() == image2.ysize(); | 189 | 92 | } |
Unexecuted instantiation: bool jxl::SameSize<jxl::Image3<float>, jxl::Image3<float> >(jxl::Image3<float> const&, jxl::Image3<float> const&) Unexecuted instantiation: bool jxl::SameSize<jxl::Plane<double>, jxl::Plane<double> >(jxl::Plane<double> const&, jxl::Plane<double> const&) |
190 | | |
191 | | template <typename T> |
192 | | class Image3; |
193 | | |
194 | | // Rectangular region in image(s). Factoring this out of Image instead of |
195 | | // shifting the pointer by x0/y0 allows this to apply to multiple images with |
196 | | // different resolutions (e.g. color transform and quantization field). |
197 | | // Can compare using SameSize(rect1, rect2). |
198 | | template <typename T> |
199 | | class RectT { |
200 | | public: |
201 | | // Most windows are xsize_max * ysize_max, except those on the borders where |
202 | | // begin + size_max > end. |
203 | | constexpr RectT(T xbegin, T ybegin, size_t xsize_max, size_t ysize_max, |
204 | | T xend, T yend) |
205 | | : x0_(xbegin), |
206 | | y0_(ybegin), |
207 | | xsize_(ClampedSize(xbegin, xsize_max, xend)), |
208 | 889k | ysize_(ClampedSize(ybegin, ysize_max, yend)) {} jxl::RectT<unsigned long>::RectT(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long) Line | Count | Source | 208 | 855k | ysize_(ClampedSize(ybegin, ysize_max, yend)) {} |
jxl::RectT<long>::RectT(long, long, unsigned long, unsigned long, long, long) Line | Count | Source | 208 | 34.1k | ysize_(ClampedSize(ybegin, ysize_max, yend)) {} |
|
209 | | |
210 | | // Construct with origin and known size (typically from another Rect). |
211 | | constexpr RectT(T xbegin, T ybegin, size_t xsize, size_t ysize) |
212 | 3.76M | : x0_(xbegin), y0_(ybegin), xsize_(xsize), ysize_(ysize) {} jxl::RectT<unsigned long>::RectT(unsigned long, unsigned long, unsigned long, unsigned long) Line | Count | Source | 212 | 2.88M | : x0_(xbegin), y0_(ybegin), xsize_(xsize), ysize_(ysize) {} |
jxl::RectT<long>::RectT(long, long, unsigned long, unsigned long) Line | Count | Source | 212 | 874k | : x0_(xbegin), y0_(ybegin), xsize_(xsize), ysize_(ysize) {} |
|
213 | | |
214 | | // Construct a rect that covers a whole image/plane/ImageBundle etc. |
215 | | template <typename ImageT> |
216 | | explicit RectT(const ImageT& image) |
217 | 544k | : RectT(0, 0, image.xsize(), image.ysize()) {} jxl::RectT<unsigned long>::RectT<jxl::Plane<float> >(jxl::Plane<float> const&) Line | Count | Source | 217 | 349k | : RectT(0, 0, image.xsize(), image.ysize()) {} |
jxl::RectT<unsigned long>::RectT<jxl::Image3<float> >(jxl::Image3<float> const&) Line | Count | Source | 217 | 736 | : RectT(0, 0, image.xsize(), image.ysize()) {} |
jxl::RectT<unsigned long>::RectT<jxl::Plane<int> >(jxl::Plane<int> const&) Line | Count | Source | 217 | 194k | : RectT(0, 0, image.xsize(), image.ysize()) {} |
Unexecuted instantiation: jxl::RectT<unsigned long>::RectT<jxl::Plane<unsigned char> >(jxl::Plane<unsigned char> const&) |
218 | | |
219 | 881k | RectT() : RectT(0, 0, 0, 0) {} |
220 | | |
221 | | RectT(const RectT&) = default; |
222 | | RectT& operator=(const RectT&) = default; |
223 | | |
224 | | // Construct a subrect that resides in an image/plane/ImageBundle etc. |
225 | | template <typename ImageT> |
226 | 129k | RectT Crop(const ImageT& image) const { |
227 | 129k | return Intersection(RectT(image)); |
228 | 129k | } |
229 | | |
230 | | // Construct a subrect that resides in the [0, ysize) x [0, xsize) region of |
231 | | // the current rect. |
232 | 35.7k | RectT Crop(size_t area_xsize, size_t area_ysize) const { |
233 | 35.7k | return Intersection(RectT(0, 0, area_xsize, area_ysize)); |
234 | 35.7k | } |
235 | | |
236 | | // Returns a rect that only contains `num` lines with offset `y` from `y0()`. |
237 | 5.24k | RectT Lines(size_t y, size_t num) const { |
238 | 5.24k | JXL_DASSERT(y + num <= ysize_); |
239 | 5.24k | return RectT(x0_, y0_ + y, xsize_, num); |
240 | 5.24k | } |
241 | | |
242 | 5.24k | RectT Line(size_t y) const { return Lines(y, 1); } |
243 | | |
244 | 198k | JXL_MUST_USE_RESULT RectT Intersection(const RectT& other) const { |
245 | 198k | return RectT(std::max(x0_, other.x0_), std::max(y0_, other.y0_), xsize_, |
246 | 198k | ysize_, std::min(x1(), other.x1()), |
247 | 198k | std::min(y1(), other.y1())); |
248 | 198k | } jxl::RectT<unsigned long>::Intersection(jxl::RectT<unsigned long> const&) const Line | Count | Source | 244 | 164k | JXL_MUST_USE_RESULT RectT Intersection(const RectT& other) const { | 245 | 164k | return RectT(std::max(x0_, other.x0_), std::max(y0_, other.y0_), xsize_, | 246 | 164k | ysize_, std::min(x1(), other.x1()), | 247 | 164k | std::min(y1(), other.y1())); | 248 | 164k | } |
jxl::RectT<long>::Intersection(jxl::RectT<long> const&) const Line | Count | Source | 244 | 34.1k | JXL_MUST_USE_RESULT RectT Intersection(const RectT& other) const { | 245 | 34.1k | return RectT(std::max(x0_, other.x0_), std::max(y0_, other.y0_), xsize_, | 246 | 34.1k | ysize_, std::min(x1(), other.x1()), | 247 | 34.1k | std::min(y1(), other.y1())); | 248 | 34.1k | } |
|
249 | | |
250 | | JXL_MUST_USE_RESULT RectT Translate(int64_t x_offset, |
251 | 347k | int64_t y_offset) const { |
252 | 347k | return RectT(x0_ + x_offset, y0_ + y_offset, xsize_, ysize_); |
253 | 347k | } Unexecuted instantiation: jxl::RectT<unsigned long>::Translate(long, long) const jxl::RectT<long>::Translate(long, long) const Line | Count | Source | 251 | 347k | int64_t y_offset) const { | 252 | 347k | return RectT(x0_ + x_offset, y0_ + y_offset, xsize_, ysize_); | 253 | 347k | } |
|
254 | | |
255 | | template <typename V> |
256 | 22.7M | V* Row(Plane<V>* image, size_t y) const { |
257 | 22.7M | JXL_DASSERT(y + y0_ >= 0); |
258 | 22.7M | return image->Row(y + y0_) + x0_; |
259 | 22.7M | } unsigned char* jxl::RectT<unsigned long>::Row<unsigned char>(jxl::Plane<unsigned char>*, unsigned long) const Line | Count | Source | 256 | 536k | V* Row(Plane<V>* image, size_t y) const { | 257 | 536k | JXL_DASSERT(y + y0_ >= 0); | 258 | 536k | return image->Row(y + y0_) + x0_; | 259 | 536k | } |
float* jxl::RectT<unsigned long>::Row<float>(jxl::Plane<float>*, unsigned long) const Line | Count | Source | 256 | 14.2M | V* Row(Plane<V>* image, size_t y) const { | 257 | 14.2M | JXL_DASSERT(y + y0_ >= 0); | 258 | 14.2M | return image->Row(y + y0_) + x0_; | 259 | 14.2M | } |
int* jxl::RectT<unsigned long>::Row<int>(jxl::Plane<int>*, unsigned long) const Line | Count | Source | 256 | 7.69M | V* Row(Plane<V>* image, size_t y) const { | 257 | 7.69M | JXL_DASSERT(y + y0_ >= 0); | 258 | 7.69M | return image->Row(y + y0_) + x0_; | 259 | 7.69M | } |
signed char* jxl::RectT<unsigned long>::Row<signed char>(jxl::Plane<signed char>*, unsigned long) const Line | Count | Source | 256 | 73.2k | V* Row(Plane<V>* image, size_t y) const { | 257 | 73.2k | JXL_DASSERT(y + y0_ >= 0); | 258 | 73.2k | return image->Row(y + y0_) + x0_; | 259 | 73.2k | } |
float* jxl::RectT<long>::Row<float>(jxl::Plane<float>*, unsigned long) const Line | Count | Source | 256 | 156k | V* Row(Plane<V>* image, size_t y) const { | 257 | 156k | JXL_DASSERT(y + y0_ >= 0); | 258 | 156k | return image->Row(y + y0_) + x0_; | 259 | 156k | } |
|
260 | | |
261 | | template <typename V> |
262 | | const V* Row(const Plane<V>* image, size_t y) const { |
263 | | JXL_DASSERT(y + y0_ >= 0); |
264 | | return image->Row(y + y0_) + x0_; |
265 | | } |
266 | | |
267 | | template <typename V> |
268 | 860k | V* PlaneRow(Image3<V>* image, const size_t c, size_t y) const { |
269 | 860k | JXL_DASSERT(y + y0_ >= 0); |
270 | 860k | return image->PlaneRow(c, y + y0_) + x0_; |
271 | 860k | } |
272 | | |
273 | | template <typename V> |
274 | 6.29M | const V* ConstRow(const Plane<V>& image, size_t y) const { |
275 | 6.29M | JXL_DASSERT(y + y0_ >= 0); |
276 | 6.29M | return image.ConstRow(y + y0_) + x0_; |
277 | 6.29M | } float const* jxl::RectT<unsigned long>::ConstRow<float>(jxl::Plane<float> const&, unsigned long) const Line | Count | Source | 274 | 4.28M | const V* ConstRow(const Plane<V>& image, size_t y) const { | 275 | 4.28M | JXL_DASSERT(y + y0_ >= 0); | 276 | 4.28M | return image.ConstRow(y + y0_) + x0_; | 277 | 4.28M | } |
int const* jxl::RectT<unsigned long>::ConstRow<int>(jxl::Plane<int> const&, unsigned long) const Line | Count | Source | 274 | 1.76M | const V* ConstRow(const Plane<V>& image, size_t y) const { | 275 | 1.76M | JXL_DASSERT(y + y0_ >= 0); | 276 | 1.76M | return image.ConstRow(y + y0_) + x0_; | 277 | 1.76M | } |
unsigned char const* jxl::RectT<unsigned long>::ConstRow<unsigned char>(jxl::Plane<unsigned char> const&, unsigned long) const Line | Count | Source | 274 | 242k | const V* ConstRow(const Plane<V>& image, size_t y) const { | 275 | 242k | JXL_DASSERT(y + y0_ >= 0); | 276 | 242k | return image.ConstRow(y + y0_) + x0_; | 277 | 242k | } |
signed char const* jxl::RectT<unsigned long>::ConstRow<signed char>(jxl::Plane<signed char> const&, unsigned long) const Line | Count | Source | 274 | 368 | const V* ConstRow(const Plane<V>& image, size_t y) const { | 275 | 368 | JXL_DASSERT(y + y0_ >= 0); | 276 | 368 | return image.ConstRow(y + y0_) + x0_; | 277 | 368 | } |
|
278 | | |
279 | | template <typename V> |
280 | 583k | const V* ConstPlaneRow(const Image3<V>& image, size_t c, size_t y) const { |
281 | 583k | JXL_DASSERT(y + y0_ >= 0); |
282 | 583k | return image.ConstPlaneRow(c, y + y0_) + x0_; |
283 | 583k | } |
284 | | |
285 | 443k | bool IsInside(const RectT& other) const { |
286 | 443k | return x0_ >= other.x0() && x1() <= other.x1() && y0_ >= other.y0() && |
287 | 443k | y1() <= other.y1(); |
288 | 443k | } |
289 | | |
290 | | // Returns true if this Rect fully resides in the given image. ImageT could be |
291 | | // Plane<T> or Image3<T>; however if ImageT is Rect, results are nonsensical. |
292 | | template <class ImageT> |
293 | 403k | bool IsInside(const ImageT& image) const { |
294 | 403k | return IsInside(RectT(image)); |
295 | 403k | } bool jxl::RectT<unsigned long>::IsInside<jxl::Plane<float> >(jxl::Plane<float> const&) const Line | Count | Source | 293 | 349k | bool IsInside(const ImageT& image) const { | 294 | 349k | return IsInside(RectT(image)); | 295 | 349k | } |
bool jxl::RectT<unsigned long>::IsInside<jxl::Plane<int> >(jxl::Plane<int> const&) const Line | Count | Source | 293 | 53.8k | bool IsInside(const ImageT& image) const { | 294 | 53.8k | return IsInside(RectT(image)); | 295 | 53.8k | } |
|
296 | | |
297 | 36.8M | T x0() const { return x0_; } jxl::RectT<unsigned long>::x0() const Line | Count | Source | 297 | 36.8M | T x0() const { return x0_; } |
jxl::RectT<long>::x0() const Line | Count | Source | 297 | 22.6k | T x0() const { return x0_; } |
|
298 | 37.1M | T y0() const { return y0_; } jxl::RectT<unsigned long>::y0() const Line | Count | Source | 298 | 37.1M | T y0() const { return y0_; } |
jxl::RectT<long>::y0() const Line | Count | Source | 298 | 11.5k | T y0() const { return y0_; } |
|
299 | 64.4M | size_t xsize() const { return xsize_; } jxl::RectT<unsigned long>::xsize() const Line | Count | Source | 299 | 64.4M | size_t xsize() const { return xsize_; } |
jxl::RectT<long>::xsize() const Line | Count | Source | 299 | 27.0k | size_t xsize() const { return xsize_; } |
|
300 | 45.9M | size_t ysize() const { return ysize_; } jxl::RectT<unsigned long>::ysize() const Line | Count | Source | 300 | 45.9M | size_t ysize() const { return ysize_; } |
jxl::RectT<long>::ysize() const Line | Count | Source | 300 | 22.7k | size_t ysize() const { return ysize_; } |
|
301 | 1.34M | T x1() const { return x0_ + xsize_; } jxl::RectT<unsigned long>::x1() const Line | Count | Source | 301 | 1.25M | T x1() const { return x0_ + xsize_; } |
jxl::RectT<long>::x1() const Line | Count | Source | 301 | 91.0k | T x1() const { return x0_ + xsize_; } |
|
302 | 1.29M | T y1() const { return y0_ + ysize_; } jxl::RectT<unsigned long>::y1() const Line | Count | Source | 302 | 1.21M | T y1() const { return y0_ + ysize_; } |
jxl::RectT<long>::y1() const Line | Count | Source | 302 | 79.8k | T y1() const { return y0_ + ysize_; } |
|
303 | | |
304 | 192k | RectT<T> ShiftLeft(size_t shiftx, size_t shifty) const { |
305 | 192k | return RectT<T>(x0_ * (1 << shiftx), y0_ * (1 << shifty), xsize_ << shiftx, |
306 | 192k | ysize_ << shifty); |
307 | 192k | } jxl::RectT<long>::ShiftLeft(unsigned long, unsigned long) const Line | Count | Source | 304 | 156k | RectT<T> ShiftLeft(size_t shiftx, size_t shifty) const { | 305 | 156k | return RectT<T>(x0_ * (1 << shiftx), y0_ * (1 << shifty), xsize_ << shiftx, | 306 | 156k | ysize_ << shifty); | 307 | 156k | } |
jxl::RectT<unsigned long>::ShiftLeft(unsigned long, unsigned long) const Line | Count | Source | 304 | 35.7k | RectT<T> ShiftLeft(size_t shiftx, size_t shifty) const { | 305 | 35.7k | return RectT<T>(x0_ * (1 << shiftx), y0_ * (1 << shifty), xsize_ << shiftx, | 306 | 35.7k | ysize_ << shifty); | 307 | 35.7k | } |
|
308 | 192k | RectT<T> ShiftLeft(size_t shift) const { return ShiftLeft(shift, shift); } jxl::RectT<long>::ShiftLeft(unsigned long) const Line | Count | Source | 308 | 156k | RectT<T> ShiftLeft(size_t shift) const { return ShiftLeft(shift, shift); } |
jxl::RectT<unsigned long>::ShiftLeft(unsigned long) const Line | Count | Source | 308 | 35.7k | RectT<T> ShiftLeft(size_t shift) const { return ShiftLeft(shift, shift); } |
|
309 | | |
310 | | // Requires x0(), y0() to be multiples of 1<<shiftx, 1<<shifty. |
311 | 375k | RectT<T> CeilShiftRight(size_t shiftx, size_t shifty) const { |
312 | 375k | JXL_ASSERT(x0_ % (1 << shiftx) == 0); |
313 | 375k | JXL_ASSERT(y0_ % (1 << shifty) == 0); |
314 | 375k | return RectT<T>(x0_ / (1 << shiftx), y0_ / (1 << shifty), |
315 | 375k | DivCeil(xsize_, T{1} << shiftx), |
316 | 375k | DivCeil(ysize_, T{1} << shifty)); |
317 | 375k | } jxl::RectT<long>::CeilShiftRight(unsigned long, unsigned long) const Line | Count | Source | 311 | 156k | RectT<T> CeilShiftRight(size_t shiftx, size_t shifty) const { | 312 | 156k | JXL_ASSERT(x0_ % (1 << shiftx) == 0); | 313 | 156k | JXL_ASSERT(y0_ % (1 << shifty) == 0); | 314 | 156k | return RectT<T>(x0_ / (1 << shiftx), y0_ / (1 << shifty), | 315 | 156k | DivCeil(xsize_, T{1} << shiftx), | 316 | 156k | DivCeil(ysize_, T{1} << shifty)); | 317 | 156k | } |
jxl::RectT<unsigned long>::CeilShiftRight(unsigned long, unsigned long) const Line | Count | Source | 311 | 218k | RectT<T> CeilShiftRight(size_t shiftx, size_t shifty) const { | 312 | 218k | JXL_ASSERT(x0_ % (1 << shiftx) == 0); | 313 | 218k | JXL_ASSERT(y0_ % (1 << shifty) == 0); | 314 | 218k | return RectT<T>(x0_ / (1 << shiftx), y0_ / (1 << shifty), | 315 | 218k | DivCeil(xsize_, T{1} << shiftx), | 316 | 218k | DivCeil(ysize_, T{1} << shifty)); | 317 | 218k | } |
|
318 | 375k | RectT<T> CeilShiftRight(std::pair<size_t, size_t> shift) const { |
319 | 375k | return CeilShiftRight(shift.first, shift.second); |
320 | 375k | } jxl::RectT<long>::CeilShiftRight(std::__1::pair<unsigned long, unsigned long>) const Line | Count | Source | 318 | 156k | RectT<T> CeilShiftRight(std::pair<size_t, size_t> shift) const { | 319 | 156k | return CeilShiftRight(shift.first, shift.second); | 320 | 156k | } |
jxl::RectT<unsigned long>::CeilShiftRight(std::__1::pair<unsigned long, unsigned long>) const Line | Count | Source | 318 | 218k | RectT<T> CeilShiftRight(std::pair<size_t, size_t> shift) const { | 319 | 218k | return CeilShiftRight(shift.first, shift.second); | 320 | 218k | } |
|
321 | | RectT<T> CeilShiftRight(size_t shift) const { |
322 | | return CeilShiftRight(shift, shift); |
323 | | } |
324 | | |
325 | | template <typename U> |
326 | 156k | RectT<U> As() const { |
327 | 156k | return RectT<U>(U(x0_), U(y0_), U(xsize_), U(ysize_)); |
328 | 156k | } |
329 | | |
330 | | private: |
331 | | // Returns size_max, or whatever is left in [begin, end). |
332 | 1.77M | static constexpr size_t ClampedSize(T begin, size_t size_max, T end) { |
333 | 1.77M | return (static_cast<T>(begin + size_max) <= end) |
334 | 1.77M | ? size_max |
335 | 1.77M | : (end > begin ? end - begin : 0); |
336 | 1.77M | } jxl::RectT<unsigned long>::ClampedSize(unsigned long, unsigned long, unsigned long) Line | Count | Source | 332 | 1.71M | static constexpr size_t ClampedSize(T begin, size_t size_max, T end) { | 333 | 1.71M | return (static_cast<T>(begin + size_max) <= end) | 334 | 1.71M | ? size_max | 335 | 1.71M | : (end > begin ? end - begin : 0); | 336 | 1.71M | } |
jxl::RectT<long>::ClampedSize(long, unsigned long, long) Line | Count | Source | 332 | 68.3k | static constexpr size_t ClampedSize(T begin, size_t size_max, T end) { | 333 | 68.3k | return (static_cast<T>(begin + size_max) <= end) | 334 | 68.3k | ? size_max | 335 | 68.3k | : (end > begin ? end - begin : 0); | 336 | 68.3k | } |
|
337 | | |
338 | | T x0_; |
339 | | T y0_; |
340 | | |
341 | | size_t xsize_; |
342 | | size_t ysize_; |
343 | | }; |
344 | | |
345 | | template <typename T> |
346 | 0 | std::string Description(RectT<T> r) { |
347 | 0 | std::ostringstream os; |
348 | 0 | os << "[" << r.x0() << ".." << r.x1() << ")x" |
349 | 0 | << "[" << r.y0() << ".." << r.y1() << ")"; |
350 | 0 | return os.str(); |
351 | 0 | } Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > jxl::Description<unsigned long>(jxl::RectT<unsigned long>) Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > jxl::Description<long>(jxl::RectT<long>) |
352 | | |
353 | | using Rect = RectT<size_t>; |
354 | | |
355 | | // Currently, we abuse Image to either refer to an image that owns its storage |
356 | | // or one that doesn't. In similar vein, we abuse Image* function parameters to |
357 | | // either mean "assign to me" or "fill the provided image with data". |
358 | | // Hopefully, the "assign to me" meaning will go away and most images in the |
359 | | // codebase will not be backed by own storage. When this happens we can redesign |
360 | | // Image to be a non-storage-holding view class and introduce BackedImage in |
361 | | // those places that actually need it. |
362 | | |
363 | | // NOTE: we can't use Image as a view because invariants are violated |
364 | | // (alignment and the presence of padding before/after each "row"). |
365 | | |
366 | | // A bundle of 3 same-sized images. Typically constructed by moving from three |
367 | | // rvalue references to Image. To overwrite an existing Image3 using |
368 | | // single-channel producers, we also need access to Image*. Constructing |
369 | | // temporary non-owning Image pointing to one plane of an existing Image3 risks |
370 | | // dangling references, especially if the wrapper is moved. Therefore, we |
371 | | // store an array of Image (which are compact enough that size is not a concern) |
372 | | // and provide Plane+Row accessors. |
373 | | template <typename ComponentType> |
374 | | class Image3 { |
375 | | public: |
376 | | using T = ComponentType; |
377 | | using PlaneT = jxl::Plane<T>; |
378 | | static constexpr size_t kNumPlanes = 3; |
379 | | |
380 | 499k | Image3() : planes_{PlaneT(), PlaneT(), PlaneT()} {} jxl::Image3<float>::Image3() Line | Count | Source | 380 | 240k | Image3() : planes_{PlaneT(), PlaneT(), PlaneT()} {} |
jxl::Image3<int>::Image3() Line | Count | Source | 380 | 257k | Image3() : planes_{PlaneT(), PlaneT(), PlaneT()} {} |
jxl::Image3<short>::Image3() Line | Count | Source | 380 | 1.52k | Image3() : planes_{PlaneT(), PlaneT(), PlaneT()} {} |
|
381 | | |
382 | | Image3(const size_t xsize, const size_t ysize) |
383 | | : planes_{PlaneT(xsize, ysize), PlaneT(xsize, ysize), |
384 | 68.8k | PlaneT(xsize, ysize)} {} jxl::Image3<int>::Image3(unsigned long, unsigned long) Line | Count | Source | 384 | 13.8k | PlaneT(xsize, ysize)} {} |
jxl::Image3<float>::Image3(unsigned long, unsigned long) Line | Count | Source | 384 | 53.4k | PlaneT(xsize, ysize)} {} |
jxl::Image3<short>::Image3(unsigned long, unsigned long) Line | Count | Source | 384 | 1.52k | PlaneT(xsize, ysize)} {} |
Unexecuted instantiation: jxl::Image3<unsigned char>::Image3(unsigned long, unsigned long) |
385 | | |
386 | 92 | Image3(Image3&& other) noexcept { |
387 | 368 | for (size_t i = 0; i < kNumPlanes; i++) { |
388 | 276 | planes_[i] = std::move(other.planes_[i]); |
389 | 276 | } |
390 | 92 | } Unexecuted instantiation: jxl::Image3<int>::Image3(jxl::Image3<int>&&) jxl::Image3<float>::Image3(jxl::Image3<float>&&) Line | Count | Source | 386 | 92 | Image3(Image3&& other) noexcept { | 387 | 368 | for (size_t i = 0; i < kNumPlanes; i++) { | 388 | 276 | planes_[i] = std::move(other.planes_[i]); | 389 | 276 | } | 390 | 92 | } |
|
391 | | |
392 | 0 | Image3(PlaneT&& plane0, PlaneT&& plane1, PlaneT&& plane2) { |
393 | 0 | JXL_CHECK(SameSize(plane0, plane1)); |
394 | 0 | JXL_CHECK(SameSize(plane0, plane2)); |
395 | 0 | planes_[0] = std::move(plane0); |
396 | 0 | planes_[1] = std::move(plane1); |
397 | 0 | planes_[2] = std::move(plane2); |
398 | 0 | } |
399 | | |
400 | | // Copy construction/assignment is forbidden to avoid inadvertent copies, |
401 | | // which can be very expensive. Use CopyImageTo instead. |
402 | | Image3(const Image3& other) = delete; |
403 | | Image3& operator=(const Image3& other) = delete; |
404 | | |
405 | 173k | Image3& operator=(Image3&& other) noexcept { |
406 | 694k | for (size_t i = 0; i < kNumPlanes; i++) { |
407 | 520k | planes_[i] = std::move(other.planes_[i]); |
408 | 520k | } |
409 | 173k | return *this; |
410 | 173k | } jxl::Image3<int>::operator=(jxl::Image3<int>&&) Line | Count | Source | 405 | 13.8k | Image3& operator=(Image3&& other) noexcept { | 406 | 55.4k | for (size_t i = 0; i < kNumPlanes; i++) { | 407 | 41.5k | planes_[i] = std::move(other.planes_[i]); | 408 | 41.5k | } | 409 | 13.8k | return *this; | 410 | 13.8k | } |
jxl::Image3<float>::operator=(jxl::Image3<float>&&) Line | Count | Source | 405 | 158k | Image3& operator=(Image3&& other) noexcept { | 406 | 632k | for (size_t i = 0; i < kNumPlanes; i++) { | 407 | 474k | planes_[i] = std::move(other.planes_[i]); | 408 | 474k | } | 409 | 158k | return *this; | 410 | 158k | } |
jxl::Image3<short>::operator=(jxl::Image3<short>&&) Line | Count | Source | 405 | 1.52k | Image3& operator=(Image3&& other) noexcept { | 406 | 6.08k | for (size_t i = 0; i < kNumPlanes; i++) { | 407 | 4.56k | planes_[i] = std::move(other.planes_[i]); | 408 | 4.56k | } | 409 | 1.52k | return *this; | 410 | 1.52k | } |
|
411 | | |
412 | | // Returns row pointer; usage: PlaneRow(idx_plane, y)[x] = val. |
413 | 12.1M | JXL_INLINE T* PlaneRow(const size_t c, const size_t y) { |
414 | | // Custom implementation instead of calling planes_[c].Row ensures only a |
415 | | // single multiplication is needed for PlaneRow(0..2, y). |
416 | 12.1M | PlaneRowBoundsCheck(c, y); |
417 | 12.1M | const size_t row_offset = y * planes_[0].bytes_per_row(); |
418 | 12.1M | void* row = planes_[c].bytes() + row_offset; |
419 | 12.1M | return static_cast<T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); |
420 | 12.1M | } jxl::Image3<int>::PlaneRow(unsigned long, unsigned long) Line | Count | Source | 413 | 583k | JXL_INLINE T* PlaneRow(const size_t c, const size_t y) { | 414 | | // Custom implementation instead of calling planes_[c].Row ensures only a | 415 | | // single multiplication is needed for PlaneRow(0..2, y). | 416 | 583k | PlaneRowBoundsCheck(c, y); | 417 | 583k | const size_t row_offset = y * planes_[0].bytes_per_row(); | 418 | 583k | void* row = planes_[c].bytes() + row_offset; | 419 | 583k | return static_cast<T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); | 420 | 583k | } |
jxl::Image3<float>::PlaneRow(unsigned long, unsigned long) Line | Count | Source | 413 | 11.5M | JXL_INLINE T* PlaneRow(const size_t c, const size_t y) { | 414 | | // Custom implementation instead of calling planes_[c].Row ensures only a | 415 | | // single multiplication is needed for PlaneRow(0..2, y). | 416 | 11.5M | PlaneRowBoundsCheck(c, y); | 417 | 11.5M | const size_t row_offset = y * planes_[0].bytes_per_row(); | 418 | 11.5M | void* row = planes_[c].bytes() + row_offset; | 419 | 11.5M | return static_cast<T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); | 420 | 11.5M | } |
jxl::Image3<short>::PlaneRow(unsigned long, unsigned long) Line | Count | Source | 413 | 57 | JXL_INLINE T* PlaneRow(const size_t c, const size_t y) { | 414 | | // Custom implementation instead of calling planes_[c].Row ensures only a | 415 | | // single multiplication is needed for PlaneRow(0..2, y). | 416 | 57 | PlaneRowBoundsCheck(c, y); | 417 | 57 | const size_t row_offset = y * planes_[0].bytes_per_row(); | 418 | 57 | void* row = planes_[c].bytes() + row_offset; | 419 | 57 | return static_cast<T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); | 420 | 57 | } |
Unexecuted instantiation: jxl::Image3<unsigned char>::PlaneRow(unsigned long, unsigned long) |
421 | | |
422 | | // Returns const row pointer; usage: val = PlaneRow(idx_plane, y)[x]. |
423 | 1.69M | JXL_INLINE const T* PlaneRow(const size_t c, const size_t y) const { |
424 | 1.69M | PlaneRowBoundsCheck(c, y); |
425 | 1.69M | const size_t row_offset = y * planes_[0].bytes_per_row(); |
426 | 1.69M | const void* row = planes_[c].bytes() + row_offset; |
427 | 1.69M | return static_cast<const T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); |
428 | 1.69M | } jxl::Image3<int>::PlaneRow(unsigned long, unsigned long) const Line | Count | Source | 423 | 542k | JXL_INLINE const T* PlaneRow(const size_t c, const size_t y) const { | 424 | 542k | PlaneRowBoundsCheck(c, y); | 425 | 542k | const size_t row_offset = y * planes_[0].bytes_per_row(); | 426 | 542k | const void* row = planes_[c].bytes() + row_offset; | 427 | 542k | return static_cast<const T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); | 428 | 542k | } |
jxl::Image3<float>::PlaneRow(unsigned long, unsigned long) const Line | Count | Source | 423 | 1.15M | JXL_INLINE const T* PlaneRow(const size_t c, const size_t y) const { | 424 | 1.15M | PlaneRowBoundsCheck(c, y); | 425 | 1.15M | const size_t row_offset = y * planes_[0].bytes_per_row(); | 426 | 1.15M | const void* row = planes_[c].bytes() + row_offset; | 427 | 1.15M | return static_cast<const T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); | 428 | 1.15M | } |
Unexecuted instantiation: jxl::Image3<short>::PlaneRow(unsigned long, unsigned long) const |
429 | | |
430 | | // Returns const row pointer, even if called from a non-const Image3. |
431 | 1.68M | JXL_INLINE const T* ConstPlaneRow(const size_t c, const size_t y) const { |
432 | 1.68M | PlaneRowBoundsCheck(c, y); |
433 | 1.68M | return PlaneRow(c, y); |
434 | 1.68M | } jxl::Image3<float>::ConstPlaneRow(unsigned long, unsigned long) const Line | Count | Source | 431 | 1.14M | JXL_INLINE const T* ConstPlaneRow(const size_t c, const size_t y) const { | 432 | 1.14M | PlaneRowBoundsCheck(c, y); | 433 | 1.14M | return PlaneRow(c, y); | 434 | 1.14M | } |
jxl::Image3<int>::ConstPlaneRow(unsigned long, unsigned long) const Line | Count | Source | 431 | 542k | JXL_INLINE const T* ConstPlaneRow(const size_t c, const size_t y) const { | 432 | 542k | PlaneRowBoundsCheck(c, y); | 433 | 542k | return PlaneRow(c, y); | 434 | 542k | } |
|
435 | | |
436 | 108k | JXL_INLINE const PlaneT& Plane(size_t idx) const { return planes_[idx]; } jxl::Image3<float>::Plane(unsigned long) const Line | Count | Source | 436 | 108k | JXL_INLINE const PlaneT& Plane(size_t idx) const { return planes_[idx]; } |
Unexecuted instantiation: jxl::Image3<unsigned char>::Plane(unsigned long) const |
437 | | |
438 | 3.07k | JXL_INLINE PlaneT& Plane(size_t idx) { return planes_[idx]; } Unexecuted instantiation: jxl::Image3<int>::Plane(unsigned long) jxl::Image3<float>::Plane(unsigned long) Line | Count | Source | 438 | 3.07k | JXL_INLINE PlaneT& Plane(size_t idx) { return planes_[idx]; } |
Unexecuted instantiation: jxl::Image3<short>::Plane(unsigned long) |
439 | | |
440 | 1.59k | void Swap(Image3& other) { |
441 | 6.39k | for (size_t c = 0; c < 3; ++c) { |
442 | 4.79k | other.planes_[c].Swap(planes_[c]); |
443 | 4.79k | } |
444 | 1.59k | } |
445 | | |
446 | | // Useful for pre-allocating image with some padding for alignment purposes |
447 | | // and later reporting the actual valid dimensions. May also be used to |
448 | | // un-shrink the image. Caller is responsible for ensuring xsize/ysize are <= |
449 | | // the original dimensions. |
450 | 276 | void ShrinkTo(const size_t xsize, const size_t ysize) { |
451 | 828 | for (PlaneT& plane : planes_) { |
452 | 828 | plane.ShrinkTo(xsize, ysize); |
453 | 828 | } |
454 | 276 | } |
455 | | |
456 | | // Sizes of all three images are guaranteed to be equal. |
457 | 14.7M | JXL_INLINE size_t xsize() const { return planes_[0].xsize(); } jxl::Image3<int>::xsize() const Line | Count | Source | 457 | 14.8k | JXL_INLINE size_t xsize() const { return planes_[0].xsize(); } |
jxl::Image3<float>::xsize() const Line | Count | Source | 457 | 14.7M | JXL_INLINE size_t xsize() const { return planes_[0].xsize(); } |
jxl::Image3<short>::xsize() const Line | Count | Source | 457 | 12.2k | JXL_INLINE size_t xsize() const { return planes_[0].xsize(); } |
Unexecuted instantiation: jxl::Image3<unsigned char>::xsize() const |
458 | 1.41M | JXL_INLINE size_t ysize() const { return planes_[0].ysize(); } jxl::Image3<int>::ysize() const Line | Count | Source | 458 | 56 | JXL_INLINE size_t ysize() const { return planes_[0].ysize(); } |
jxl::Image3<float>::ysize() const Line | Count | Source | 458 | 1.41M | JXL_INLINE size_t ysize() const { return planes_[0].ysize(); } |
jxl::Image3<short>::ysize() const Line | Count | Source | 458 | 59 | JXL_INLINE size_t ysize() const { return planes_[0].ysize(); } |
Unexecuted instantiation: jxl::Image3<unsigned char>::ysize() const |
459 | | // Returns offset [bytes] from one row to the next row of the same plane. |
460 | | // WARNING: this must NOT be used to determine xsize, nor for copying rows - |
461 | | // the valid xsize may be much less. |
462 | | JXL_INLINE size_t bytes_per_row() const { return planes_[0].bytes_per_row(); } |
463 | | // Returns number of pixels (some of which are padding) per row. Useful for |
464 | | // computing other rows via pointer arithmetic. WARNING: this must NOT be used |
465 | | // to determine xsize. |
466 | 40.9k | JXL_INLINE intptr_t PixelsPerRow() const { return planes_[0].PixelsPerRow(); } jxl::Image3<int>::PixelsPerRow() const Line | Count | Source | 466 | 26.8k | JXL_INLINE intptr_t PixelsPerRow() const { return planes_[0].PixelsPerRow(); } |
Unexecuted instantiation: jxl::Image3<short>::PixelsPerRow() const jxl::Image3<float>::PixelsPerRow() const Line | Count | Source | 466 | 14.0k | JXL_INLINE intptr_t PixelsPerRow() const { return planes_[0].PixelsPerRow(); } |
|
467 | | |
468 | | private: |
469 | 15.5M | void PlaneRowBoundsCheck(const size_t c, const size_t y) const { |
470 | | #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \ |
471 | | defined(THREAD_SANITIZER) |
472 | | if (c >= kNumPlanes || y >= ysize()) { |
473 | | JXL_ABORT("PlaneRow(%" PRIu64 ", %" PRIu64 ") in (%" PRIu64 " x %" PRIu64 |
474 | | ") image\n", |
475 | | static_cast<uint64_t>(c), static_cast<uint64_t>(y), |
476 | | static_cast<uint64_t>(xsize()), static_cast<uint64_t>(ysize())); |
477 | | } |
478 | | #endif |
479 | 15.5M | } jxl::Image3<int>::PlaneRowBoundsCheck(unsigned long, unsigned long) const Line | Count | Source | 469 | 1.66M | void PlaneRowBoundsCheck(const size_t c, const size_t y) const { | 470 | | #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \ | 471 | | defined(THREAD_SANITIZER) | 472 | | if (c >= kNumPlanes || y >= ysize()) { | 473 | | JXL_ABORT("PlaneRow(%" PRIu64 ", %" PRIu64 ") in (%" PRIu64 " x %" PRIu64 | 474 | | ") image\n", | 475 | | static_cast<uint64_t>(c), static_cast<uint64_t>(y), | 476 | | static_cast<uint64_t>(xsize()), static_cast<uint64_t>(ysize())); | 477 | | } | 478 | | #endif | 479 | 1.66M | } |
jxl::Image3<float>::PlaneRowBoundsCheck(unsigned long, unsigned long) const Line | Count | Source | 469 | 13.8M | void PlaneRowBoundsCheck(const size_t c, const size_t y) const { | 470 | | #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \ | 471 | | defined(THREAD_SANITIZER) | 472 | | if (c >= kNumPlanes || y >= ysize()) { | 473 | | JXL_ABORT("PlaneRow(%" PRIu64 ", %" PRIu64 ") in (%" PRIu64 " x %" PRIu64 | 474 | | ") image\n", | 475 | | static_cast<uint64_t>(c), static_cast<uint64_t>(y), | 476 | | static_cast<uint64_t>(xsize()), static_cast<uint64_t>(ysize())); | 477 | | } | 478 | | #endif | 479 | 13.8M | } |
jxl::Image3<short>::PlaneRowBoundsCheck(unsigned long, unsigned long) const Line | Count | Source | 469 | 57 | void PlaneRowBoundsCheck(const size_t c, const size_t y) const { | 470 | | #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \ | 471 | | defined(THREAD_SANITIZER) | 472 | | if (c >= kNumPlanes || y >= ysize()) { | 473 | | JXL_ABORT("PlaneRow(%" PRIu64 ", %" PRIu64 ") in (%" PRIu64 " x %" PRIu64 | 474 | | ") image\n", | 475 | | static_cast<uint64_t>(c), static_cast<uint64_t>(y), | 476 | | static_cast<uint64_t>(xsize()), static_cast<uint64_t>(ysize())); | 477 | | } | 478 | | #endif | 479 | 57 | } |
Unexecuted instantiation: jxl::Image3<unsigned char>::PlaneRowBoundsCheck(unsigned long, unsigned long) const |
480 | | |
481 | | private: |
482 | | PlaneT planes_[kNumPlanes]; |
483 | | }; |
484 | | |
485 | | using Image3B = Image3<uint8_t>; |
486 | | using Image3S = Image3<int16_t>; |
487 | | using Image3U = Image3<uint16_t>; |
488 | | using Image3I = Image3<int32_t>; |
489 | | using Image3F = Image3<float>; |
490 | | using Image3D = Image3<double>; |
491 | | |
492 | | } // namespace jxl |
493 | | |
494 | | #endif // LIB_JXL_IMAGE_H_ |