/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 | | #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \ |
12 | | defined(THREAD_SANITIZER) |
13 | | #include <cinttypes> // PRIu64 |
14 | | #endif |
15 | | |
16 | | #include <jxl/memory_manager.h> |
17 | | |
18 | | #include <algorithm> |
19 | | #include <cstddef> |
20 | | #include <cstdint> |
21 | | #include <cstring> |
22 | | #include <utility> // std::move |
23 | | |
24 | | #include "lib/jxl/base/compiler_specific.h" |
25 | | #include "lib/jxl/base/status.h" |
26 | | #include "lib/jxl/memory_manager_internal.h" |
27 | | |
28 | | namespace jxl { |
29 | | |
30 | | // DO NOT use PlaneBase outside of image.{h|cc} |
31 | | namespace detail { |
32 | | |
33 | | // Type-independent parts of Plane<> - reduces code duplication and facilitates |
34 | | // moving member function implementations to cc file. |
35 | | struct PlaneBase { |
36 | | PlaneBase() |
37 | | : xsize_(0), |
38 | | ysize_(0), |
39 | | orig_xsize_(0), |
40 | | orig_ysize_(0), |
41 | | bytes_per_row_(0), |
42 | 36.8k | sizeof_t_(0) {} |
43 | | |
44 | | // Copy construction/assignment is forbidden to avoid inadvertent copies, |
45 | | // which can be very expensive. Use CopyImageTo() instead. |
46 | | PlaneBase(const PlaneBase& other) = delete; |
47 | | PlaneBase& operator=(const PlaneBase& other) = delete; |
48 | | |
49 | | // Move constructor (required for returning Image from function) |
50 | 19.5k | PlaneBase(PlaneBase&& other) noexcept = default; |
51 | | |
52 | | // Move assignment (required for std::vector) |
53 | 18.0k | PlaneBase& operator=(PlaneBase&& other) noexcept = default; |
54 | | |
55 | 64.7k | ~PlaneBase() {} |
56 | | |
57 | | void Swap(PlaneBase& other); |
58 | | |
59 | | // Useful for pre-allocating image with some padding for alignment purposes |
60 | | // and later reporting the actual valid dimensions. May also be used to |
61 | | // un-shrink the image. Caller is responsible for ensuring xsize/ysize are <= |
62 | | // the original dimensions. |
63 | 676 | void ShrinkTo(const size_t xsize, const size_t ysize) { |
64 | 676 | JXL_CHECK(xsize <= orig_xsize_); |
65 | 676 | JXL_CHECK(ysize <= orig_ysize_); |
66 | 676 | xsize_ = static_cast<uint32_t>(xsize); |
67 | 676 | ysize_ = static_cast<uint32_t>(ysize); |
68 | | // NOTE: we can't recompute bytes_per_row for more compact storage and |
69 | | // better locality because that would invalidate the image contents. |
70 | 676 | } |
71 | | |
72 | | // How many pixels. |
73 | 23.4k | JXL_INLINE size_t xsize() const { return xsize_; } |
74 | 22.5k | JXL_INLINE size_t ysize() const { return ysize_; } |
75 | | |
76 | | // NOTE: do not use this for copying rows - the valid xsize may be much less. |
77 | 9.67k | JXL_INLINE size_t bytes_per_row() const { return bytes_per_row_; } |
78 | | |
79 | 674 | JXL_INLINE JxlMemoryManager* memory_manager() const { |
80 | 674 | return bytes_.memory_manager(); |
81 | 674 | } |
82 | | |
83 | | // Raw access to byte contents, for interfacing with other libraries. |
84 | | // Unsigned char instead of char to avoid surprises (sign extension). |
85 | 4.52k | JXL_INLINE uint8_t* bytes() { |
86 | 4.52k | uint8_t* p = bytes_.address<uint8_t>(); |
87 | 4.52k | return static_cast<uint8_t * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(p, 64)); |
88 | 4.52k | } |
89 | 5.14k | JXL_INLINE const uint8_t* bytes() const { |
90 | 5.14k | const uint8_t* p = bytes_.address<uint8_t>(); |
91 | 5.14k | return static_cast<const uint8_t * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(p, 64)); |
92 | 5.14k | } |
93 | | |
94 | | protected: |
95 | | PlaneBase(size_t xsize, size_t ysize, size_t sizeof_t); |
96 | | Status Allocate(JxlMemoryManager* memory_manager); |
97 | | |
98 | | // Returns pointer to the start of a row. |
99 | 100k | JXL_INLINE void* VoidRow(const size_t y) const { |
100 | | #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \ |
101 | | defined(THREAD_SANITIZER) |
102 | | if (y >= ysize_) { |
103 | | JXL_ABORT("Row(%" PRIu64 ") in (%u x %u) image\n", |
104 | | static_cast<uint64_t>(y), xsize_, ysize_); |
105 | | } |
106 | | #endif |
107 | | |
108 | 100k | uint8_t* row = bytes_.address<uint8_t>() + y * bytes_per_row_; |
109 | 100k | return JXL_ASSUME_ALIGNED(row, 64); |
110 | 100k | } |
111 | | |
112 | | // (Members are non-const to enable assignment during move-assignment.) |
113 | | uint32_t xsize_; // In valid pixels, not including any padding. |
114 | | uint32_t ysize_; |
115 | | uint32_t orig_xsize_; |
116 | | uint32_t orig_ysize_; |
117 | | size_t bytes_per_row_; // Includes padding. |
118 | | AlignedMemory bytes_; |
119 | | size_t sizeof_t_; |
120 | | }; |
121 | | |
122 | | } // namespace detail |
123 | | |
124 | | // Single channel, aligned rows separated by padding. T must be POD. |
125 | | // |
126 | | // 'Single channel' (one 2D array per channel) simplifies vectorization |
127 | | // (repeating the same operation on multiple adjacent components) without the |
128 | | // complexity of a hybrid layout (8 R, 8 G, 8 B, ...). In particular, clients |
129 | | // can easily iterate over all components in a row and Image requires no |
130 | | // knowledge of the pixel format beyond the component type "T". |
131 | | // |
132 | | // 'Aligned' means each row is aligned to the L1 cache line size. This prevents |
133 | | // false sharing between two threads operating on adjacent rows. |
134 | | // |
135 | | // 'Padding' is still relevant because vectors could potentially be larger than |
136 | | // a cache line. By rounding up row sizes to the vector size, we allow |
137 | | // reading/writing ALIGNED vectors whose first lane is a valid sample. This |
138 | | // avoids needing a separate loop to handle remaining unaligned lanes. |
139 | | // |
140 | | // This image layout could also be achieved with a vector and a row accessor |
141 | | // function, but a class wrapper with support for "deleter" allows wrapping |
142 | | // existing memory allocated by clients without copying the pixels. It also |
143 | | // provides convenient accessors for xsize/ysize, which shortens function |
144 | | // argument lists. Supports move-construction so it can be stored in containers. |
145 | | template <typename ComponentType> |
146 | | class Plane : public detail::PlaneBase { |
147 | | public: |
148 | | using T = ComponentType; |
149 | | static constexpr size_t kNumPlanes = 1; |
150 | | |
151 | 36.8k | Plane() = default; jxl::Plane<float>::Plane() Line | Count | Source | 151 | 23.2k | Plane() = default; |
Line | Count | Source | 151 | 12.3k | Plane() = default; |
jxl::Plane<unsigned char>::Plane() Line | Count | Source | 151 | 676 | Plane() = default; |
jxl::Plane<signed char>::Plane() Line | Count | Source | 151 | 520 | Plane() = default; |
Unexecuted instantiation: jxl::Plane<hwy::float16_t>::Plane() Unexecuted instantiation: jxl::Plane<unsigned int>::Plane() Unexecuted instantiation: jxl::Plane<short>::Plane() |
152 | | |
153 | | static StatusOr<Plane> Create(JxlMemoryManager* memory_manager, |
154 | 8.36k | const size_t xsize, const size_t ysize) { |
155 | 8.36k | Plane plane(xsize, ysize, sizeof(T)); |
156 | 8.36k | JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager)); |
157 | 8.36k | return plane; |
158 | 8.36k | } jxl::Plane<float>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long) Line | Count | Source | 154 | 7.17k | const size_t xsize, const size_t ysize) { | 155 | 7.17k | Plane plane(xsize, ysize, sizeof(T)); | 156 | 7.17k | JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager)); | 157 | 7.17k | return plane; | 158 | 7.17k | } |
jxl::Plane<int>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long) Line | Count | Source | 154 | 884 | const size_t xsize, const size_t ysize) { | 155 | 884 | Plane plane(xsize, ysize, sizeof(T)); | 156 | 884 | JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager)); | 157 | 884 | return plane; | 158 | 884 | } |
jxl::Plane<unsigned char>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long) Line | Count | Source | 154 | 208 | const size_t xsize, const size_t ysize) { | 155 | 208 | Plane plane(xsize, ysize, sizeof(T)); | 156 | 208 | JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager)); | 157 | 208 | return plane; | 158 | 208 | } |
jxl::Plane<signed char>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long) Line | Count | Source | 154 | 104 | const size_t xsize, const size_t ysize) { | 155 | 104 | Plane plane(xsize, ysize, sizeof(T)); | 156 | 104 | JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager)); | 157 | 104 | return plane; | 158 | 104 | } |
Unexecuted instantiation: jxl::Plane<hwy::float16_t>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long) Unexecuted instantiation: jxl::Plane<unsigned int>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long) Unexecuted instantiation: jxl::Plane<short>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long) |
159 | | |
160 | 12.1k | JXL_INLINE T* Row(const size_t y) { return static_cast<T*>(VoidRow(y)); } jxl::Plane<float>::Row(unsigned long) Line | Count | Source | 160 | 10.5k | JXL_INLINE T* Row(const size_t y) { return static_cast<T*>(VoidRow(y)); } |
jxl::Plane<unsigned char>::Row(unsigned long) Line | Count | Source | 160 | 624 | JXL_INLINE T* Row(const size_t y) { return static_cast<T*>(VoidRow(y)); } |
jxl::Plane<int>::Row(unsigned long) Line | Count | Source | 160 | 624 | JXL_INLINE T* Row(const size_t y) { return static_cast<T*>(VoidRow(y)); } |
jxl::Plane<signed char>::Row(unsigned long) Line | Count | Source | 160 | 312 | JXL_INLINE T* Row(const size_t y) { return static_cast<T*>(VoidRow(y)); } |
Unexecuted instantiation: jxl::Plane<hwy::float16_t>::Row(unsigned long) Unexecuted instantiation: jxl::Plane<unsigned int>::Row(unsigned long) Unexecuted instantiation: jxl::Plane<short>::Row(unsigned long) |
161 | | |
162 | | // Returns pointer to const (see above). |
163 | 24.1k | JXL_INLINE const T* Row(const size_t y) const { |
164 | 24.1k | return static_cast<const T*>(VoidRow(y)); |
165 | 24.1k | } jxl::Plane<int>::Row(unsigned long) const Line | Count | Source | 163 | 623 | JXL_INLINE const T* Row(const size_t y) const { | 164 | 623 | return static_cast<const T*>(VoidRow(y)); | 165 | 623 | } |
jxl::Plane<float>::Row(unsigned long) const Line | Count | Source | 163 | 23.5k | JXL_INLINE const T* Row(const size_t y) const { | 164 | 23.5k | return static_cast<const T*>(VoidRow(y)); | 165 | 23.5k | } |
Unexecuted instantiation: jxl::Plane<unsigned char>::Row(unsigned long) const |
166 | | |
167 | | // Documents that the access is const. |
168 | 64.7k | JXL_INLINE const T* ConstRow(const size_t y) const { |
169 | 64.7k | return static_cast<const T*>(VoidRow(y)); |
170 | 64.7k | } jxl::Plane<float>::ConstRow(unsigned long) const Line | Count | Source | 168 | 62.8k | JXL_INLINE const T* ConstRow(const size_t y) const { | 169 | 62.8k | return static_cast<const T*>(VoidRow(y)); | 170 | 62.8k | } |
jxl::Plane<unsigned char>::ConstRow(unsigned long) const Line | Count | Source | 168 | 884 | JXL_INLINE const T* ConstRow(const size_t y) const { | 169 | 884 | return static_cast<const T*>(VoidRow(y)); | 170 | 884 | } |
jxl::Plane<int>::ConstRow(unsigned long) const Line | Count | Source | 168 | 416 | JXL_INLINE const T* ConstRow(const size_t y) const { | 169 | 416 | return static_cast<const T*>(VoidRow(y)); | 170 | 416 | } |
jxl::Plane<signed char>::ConstRow(unsigned long) const Line | Count | Source | 168 | 624 | JXL_INLINE const T* ConstRow(const size_t y) const { | 169 | 624 | return static_cast<const T*>(VoidRow(y)); | 170 | 624 | } |
|
171 | | |
172 | | // Returns number of pixels (some of which are padding) per row. Useful for |
173 | | // computing other rows via pointer arithmetic. WARNING: this must |
174 | | // NOT be used to determine xsize. |
175 | 3.53k | JXL_INLINE intptr_t PixelsPerRow() const { |
176 | 3.53k | return static_cast<intptr_t>(bytes_per_row_ / sizeof(T)); |
177 | 3.53k | } jxl::Plane<unsigned char>::PixelsPerRow() const Line | Count | Source | 175 | 260 | JXL_INLINE intptr_t PixelsPerRow() const { | 176 | 260 | return static_cast<intptr_t>(bytes_per_row_ / sizeof(T)); | 177 | 260 | } |
jxl::Plane<int>::PixelsPerRow() const Line | Count | Source | 175 | 571 | JXL_INLINE intptr_t PixelsPerRow() const { | 176 | 571 | return static_cast<intptr_t>(bytes_per_row_ / sizeof(T)); | 177 | 571 | } |
jxl::Plane<float>::PixelsPerRow() const Line | Count | Source | 175 | 2.70k | JXL_INLINE intptr_t PixelsPerRow() const { | 176 | 2.70k | return static_cast<intptr_t>(bytes_per_row_ / sizeof(T)); | 177 | 2.70k | } |
Unexecuted instantiation: jxl::Plane<short>::PixelsPerRow() const |
178 | | |
179 | | private: |
180 | | Plane(size_t xsize, size_t ysize, size_t sizeof_t) |
181 | 8.36k | : detail::PlaneBase(xsize, ysize, sizeof_t) {} jxl::Plane<float>::Plane(unsigned long, unsigned long, unsigned long) Line | Count | Source | 181 | 7.17k | : detail::PlaneBase(xsize, ysize, sizeof_t) {} |
jxl::Plane<int>::Plane(unsigned long, unsigned long, unsigned long) Line | Count | Source | 181 | 884 | : detail::PlaneBase(xsize, ysize, sizeof_t) {} |
jxl::Plane<unsigned char>::Plane(unsigned long, unsigned long, unsigned long) Line | Count | Source | 181 | 208 | : detail::PlaneBase(xsize, ysize, sizeof_t) {} |
jxl::Plane<signed char>::Plane(unsigned long, unsigned long, unsigned long) Line | Count | Source | 181 | 104 | : detail::PlaneBase(xsize, ysize, sizeof_t) {} |
Unexecuted instantiation: jxl::Plane<hwy::float16_t>::Plane(unsigned long, unsigned long, unsigned long) Unexecuted instantiation: jxl::Plane<unsigned int>::Plane(unsigned long, unsigned long, unsigned long) Unexecuted instantiation: jxl::Plane<short>::Plane(unsigned long, unsigned long, unsigned long) |
182 | | }; |
183 | | |
184 | | using ImageSB = Plane<int8_t>; |
185 | | using ImageB = Plane<uint8_t>; |
186 | | using ImageS = Plane<int16_t>; // signed integer or half-float |
187 | | using ImageU = Plane<uint16_t>; |
188 | | using ImageI = Plane<int32_t>; |
189 | | using ImageF = Plane<float>; |
190 | | using ImageD = Plane<double>; |
191 | | |
192 | | // Currently, we abuse Image to either refer to an image that owns its storage |
193 | | // or one that doesn't. In similar vein, we abuse Image* function parameters to |
194 | | // either mean "assign to me" or "fill the provided image with data". |
195 | | // Hopefully, the "assign to me" meaning will go away and most images in the |
196 | | // codebase will not be backed by own storage. When this happens we can redesign |
197 | | // Image to be a non-storage-holding view class and introduce BackedImage in |
198 | | // those places that actually need it. |
199 | | |
200 | | // NOTE: we can't use Image as a view because invariants are violated |
201 | | // (alignment and the presence of padding before/after each "row"). |
202 | | |
203 | | // A bundle of 3 same-sized images. Typically constructed by moving from three |
204 | | // rvalue references to Image. To overwrite an existing Image3 using |
205 | | // single-channel producers, we also need access to Image*. Constructing |
206 | | // temporary non-owning Image pointing to one plane of an existing Image3 risks |
207 | | // dangling references, especially if the wrapper is moved. Therefore, we |
208 | | // store an array of Image (which are compact enough that size is not a concern) |
209 | | // and provide Plane+Row accessors. |
210 | | template <typename ComponentType> |
211 | | class Image3 { |
212 | | public: |
213 | | using T = ComponentType; |
214 | | using PlaneT = jxl::Plane<T>; |
215 | | static constexpr size_t kNumPlanes = 3; |
216 | | |
217 | 6.55k | Image3() : planes_{PlaneT(), PlaneT(), PlaneT()} {} jxl::Image3<float>::Image3() Line | Count | Source | 217 | 2.80k | Image3() : planes_{PlaneT(), PlaneT(), PlaneT()} {} |
jxl::Image3<int>::Image3() Line | Count | Source | 217 | 3.74k | Image3() : planes_{PlaneT(), PlaneT(), PlaneT()} {} |
Unexecuted instantiation: jxl::Image3<short>::Image3() |
218 | | |
219 | | // Copy construction/assignment is forbidden to avoid inadvertent copies, |
220 | | // which can be very expensive. Use CopyImageTo instead. |
221 | | Image3(const Image3& other) = delete; |
222 | | Image3& operator=(const Image3& other) = delete; |
223 | | |
224 | 2.28k | Image3(Image3&& other) noexcept { |
225 | 9.15k | for (size_t i = 0; i < kNumPlanes; i++) { |
226 | 6.86k | planes_[i] = std::move(other.planes_[i]); |
227 | 6.86k | } |
228 | 2.28k | } jxl::Image3<float>::Image3(jxl::Image3<float>&&) Line | Count | Source | 224 | 2.08k | Image3(Image3&& other) noexcept { | 225 | 8.31k | for (size_t i = 0; i < kNumPlanes; i++) { | 226 | 6.23k | planes_[i] = std::move(other.planes_[i]); | 227 | 6.23k | } | 228 | 2.08k | } |
jxl::Image3<int>::Image3(jxl::Image3<int>&&) Line | Count | Source | 224 | 208 | Image3(Image3&& other) noexcept { | 225 | 832 | for (size_t i = 0; i < kNumPlanes; i++) { | 226 | 624 | planes_[i] = std::move(other.planes_[i]); | 227 | 624 | } | 228 | 208 | } |
Unexecuted instantiation: jxl::Image3<short>::Image3(jxl::Image3<short>&&) Unexecuted instantiation: jxl::Image3<unsigned char>::Image3(jxl::Image3<unsigned char>&&) |
229 | 1.04k | Image3& operator=(Image3&& other) noexcept { |
230 | 4.16k | for (size_t i = 0; i < kNumPlanes; i++) { |
231 | 3.12k | planes_[i] = std::move(other.planes_[i]); |
232 | 3.12k | } |
233 | 1.04k | return *this; |
234 | 1.04k | } jxl::Image3<float>::operator=(jxl::Image3<float>&&) Line | Count | Source | 229 | 936 | Image3& operator=(Image3&& other) noexcept { | 230 | 3.74k | for (size_t i = 0; i < kNumPlanes; i++) { | 231 | 2.80k | planes_[i] = std::move(other.planes_[i]); | 232 | 2.80k | } | 233 | 936 | return *this; | 234 | 936 | } |
jxl::Image3<int>::operator=(jxl::Image3<int>&&) Line | Count | Source | 229 | 104 | Image3& operator=(Image3&& other) noexcept { | 230 | 416 | for (size_t i = 0; i < kNumPlanes; i++) { | 231 | 312 | planes_[i] = std::move(other.planes_[i]); | 232 | 312 | } | 233 | 104 | return *this; | 234 | 104 | } |
Unexecuted instantiation: jxl::Image3<short>::operator=(jxl::Image3<short>&&) |
235 | | |
236 | | static StatusOr<Image3> Create(JxlMemoryManager* memory_manager, |
237 | 986 | const size_t xsize, const size_t ysize) { |
238 | 986 | StatusOr<PlaneT> plane0 = PlaneT::Create(memory_manager, xsize, ysize); |
239 | 986 | JXL_RETURN_IF_ERROR(plane0.status()); |
240 | 986 | StatusOr<PlaneT> plane1 = PlaneT::Create(memory_manager, xsize, ysize); |
241 | 986 | JXL_RETURN_IF_ERROR(plane1.status()); |
242 | 986 | StatusOr<PlaneT> plane2 = PlaneT::Create(memory_manager, xsize, ysize); |
243 | 986 | JXL_RETURN_IF_ERROR(plane2.status()); |
244 | 986 | return Image3(std::move(plane0).value(), std::move(plane1).value(), |
245 | 986 | std::move(plane2).value()); |
246 | 986 | } jxl::Image3<float>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long) Line | Count | Source | 237 | 882 | const size_t xsize, const size_t ysize) { | 238 | 882 | StatusOr<PlaneT> plane0 = PlaneT::Create(memory_manager, xsize, ysize); | 239 | 882 | JXL_RETURN_IF_ERROR(plane0.status()); | 240 | 882 | StatusOr<PlaneT> plane1 = PlaneT::Create(memory_manager, xsize, ysize); | 241 | 882 | JXL_RETURN_IF_ERROR(plane1.status()); | 242 | 882 | StatusOr<PlaneT> plane2 = PlaneT::Create(memory_manager, xsize, ysize); | 243 | 882 | JXL_RETURN_IF_ERROR(plane2.status()); | 244 | 882 | return Image3(std::move(plane0).value(), std::move(plane1).value(), | 245 | 882 | std::move(plane2).value()); | 246 | 882 | } |
jxl::Image3<int>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long) Line | Count | Source | 237 | 104 | const size_t xsize, const size_t ysize) { | 238 | 104 | StatusOr<PlaneT> plane0 = PlaneT::Create(memory_manager, xsize, ysize); | 239 | 104 | JXL_RETURN_IF_ERROR(plane0.status()); | 240 | 104 | StatusOr<PlaneT> plane1 = PlaneT::Create(memory_manager, xsize, ysize); | 241 | 104 | JXL_RETURN_IF_ERROR(plane1.status()); | 242 | 104 | StatusOr<PlaneT> plane2 = PlaneT::Create(memory_manager, xsize, ysize); | 243 | 104 | JXL_RETURN_IF_ERROR(plane2.status()); | 244 | 104 | return Image3(std::move(plane0).value(), std::move(plane1).value(), | 245 | 104 | std::move(plane2).value()); | 246 | 104 | } |
Unexecuted instantiation: jxl::Image3<short>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long) Unexecuted instantiation: jxl::Image3<unsigned char>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long) |
247 | | |
248 | | // Returns row pointer; usage: PlaneRow(idx_plane, y)[x] = val. |
249 | 4.52k | JXL_INLINE T* PlaneRow(const size_t c, const size_t y) { |
250 | | // Custom implementation instead of calling planes_[c].Row ensures only a |
251 | | // single multiplication is needed for PlaneRow(0..2, y). |
252 | 4.52k | PlaneRowBoundsCheck(c, y); |
253 | 4.52k | const size_t row_offset = y * planes_[0].bytes_per_row(); |
254 | 4.52k | void* row = planes_[c].bytes() + row_offset; |
255 | 4.52k | return static_cast<T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); |
256 | 4.52k | } jxl::Image3<int>::PlaneRow(unsigned long, unsigned long) Line | Count | Source | 249 | 936 | JXL_INLINE T* PlaneRow(const size_t c, const size_t y) { | 250 | | // Custom implementation instead of calling planes_[c].Row ensures only a | 251 | | // single multiplication is needed for PlaneRow(0..2, y). | 252 | 936 | PlaneRowBoundsCheck(c, y); | 253 | 936 | const size_t row_offset = y * planes_[0].bytes_per_row(); | 254 | 936 | void* row = planes_[c].bytes() + row_offset; | 255 | 936 | return static_cast<T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); | 256 | 936 | } |
jxl::Image3<float>::PlaneRow(unsigned long, unsigned long) Line | Count | Source | 249 | 3.58k | JXL_INLINE T* PlaneRow(const size_t c, const size_t y) { | 250 | | // Custom implementation instead of calling planes_[c].Row ensures only a | 251 | | // single multiplication is needed for PlaneRow(0..2, y). | 252 | 3.58k | PlaneRowBoundsCheck(c, y); | 253 | 3.58k | const size_t row_offset = y * planes_[0].bytes_per_row(); | 254 | 3.58k | void* row = planes_[c].bytes() + row_offset; | 255 | 3.58k | return static_cast<T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); | 256 | 3.58k | } |
Unexecuted instantiation: jxl::Image3<short>::PlaneRow(unsigned long, unsigned long) Unexecuted instantiation: jxl::Image3<unsigned char>::PlaneRow(unsigned long, unsigned long) |
257 | | |
258 | | // Returns const row pointer; usage: val = PlaneRow(idx_plane, y)[x]. |
259 | 5.14k | JXL_INLINE const T* PlaneRow(const size_t c, const size_t y) const { |
260 | 5.14k | PlaneRowBoundsCheck(c, y); |
261 | 5.14k | const size_t row_offset = y * planes_[0].bytes_per_row(); |
262 | 5.14k | const void* row = planes_[c].bytes() + row_offset; |
263 | 5.14k | return static_cast<const T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); |
264 | 5.14k | } Unexecuted instantiation: jxl::Image3<int>::PlaneRow(unsigned long, unsigned long) const jxl::Image3<float>::PlaneRow(unsigned long, unsigned long) const Line | Count | Source | 259 | 5.14k | JXL_INLINE const T* PlaneRow(const size_t c, const size_t y) const { | 260 | 5.14k | PlaneRowBoundsCheck(c, y); | 261 | 5.14k | const size_t row_offset = y * planes_[0].bytes_per_row(); | 262 | 5.14k | const void* row = planes_[c].bytes() + row_offset; | 263 | 5.14k | return static_cast<const T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); | 264 | 5.14k | } |
Unexecuted instantiation: jxl::Image3<short>::PlaneRow(unsigned long, unsigned long) const Unexecuted instantiation: jxl::Image3<unsigned char>::PlaneRow(unsigned long, unsigned long) const |
265 | | |
266 | | // Returns const row pointer, even if called from a non-const Image3. |
267 | 5.14k | JXL_INLINE const T* ConstPlaneRow(const size_t c, const size_t y) const { |
268 | 5.14k | PlaneRowBoundsCheck(c, y); |
269 | 5.14k | return PlaneRow(c, y); |
270 | 5.14k | } jxl::Image3<float>::ConstPlaneRow(unsigned long, unsigned long) const Line | Count | Source | 267 | 5.14k | JXL_INLINE const T* ConstPlaneRow(const size_t c, const size_t y) const { | 268 | 5.14k | PlaneRowBoundsCheck(c, y); | 269 | 5.14k | return PlaneRow(c, y); | 270 | 5.14k | } |
Unexecuted instantiation: jxl::Image3<int>::ConstPlaneRow(unsigned long, unsigned long) const Unexecuted instantiation: jxl::Image3<unsigned char>::ConstPlaneRow(unsigned long, unsigned long) const |
271 | | |
272 | 1.40k | JXL_INLINE const PlaneT& Plane(size_t idx) const { return planes_[idx]; } |
273 | | |
274 | 2.02k | JXL_INLINE PlaneT& Plane(size_t idx) { return planes_[idx]; } jxl::Image3<float>::Plane(unsigned long) Line | Count | Source | 274 | 2.02k | JXL_INLINE PlaneT& Plane(size_t idx) { return planes_[idx]; } |
Unexecuted instantiation: jxl::Image3<int>::Plane(unsigned long) Unexecuted instantiation: jxl::Image3<short>::Plane(unsigned long) |
275 | | |
276 | 0 | void Swap(Image3& other) { |
277 | 0 | for (size_t c = 0; c < 3; ++c) { |
278 | 0 | other.planes_[c].Swap(planes_[c]); |
279 | 0 | } |
280 | 0 | } |
281 | | |
282 | | // Useful for pre-allocating image with some padding for alignment purposes |
283 | | // and later reporting the actual valid dimensions. May also be used to |
284 | | // un-shrink the image. Caller is responsible for ensuring xsize/ysize are <= |
285 | | // the original dimensions. |
286 | 208 | void ShrinkTo(const size_t xsize, const size_t ysize) { |
287 | 624 | for (PlaneT& plane : planes_) { |
288 | 624 | plane.ShrinkTo(xsize, ysize); |
289 | 624 | } |
290 | 208 | } |
291 | | |
292 | | // Sizes of all three images are guaranteed to be equal. |
293 | 312 | JXL_INLINE JxlMemoryManager* memory_manager() const { |
294 | 312 | return planes_[0].memory_manager(); |
295 | 312 | } jxl::Image3<float>::memory_manager() const Line | Count | Source | 293 | 312 | JXL_INLINE JxlMemoryManager* memory_manager() const { | 294 | 312 | return planes_[0].memory_manager(); | 295 | 312 | } |
Unexecuted instantiation: jxl::Image3<unsigned char>::memory_manager() const |
296 | 2.60k | JXL_INLINE size_t xsize() const { return planes_[0].xsize(); } jxl::Image3<float>::xsize() const Line | Count | Source | 296 | 2.39k | JXL_INLINE size_t xsize() const { return planes_[0].xsize(); } |
jxl::Image3<int>::xsize() const Line | Count | Source | 296 | 208 | JXL_INLINE size_t xsize() const { return planes_[0].xsize(); } |
Unexecuted instantiation: jxl::Image3<short>::xsize() const Unexecuted instantiation: jxl::Image3<unsigned char>::xsize() const |
297 | 2.23k | JXL_INLINE size_t ysize() const { return planes_[0].ysize(); } jxl::Image3<float>::ysize() const Line | Count | Source | 297 | 2.23k | JXL_INLINE size_t ysize() const { return planes_[0].ysize(); } |
Unexecuted instantiation: jxl::Image3<int>::ysize() const Unexecuted instantiation: jxl::Image3<short>::ysize() const Unexecuted instantiation: jxl::Image3<unsigned char>::ysize() const |
298 | | // Returns offset [bytes] from one row to the next row of the same plane. |
299 | | // WARNING: this must NOT be used to determine xsize, nor for copying rows - |
300 | | // the valid xsize may be much less. |
301 | | JXL_INLINE size_t bytes_per_row() const { return planes_[0].bytes_per_row(); } |
302 | | // Returns number of pixels (some of which are padding) per row. Useful for |
303 | | // computing other rows via pointer arithmetic. WARNING: this must NOT be used |
304 | | // to determine xsize. |
305 | 520 | JXL_INLINE intptr_t PixelsPerRow() const { return planes_[0].PixelsPerRow(); } jxl::Image3<int>::PixelsPerRow() const Line | Count | Source | 305 | 52 | JXL_INLINE intptr_t PixelsPerRow() const { return planes_[0].PixelsPerRow(); } |
jxl::Image3<float>::PixelsPerRow() const Line | Count | Source | 305 | 468 | JXL_INLINE intptr_t PixelsPerRow() const { return planes_[0].PixelsPerRow(); } |
Unexecuted instantiation: jxl::Image3<short>::PixelsPerRow() const |
306 | | |
307 | | private: |
308 | 988 | Image3(PlaneT&& plane0, PlaneT&& plane1, PlaneT&& plane2) { |
309 | 988 | planes_[0] = std::move(plane0); |
310 | 988 | planes_[1] = std::move(plane1); |
311 | 988 | planes_[2] = std::move(plane2); |
312 | 988 | } jxl::Image3<float>::Image3(jxl::Plane<float>&&, jxl::Plane<float>&&, jxl::Plane<float>&&) Line | Count | Source | 308 | 884 | Image3(PlaneT&& plane0, PlaneT&& plane1, PlaneT&& plane2) { | 309 | 884 | planes_[0] = std::move(plane0); | 310 | 884 | planes_[1] = std::move(plane1); | 311 | 884 | planes_[2] = std::move(plane2); | 312 | 884 | } |
jxl::Image3<int>::Image3(jxl::Plane<int>&&, jxl::Plane<int>&&, jxl::Plane<int>&&) Line | Count | Source | 308 | 104 | Image3(PlaneT&& plane0, PlaneT&& plane1, PlaneT&& plane2) { | 309 | 104 | planes_[0] = std::move(plane0); | 310 | 104 | planes_[1] = std::move(plane1); | 311 | 104 | planes_[2] = std::move(plane2); | 312 | 104 | } |
Unexecuted instantiation: jxl::Image3<short>::Image3(jxl::Plane<short>&&, jxl::Plane<short>&&, jxl::Plane<short>&&) Unexecuted instantiation: jxl::Image3<unsigned char>::Image3(jxl::Plane<unsigned char>&&, jxl::Plane<unsigned char>&&, jxl::Plane<unsigned char>&&) |
313 | | |
314 | 14.8k | void PlaneRowBoundsCheck(const size_t c, const size_t y) const { |
315 | | #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \ |
316 | | defined(THREAD_SANITIZER) |
317 | | if (c >= kNumPlanes || y >= ysize()) { |
318 | | JXL_ABORT("PlaneRow(%" PRIu64 ", %" PRIu64 ") in (%" PRIu64 " x %" PRIu64 |
319 | | ") image\n", |
320 | | static_cast<uint64_t>(c), static_cast<uint64_t>(y), |
321 | | static_cast<uint64_t>(xsize()), static_cast<uint64_t>(ysize())); |
322 | | } |
323 | | #endif |
324 | 14.8k | } jxl::Image3<int>::PlaneRowBoundsCheck(unsigned long, unsigned long) const Line | Count | Source | 314 | 936 | void PlaneRowBoundsCheck(const size_t c, const size_t y) const { | 315 | | #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \ | 316 | | defined(THREAD_SANITIZER) | 317 | | if (c >= kNumPlanes || y >= ysize()) { | 318 | | JXL_ABORT("PlaneRow(%" PRIu64 ", %" PRIu64 ") in (%" PRIu64 " x %" PRIu64 | 319 | | ") image\n", | 320 | | static_cast<uint64_t>(c), static_cast<uint64_t>(y), | 321 | | static_cast<uint64_t>(xsize()), static_cast<uint64_t>(ysize())); | 322 | | } | 323 | | #endif | 324 | 936 | } |
jxl::Image3<float>::PlaneRowBoundsCheck(unsigned long, unsigned long) const Line | Count | Source | 314 | 13.8k | void PlaneRowBoundsCheck(const size_t c, const size_t y) const { | 315 | | #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \ | 316 | | defined(THREAD_SANITIZER) | 317 | | if (c >= kNumPlanes || y >= ysize()) { | 318 | | JXL_ABORT("PlaneRow(%" PRIu64 ", %" PRIu64 ") in (%" PRIu64 " x %" PRIu64 | 319 | | ") image\n", | 320 | | static_cast<uint64_t>(c), static_cast<uint64_t>(y), | 321 | | static_cast<uint64_t>(xsize()), static_cast<uint64_t>(ysize())); | 322 | | } | 323 | | #endif | 324 | 13.8k | } |
Unexecuted instantiation: jxl::Image3<short>::PlaneRowBoundsCheck(unsigned long, unsigned long) const Unexecuted instantiation: jxl::Image3<unsigned char>::PlaneRowBoundsCheck(unsigned long, unsigned long) const |
325 | | |
326 | | PlaneT planes_[kNumPlanes]; |
327 | | }; |
328 | | |
329 | | using Image3B = Image3<uint8_t>; |
330 | | using Image3S = Image3<int16_t>; |
331 | | using Image3U = Image3<uint16_t>; |
332 | | using Image3I = Image3<int32_t>; |
333 | | using Image3F = Image3<float>; |
334 | | using Image3D = Image3<double>; |
335 | | |
336 | | } // namespace jxl |
337 | | |
338 | | #endif // LIB_JXL_IMAGE_H_ |