/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 | 4.46M | 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 | 10.2M | PlaneBase(PlaneBase&& other) noexcept = default; |
51 | | |
52 | | // Move assignment (required for std::vector) |
53 | 16.9M | PlaneBase& operator=(PlaneBase&& other) noexcept = default; |
54 | | |
55 | 17.7M | ~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 | 0 | void ShrinkTo(const size_t xsize, const size_t ysize) { |
64 | 0 | JXL_CHECK(xsize <= orig_xsize_); |
65 | 0 | JXL_CHECK(ysize <= orig_ysize_); |
66 | 0 | xsize_ = static_cast<uint32_t>(xsize); |
67 | 0 | 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 | 0 | } |
71 | | |
72 | | // How many pixels. |
73 | 85.9M | JXL_INLINE size_t xsize() const { return xsize_; } |
74 | 10.0M | 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 | 14.3M | JXL_INLINE size_t bytes_per_row() const { return bytes_per_row_; } |
78 | | |
79 | 288k | JXL_INLINE JxlMemoryManager* memory_manager() const { |
80 | 288k | return bytes_.memory_manager(); |
81 | 288k | } |
82 | | |
83 | | // Raw access to byte contents, for interfacing with other libraries. |
84 | | // Unsigned char instead of char to avoid surprises (sign extension). |
85 | 11.8M | JXL_INLINE uint8_t* bytes() { |
86 | 11.8M | uint8_t* p = bytes_.address<uint8_t>(); |
87 | 11.8M | return static_cast<uint8_t * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(p, 64)); |
88 | 11.8M | } |
89 | 2.48M | JXL_INLINE const uint8_t* bytes() const { |
90 | 2.48M | const uint8_t* p = bytes_.address<uint8_t>(); |
91 | 2.48M | return static_cast<const uint8_t * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(p, 64)); |
92 | 2.48M | } |
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 | 177M | 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 | 177M | uint8_t* row = bytes_.address<uint8_t>() + y * bytes_per_row_; |
109 | 177M | return JXL_ASSUME_ALIGNED(row, 64); |
110 | 177M | } |
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 | 4.46M | Plane() = default; jxl::Plane<float>::Plane() Line | Count | Source | 151 | 3.02M | Plane() = default; |
Line | Count | Source | 151 | 1.24M | Plane() = default; |
jxl::Plane<unsigned char>::Plane() Line | Count | Source | 151 | 77.1k | Plane() = default; |
jxl::Plane<signed char>::Plane() Line | Count | Source | 151 | 101k | Plane() = default; |
jxl::Plane<short>::Plane() Line | Count | Source | 151 | 16.7k | Plane() = default; |
|
152 | | |
153 | | static StatusOr<Plane> Create(JxlMemoryManager* memory_manager, |
154 | 3.02M | const size_t xsize, const size_t ysize) { |
155 | 3.02M | Plane plane(xsize, ysize, sizeof(T)); |
156 | 3.02M | JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager)); |
157 | 3.02M | return plane; |
158 | 3.02M | } jxl::Plane<float>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long) Line | Count | Source | 154 | 1.62M | const size_t xsize, const size_t ysize) { | 155 | 1.62M | Plane plane(xsize, ysize, sizeof(T)); | 156 | 1.62M | JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager)); | 157 | 1.62M | return plane; | 158 | 1.62M | } |
jxl::Plane<int>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long) Line | Count | Source | 154 | 1.20M | const size_t xsize, const size_t ysize) { | 155 | 1.20M | Plane plane(xsize, ysize, sizeof(T)); | 156 | 1.20M | JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager)); | 157 | 1.20M | return plane; | 158 | 1.20M | } |
jxl::Plane<short>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long) Line | Count | Source | 154 | 4.18k | const size_t xsize, const size_t ysize) { | 155 | 4.18k | Plane plane(xsize, ysize, sizeof(T)); | 156 | 4.18k | JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager)); | 157 | 4.18k | return plane; | 158 | 4.18k | } |
jxl::Plane<unsigned char>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long) Line | Count | Source | 154 | 113k | const size_t xsize, const size_t ysize) { | 155 | 113k | Plane plane(xsize, ysize, sizeof(T)); | 156 | 113k | JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager)); | 157 | 113k | return plane; | 158 | 113k | } |
jxl::Plane<signed char>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long) Line | Count | Source | 154 | 75.8k | const size_t xsize, const size_t ysize) { | 155 | 75.8k | Plane plane(xsize, ysize, sizeof(T)); | 156 | 75.8k | JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager)); | 157 | 75.8k | return plane; | 158 | 75.8k | } |
|
159 | | |
160 | 142M | JXL_INLINE T* Row(const size_t y) { return static_cast<T*>(VoidRow(y)); } jxl::Plane<float>::Row(unsigned long) Line | Count | Source | 160 | 81.7M | 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 | 769k | JXL_INLINE T* Row(const size_t y) { return static_cast<T*>(VoidRow(y)); } |
jxl::Plane<int>::Row(unsigned long) Line | Count | Source | 160 | 59.5M | 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 | 160 | 323k | JXL_INLINE T* Row(const size_t y) { return static_cast<T*>(VoidRow(y)); } |
|
161 | | |
162 | | // Returns pointer to const (see above). |
163 | 30.3M | JXL_INLINE const T* Row(const size_t y) const { |
164 | 30.3M | return static_cast<const T*>(VoidRow(y)); |
165 | 30.3M | } jxl::Plane<int>::Row(unsigned long) const Line | Count | Source | 163 | 25.6M | JXL_INLINE const T* Row(const size_t y) const { | 164 | 25.6M | return static_cast<const T*>(VoidRow(y)); | 165 | 25.6M | } |
jxl::Plane<float>::Row(unsigned long) const Line | Count | Source | 163 | 4.67M | JXL_INLINE const T* Row(const size_t y) const { | 164 | 4.67M | return static_cast<const T*>(VoidRow(y)); | 165 | 4.67M | } |
|
166 | | |
167 | | // Documents that the access is const. |
168 | 5.90M | JXL_INLINE const T* ConstRow(const size_t y) const { |
169 | 5.90M | return static_cast<const T*>(VoidRow(y)); |
170 | 5.90M | } jxl::Plane<float>::ConstRow(unsigned long) const Line | Count | Source | 168 | 3.66M | JXL_INLINE const T* ConstRow(const size_t y) const { | 169 | 3.66M | return static_cast<const T*>(VoidRow(y)); | 170 | 3.66M | } |
jxl::Plane<unsigned char>::ConstRow(unsigned long) const Line | Count | Source | 168 | 1.06M | JXL_INLINE const T* ConstRow(const size_t y) const { | 169 | 1.06M | return static_cast<const T*>(VoidRow(y)); | 170 | 1.06M | } |
jxl::Plane<int>::ConstRow(unsigned long) const Line | Count | Source | 168 | 844k | JXL_INLINE const T* ConstRow(const size_t y) const { | 169 | 844k | return static_cast<const T*>(VoidRow(y)); | 170 | 844k | } |
jxl::Plane<signed char>::ConstRow(unsigned long) const Line | Count | Source | 168 | 326k | JXL_INLINE const T* ConstRow(const size_t y) const { | 169 | 326k | return static_cast<const T*>(VoidRow(y)); | 170 | 326k | } |
|
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.96M | JXL_INLINE intptr_t PixelsPerRow() const { |
176 | 3.96M | return static_cast<intptr_t>(bytes_per_row_ / sizeof(T)); |
177 | 3.96M | } jxl::Plane<unsigned char>::PixelsPerRow() const Line | Count | Source | 175 | 40.5k | JXL_INLINE intptr_t PixelsPerRow() const { | 176 | 40.5k | return static_cast<intptr_t>(bytes_per_row_ / sizeof(T)); | 177 | 40.5k | } |
jxl::Plane<int>::PixelsPerRow() const Line | Count | Source | 175 | 3.44M | JXL_INLINE intptr_t PixelsPerRow() const { | 176 | 3.44M | return static_cast<intptr_t>(bytes_per_row_ / sizeof(T)); | 177 | 3.44M | } |
Unexecuted instantiation: jxl::Plane<short>::PixelsPerRow() const jxl::Plane<float>::PixelsPerRow() const Line | Count | Source | 175 | 475k | JXL_INLINE intptr_t PixelsPerRow() const { | 176 | 475k | return static_cast<intptr_t>(bytes_per_row_ / sizeof(T)); | 177 | 475k | } |
|
178 | | |
179 | | private: |
180 | | Plane(size_t xsize, size_t ysize, size_t sizeof_t) |
181 | 3.02M | : detail::PlaneBase(xsize, ysize, sizeof_t) {} jxl::Plane<int>::Plane(unsigned long, unsigned long, unsigned long) Line | Count | Source | 181 | 1.20M | : detail::PlaneBase(xsize, ysize, sizeof_t) {} |
jxl::Plane<float>::Plane(unsigned long, unsigned long, unsigned long) Line | Count | Source | 181 | 1.62M | : detail::PlaneBase(xsize, ysize, sizeof_t) {} |
jxl::Plane<short>::Plane(unsigned long, unsigned long, unsigned long) Line | Count | Source | 181 | 4.18k | : detail::PlaneBase(xsize, ysize, sizeof_t) {} |
jxl::Plane<unsigned char>::Plane(unsigned long, unsigned long, unsigned long) Line | Count | Source | 181 | 113k | : detail::PlaneBase(xsize, ysize, sizeof_t) {} |
jxl::Plane<signed char>::Plane(unsigned long, unsigned long, unsigned long) Line | Count | Source | 181 | 75.8k | : detail::PlaneBase(xsize, ysize, sizeof_t) {} |
|
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 | 676k | Image3() : planes_{PlaneT(), PlaneT(), PlaneT()} {} jxl::Image3<float>::Image3() Line | Count | Source | 217 | 279k | Image3() : planes_{PlaneT(), PlaneT(), PlaneT()} {} |
jxl::Image3<int>::Image3() Line | Count | Source | 217 | 396k | Image3() : planes_{PlaneT(), PlaneT(), PlaneT()} {} |
jxl::Image3<short>::Image3() Line | Count | Source | 217 | 1.39k | Image3() : planes_{PlaneT(), PlaneT(), PlaneT()} {} |
|
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 | 154k | Image3(Image3&& other) noexcept { |
225 | 617k | for (size_t i = 0; i < kNumPlanes; i++) { |
226 | 463k | planes_[i] = std::move(other.planes_[i]); |
227 | 463k | } |
228 | 154k | } jxl::Image3<int>::Image3(jxl::Image3<int>&&) Line | Count | Source | 224 | 8.92k | Image3(Image3&& other) noexcept { | 225 | 35.6k | for (size_t i = 0; i < kNumPlanes; i++) { | 226 | 26.7k | planes_[i] = std::move(other.planes_[i]); | 227 | 26.7k | } | 228 | 8.92k | } |
jxl::Image3<short>::Image3(jxl::Image3<short>&&) Line | Count | Source | 224 | 2.79k | Image3(Image3&& other) noexcept { | 225 | 11.1k | for (size_t i = 0; i < kNumPlanes; i++) { | 226 | 8.37k | planes_[i] = std::move(other.planes_[i]); | 227 | 8.37k | } | 228 | 2.79k | } |
jxl::Image3<float>::Image3(jxl::Image3<float>&&) Line | Count | Source | 224 | 142k | Image3(Image3&& other) noexcept { | 225 | 570k | for (size_t i = 0; i < kNumPlanes; i++) { | 226 | 428k | planes_[i] = std::move(other.planes_[i]); | 227 | 428k | } | 228 | 142k | } |
|
229 | 204k | Image3& operator=(Image3&& other) noexcept { |
230 | 817k | for (size_t i = 0; i < kNumPlanes; i++) { |
231 | 613k | planes_[i] = std::move(other.planes_[i]); |
232 | 613k | } |
233 | 204k | return *this; |
234 | 204k | } jxl::Image3<float>::operator=(jxl::Image3<float>&&) Line | Count | Source | 229 | 198k | Image3& operator=(Image3&& other) noexcept { | 230 | 794k | for (size_t i = 0; i < kNumPlanes; i++) { | 231 | 595k | planes_[i] = std::move(other.planes_[i]); | 232 | 595k | } | 233 | 198k | return *this; | 234 | 198k | } |
jxl::Image3<int>::operator=(jxl::Image3<int>&&) Line | Count | Source | 229 | 4.46k | Image3& operator=(Image3&& other) noexcept { | 230 | 17.8k | for (size_t i = 0; i < kNumPlanes; i++) { | 231 | 13.3k | planes_[i] = std::move(other.planes_[i]); | 232 | 13.3k | } | 233 | 4.46k | return *this; | 234 | 4.46k | } |
jxl::Image3<short>::operator=(jxl::Image3<short>&&) Line | Count | Source | 229 | 1.39k | Image3& operator=(Image3&& other) noexcept { | 230 | 5.58k | for (size_t i = 0; i < kNumPlanes; i++) { | 231 | 4.18k | planes_[i] = std::move(other.planes_[i]); | 232 | 4.18k | } | 233 | 1.39k | return *this; | 234 | 1.39k | } |
|
235 | | |
236 | | static StatusOr<Image3> Create(JxlMemoryManager* memory_manager, |
237 | 77.2k | const size_t xsize, const size_t ysize) { |
238 | 77.2k | StatusOr<PlaneT> plane0 = PlaneT::Create(memory_manager, xsize, ysize); |
239 | 77.2k | JXL_RETURN_IF_ERROR(plane0.status()); |
240 | 77.2k | StatusOr<PlaneT> plane1 = PlaneT::Create(memory_manager, xsize, ysize); |
241 | 77.2k | JXL_RETURN_IF_ERROR(plane1.status()); |
242 | 77.2k | StatusOr<PlaneT> plane2 = PlaneT::Create(memory_manager, xsize, ysize); |
243 | 77.2k | JXL_RETURN_IF_ERROR(plane2.status()); |
244 | 77.2k | return Image3(std::move(plane0).value(), std::move(plane1).value(), |
245 | 77.2k | std::move(plane2).value()); |
246 | 77.2k | } jxl::Image3<float>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long) Line | Count | Source | 237 | 71.3k | const size_t xsize, const size_t ysize) { | 238 | 71.3k | StatusOr<PlaneT> plane0 = PlaneT::Create(memory_manager, xsize, ysize); | 239 | 71.3k | JXL_RETURN_IF_ERROR(plane0.status()); | 240 | 71.3k | StatusOr<PlaneT> plane1 = PlaneT::Create(memory_manager, xsize, ysize); | 241 | 71.3k | JXL_RETURN_IF_ERROR(plane1.status()); | 242 | 71.3k | StatusOr<PlaneT> plane2 = PlaneT::Create(memory_manager, xsize, ysize); | 243 | 71.3k | JXL_RETURN_IF_ERROR(plane2.status()); | 244 | 71.3k | return Image3(std::move(plane0).value(), std::move(plane1).value(), | 245 | 71.3k | std::move(plane2).value()); | 246 | 71.3k | } |
jxl::Image3<int>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long) Line | Count | Source | 237 | 4.45k | const size_t xsize, const size_t ysize) { | 238 | 4.45k | StatusOr<PlaneT> plane0 = PlaneT::Create(memory_manager, xsize, ysize); | 239 | 4.45k | JXL_RETURN_IF_ERROR(plane0.status()); | 240 | 4.45k | StatusOr<PlaneT> plane1 = PlaneT::Create(memory_manager, xsize, ysize); | 241 | 4.45k | JXL_RETURN_IF_ERROR(plane1.status()); | 242 | 4.45k | StatusOr<PlaneT> plane2 = PlaneT::Create(memory_manager, xsize, ysize); | 243 | 4.45k | JXL_RETURN_IF_ERROR(plane2.status()); | 244 | 4.45k | return Image3(std::move(plane0).value(), std::move(plane1).value(), | 245 | 4.45k | std::move(plane2).value()); | 246 | 4.45k | } |
jxl::Image3<short>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long) Line | Count | Source | 237 | 1.39k | const size_t xsize, const size_t ysize) { | 238 | 1.39k | StatusOr<PlaneT> plane0 = PlaneT::Create(memory_manager, xsize, ysize); | 239 | 1.39k | JXL_RETURN_IF_ERROR(plane0.status()); | 240 | 1.39k | StatusOr<PlaneT> plane1 = PlaneT::Create(memory_manager, xsize, ysize); | 241 | 1.39k | JXL_RETURN_IF_ERROR(plane1.status()); | 242 | 1.39k | StatusOr<PlaneT> plane2 = PlaneT::Create(memory_manager, xsize, ysize); | 243 | 1.39k | JXL_RETURN_IF_ERROR(plane2.status()); | 244 | 1.39k | return Image3(std::move(plane0).value(), std::move(plane1).value(), | 245 | 1.39k | std::move(plane2).value()); | 246 | 1.39k | } |
|
247 | | |
248 | | // Returns row pointer; usage: PlaneRow(idx_plane, y)[x] = val. |
249 | 11.8M | 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 | 11.8M | PlaneRowBoundsCheck(c, y); |
253 | 11.8M | const size_t row_offset = y * planes_[0].bytes_per_row(); |
254 | 11.8M | void* row = planes_[c].bytes() + row_offset; |
255 | 11.8M | return static_cast<T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); |
256 | 11.8M | } jxl::Image3<int>::PlaneRow(unsigned long, unsigned long) Line | Count | Source | 249 | 489k | 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 | 489k | PlaneRowBoundsCheck(c, y); | 253 | 489k | const size_t row_offset = y * planes_[0].bytes_per_row(); | 254 | 489k | void* row = planes_[c].bytes() + row_offset; | 255 | 489k | return static_cast<T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); | 256 | 489k | } |
jxl::Image3<short>::PlaneRow(unsigned long, unsigned long) Line | Count | Source | 249 | 285 | 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 | 285 | PlaneRowBoundsCheck(c, y); | 253 | 285 | const size_t row_offset = y * planes_[0].bytes_per_row(); | 254 | 285 | void* row = planes_[c].bytes() + row_offset; | 255 | 285 | return static_cast<T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); | 256 | 285 | } |
jxl::Image3<float>::PlaneRow(unsigned long, unsigned long) Line | Count | Source | 249 | 11.3M | 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 | 11.3M | PlaneRowBoundsCheck(c, y); | 253 | 11.3M | const size_t row_offset = y * planes_[0].bytes_per_row(); | 254 | 11.3M | void* row = planes_[c].bytes() + row_offset; | 255 | 11.3M | return static_cast<T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); | 256 | 11.3M | } |
|
257 | | |
258 | | // Returns const row pointer; usage: val = PlaneRow(idx_plane, y)[x]. |
259 | 2.48M | JXL_INLINE const T* PlaneRow(const size_t c, const size_t y) const { |
260 | 2.48M | PlaneRowBoundsCheck(c, y); |
261 | 2.48M | const size_t row_offset = y * planes_[0].bytes_per_row(); |
262 | 2.48M | const void* row = planes_[c].bytes() + row_offset; |
263 | 2.48M | return static_cast<const T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); |
264 | 2.48M | } jxl::Image3<int>::PlaneRow(unsigned long, unsigned long) const Line | Count | Source | 259 | 456k | JXL_INLINE const T* PlaneRow(const size_t c, const size_t y) const { | 260 | 456k | PlaneRowBoundsCheck(c, y); | 261 | 456k | const size_t row_offset = y * planes_[0].bytes_per_row(); | 262 | 456k | const void* row = planes_[c].bytes() + row_offset; | 263 | 456k | return static_cast<const T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); | 264 | 456k | } |
Unexecuted instantiation: jxl::Image3<short>::PlaneRow(unsigned long, unsigned long) const jxl::Image3<float>::PlaneRow(unsigned long, unsigned long) const Line | Count | Source | 259 | 2.02M | JXL_INLINE const T* PlaneRow(const size_t c, const size_t y) const { | 260 | 2.02M | PlaneRowBoundsCheck(c, y); | 261 | 2.02M | const size_t row_offset = y * planes_[0].bytes_per_row(); | 262 | 2.02M | const void* row = planes_[c].bytes() + row_offset; | 263 | 2.02M | return static_cast<const T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); | 264 | 2.02M | } |
|
265 | | |
266 | | // Returns const row pointer, even if called from a non-const Image3. |
267 | 2.48M | JXL_INLINE const T* ConstPlaneRow(const size_t c, const size_t y) const { |
268 | 2.48M | PlaneRowBoundsCheck(c, y); |
269 | 2.48M | return PlaneRow(c, y); |
270 | 2.48M | } jxl::Image3<float>::ConstPlaneRow(unsigned long, unsigned long) const Line | Count | Source | 267 | 2.02M | JXL_INLINE const T* ConstPlaneRow(const size_t c, const size_t y) const { | 268 | 2.02M | PlaneRowBoundsCheck(c, y); | 269 | 2.02M | return PlaneRow(c, y); | 270 | 2.02M | } |
jxl::Image3<int>::ConstPlaneRow(unsigned long, unsigned long) const Line | Count | Source | 267 | 456k | JXL_INLINE const T* ConstPlaneRow(const size_t c, const size_t y) const { | 268 | 456k | PlaneRowBoundsCheck(c, y); | 269 | 456k | return PlaneRow(c, y); | 270 | 456k | } |
|
271 | | |
272 | 64.1k | JXL_INLINE const PlaneT& Plane(size_t idx) const { return planes_[idx]; } |
273 | | |
274 | 0 | JXL_INLINE PlaneT& Plane(size_t idx) { return planes_[idx]; } Unexecuted instantiation: jxl::Image3<float>::Plane(unsigned long) Unexecuted instantiation: jxl::Image3<int>::Plane(unsigned long) Unexecuted instantiation: jxl::Image3<short>::Plane(unsigned long) |
275 | | |
276 | 1.25k | void Swap(Image3& other) { |
277 | 5.02k | for (size_t c = 0; c < 3; ++c) { |
278 | 3.76k | other.planes_[c].Swap(planes_[c]); |
279 | 3.76k | } |
280 | 1.25k | } |
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 | 0 | void ShrinkTo(const size_t xsize, const size_t ysize) { |
287 | 0 | for (PlaneT& plane : planes_) { |
288 | 0 | plane.ShrinkTo(xsize, ysize); |
289 | 0 | } |
290 | 0 | } |
291 | | |
292 | | // Sizes of all three images are guaranteed to be equal. |
293 | | JXL_INLINE JxlMemoryManager* memory_manager() const { |
294 | | return planes_[0].memory_manager(); |
295 | | } |
296 | 16.0M | JXL_INLINE size_t xsize() const { return planes_[0].xsize(); } jxl::Image3<float>::xsize() const Line | Count | Source | 296 | 16.0M | JXL_INLINE size_t xsize() const { return planes_[0].xsize(); } |
jxl::Image3<int>::xsize() const Line | Count | Source | 296 | 19.0k | JXL_INLINE size_t xsize() const { return planes_[0].xsize(); } |
jxl::Image3<short>::xsize() const Line | Count | Source | 296 | 3.89k | JXL_INLINE size_t xsize() const { return planes_[0].xsize(); } |
|
297 | 3.00M | JXL_INLINE size_t ysize() const { return planes_[0].ysize(); } jxl::Image3<float>::ysize() const Line | Count | Source | 297 | 3.00M | JXL_INLINE size_t ysize() const { return planes_[0].ysize(); } |
jxl::Image3<int>::ysize() const Line | Count | Source | 297 | 183 | JXL_INLINE size_t ysize() const { return planes_[0].ysize(); } |
jxl::Image3<short>::ysize() const Line | Count | Source | 297 | 225 | JXL_INLINE size_t ysize() const { return planes_[0].ysize(); } |
|
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 | 32.3k | JXL_INLINE intptr_t PixelsPerRow() const { return planes_[0].PixelsPerRow(); } jxl::Image3<int>::PixelsPerRow() const Line | Count | Source | 305 | 21.5k | 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 | 305 | 10.7k | JXL_INLINE intptr_t PixelsPerRow() const { return planes_[0].PixelsPerRow(); } |
|
306 | | |
307 | | private: |
308 | 77.2k | Image3(PlaneT&& plane0, PlaneT&& plane1, PlaneT&& plane2) { |
309 | 77.2k | planes_[0] = std::move(plane0); |
310 | 77.2k | planes_[1] = std::move(plane1); |
311 | 77.2k | planes_[2] = std::move(plane2); |
312 | 77.2k | } jxl::Image3<int>::Image3(jxl::Plane<int>&&, jxl::Plane<int>&&, jxl::Plane<int>&&) Line | Count | Source | 308 | 4.46k | Image3(PlaneT&& plane0, PlaneT&& plane1, PlaneT&& plane2) { | 309 | 4.46k | planes_[0] = std::move(plane0); | 310 | 4.46k | planes_[1] = std::move(plane1); | 311 | 4.46k | planes_[2] = std::move(plane2); | 312 | 4.46k | } |
jxl::Image3<short>::Image3(jxl::Plane<short>&&, jxl::Plane<short>&&, jxl::Plane<short>&&) Line | Count | Source | 308 | 1.39k | Image3(PlaneT&& plane0, PlaneT&& plane1, PlaneT&& plane2) { | 309 | 1.39k | planes_[0] = std::move(plane0); | 310 | 1.39k | planes_[1] = std::move(plane1); | 311 | 1.39k | planes_[2] = std::move(plane2); | 312 | 1.39k | } |
jxl::Image3<float>::Image3(jxl::Plane<float>&&, jxl::Plane<float>&&, jxl::Plane<float>&&) Line | Count | Source | 308 | 71.3k | Image3(PlaneT&& plane0, PlaneT&& plane1, PlaneT&& plane2) { | 309 | 71.3k | planes_[0] = std::move(plane0); | 310 | 71.3k | planes_[1] = std::move(plane1); | 311 | 71.3k | planes_[2] = std::move(plane2); | 312 | 71.3k | } |
|
313 | | |
314 | 16.8M | 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 | 16.8M | } jxl::Image3<int>::PlaneRowBoundsCheck(unsigned long, unsigned long) const Line | Count | Source | 314 | 1.40M | 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 | 1.40M | } |
jxl::Image3<short>::PlaneRowBoundsCheck(unsigned long, unsigned long) const Line | Count | Source | 314 | 285 | 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 | 285 | } |
jxl::Image3<float>::PlaneRowBoundsCheck(unsigned long, unsigned long) const Line | Count | Source | 314 | 15.4M | 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 | 15.4M | } |
|
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_ |