/src/libjxl/lib/jxl/image.h
Line | Count | Source |
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 | 3.09M | : xsize_(0), |
38 | 3.09M | ysize_(0), |
39 | 3.09M | orig_xsize_(0), |
40 | 3.09M | orig_ysize_(0), |
41 | 3.09M | bytes_per_row_(0), |
42 | 3.09M | 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 | 13.4M | PlaneBase(PlaneBase&& other) noexcept = default; |
51 | | |
52 | | // Move assignment (required for std::vector) |
53 | 3.17M | PlaneBase& operator=(PlaneBase&& other) noexcept = default; |
54 | | |
55 | 22.6M | ~PlaneBase() = default; |
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 | 9.47k | Status ShrinkTo(const size_t xsize, const size_t ysize) { |
64 | 9.47k | JXL_ENSURE(xsize <= orig_xsize_); |
65 | 9.47k | JXL_ENSURE(ysize <= orig_ysize_); |
66 | 9.47k | xsize_ = static_cast<uint32_t>(xsize); |
67 | 9.47k | 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 | 9.47k | return true; |
71 | 9.47k | } |
72 | | |
73 | | // How many pixels. |
74 | 29.4M | JXL_INLINE size_t xsize() const { return xsize_; } |
75 | 23.3M | JXL_INLINE size_t ysize() const { return ysize_; } |
76 | | |
77 | | // NOTE: do not use this for copying rows - the valid xsize may be much less. |
78 | 86.9M | JXL_INLINE size_t bytes_per_row() const { return bytes_per_row_; } |
79 | | |
80 | 84.3k | JXL_INLINE JxlMemoryManager* memory_manager() const { |
81 | 84.3k | return bytes_.memory_manager(); |
82 | 84.3k | } |
83 | | |
84 | | // Raw access to byte contents, for interfacing with other libraries. |
85 | | // Unsigned char instead of char to avoid surprises (sign extension). |
86 | 9.95M | JXL_INLINE uint8_t* bytes() { |
87 | 9.95M | uint8_t* p = bytes_.address<uint8_t>(); |
88 | 9.95M | return static_cast<uint8_t * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(p, 64)); |
89 | 9.95M | } |
90 | 77.0M | JXL_INLINE const uint8_t* bytes() const { |
91 | 77.0M | const uint8_t* p = bytes_.address<uint8_t>(); |
92 | 77.0M | return static_cast<const uint8_t * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(p, 64)); |
93 | 77.0M | } |
94 | | |
95 | | protected: |
96 | | PlaneBase(uint32_t xsize, uint32_t ysize, size_t sizeof_t); |
97 | | Status Allocate(JxlMemoryManager* memory_manager, size_t pre_padding); |
98 | | |
99 | | // Returns pointer to the start of a row. |
100 | 417M | JXL_INLINE void* VoidRow(const size_t y) const { |
101 | 417M | JXL_DASSERT(y < ysize_); |
102 | 417M | uint8_t* row = bytes_.address<uint8_t>() + y * bytes_per_row_; |
103 | 417M | return JXL_ASSUME_ALIGNED(row, 64); |
104 | 417M | } |
105 | | |
106 | | // (Members are non-const to enable assignment during move-assignment.) |
107 | | uint32_t xsize_; // In valid pixels, not including any padding. |
108 | | uint32_t ysize_; |
109 | | uint32_t orig_xsize_; |
110 | | uint32_t orig_ysize_; |
111 | | size_t bytes_per_row_; // Includes padding. |
112 | | AlignedMemory bytes_; |
113 | | size_t sizeof_t_; |
114 | | }; |
115 | | |
116 | | } // namespace detail |
117 | | |
118 | | // Single channel, aligned rows separated by padding. T must be POD. |
119 | | // |
120 | | // 'Single channel' (one 2D array per channel) simplifies vectorization |
121 | | // (repeating the same operation on multiple adjacent components) without the |
122 | | // complexity of a hybrid layout (8 R, 8 G, 8 B, ...). In particular, clients |
123 | | // can easily iterate over all components in a row and Image requires no |
124 | | // knowledge of the pixel format beyond the component type "T". |
125 | | // |
126 | | // 'Aligned' means each row is aligned to the L1 cache line size. This prevents |
127 | | // false sharing between two threads operating on adjacent rows. |
128 | | // |
129 | | // 'Padding' is still relevant because vectors could potentially be larger than |
130 | | // a cache line. By rounding up row sizes to the vector size, we allow |
131 | | // reading/writing ALIGNED vectors whose first lane is a valid sample. This |
132 | | // avoids needing a separate loop to handle remaining unaligned lanes. |
133 | | // |
134 | | // This image layout could also be achieved with a vector and a row accessor |
135 | | // function, but a class wrapper with support for "deleter" allows wrapping |
136 | | // existing memory allocated by clients without copying the pixels. It also |
137 | | // provides convenient accessors for xsize/ysize, which shortens function |
138 | | // argument lists. Supports move-construction so it can be stored in containers. |
139 | | template <typename ComponentType> |
140 | | class Plane : public detail::PlaneBase { |
141 | | public: |
142 | | using T = ComponentType; |
143 | | static constexpr size_t kNumPlanes = 1; |
144 | | |
145 | 3.09M | Plane() = default; Line | Count | Source | 145 | 788k | Plane() = default; |
jxl::Plane<unsigned char>::Plane() Line | Count | Source | 145 | 57.2k | Plane() = default; |
jxl::Plane<signed char>::Plane() Line | Count | Source | 145 | 73.1k | Plane() = default; |
jxl::Plane<float>::Plane() Line | Count | Source | 145 | 2.15M | Plane() = default; |
Unexecuted instantiation: jxl::Plane<hwy::float16_t>::Plane() Unexecuted instantiation: jxl::Plane<unsigned int>::Plane() jxl::Plane<short>::Plane() Line | Count | Source | 145 | 18.7k | Plane() = default; |
|
146 | | |
147 | | static StatusOr<Plane> Create(JxlMemoryManager* memory_manager, |
148 | | const size_t xsize, const size_t ysize, |
149 | 6.03M | const size_t pre_padding = 0) { |
150 | 6.03M | static_assert( |
151 | 6.03M | sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, |
152 | 6.03M | "Only 1/2/4/8-byte samples are supported"); |
153 | 6.03M | uint32_t xsize32 = static_cast<uint32_t>(xsize); |
154 | 6.03M | uint32_t ysize32 = static_cast<uint32_t>(ysize); |
155 | 6.03M | JXL_ENSURE(xsize32 == xsize); |
156 | 6.03M | JXL_ENSURE(ysize32 == ysize); |
157 | 6.03M | Plane plane(xsize32, ysize32, sizeof(T)); |
158 | 6.03M | JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager, pre_padding)); |
159 | 6.03M | return plane; |
160 | 6.03M | } jxl::Plane<float>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long, unsigned long) Line | Count | Source | 149 | 5.50M | const size_t pre_padding = 0) { | 150 | 5.50M | static_assert( | 151 | 5.50M | sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, | 152 | 5.50M | "Only 1/2/4/8-byte samples are supported"); | 153 | 5.50M | uint32_t xsize32 = static_cast<uint32_t>(xsize); | 154 | 5.50M | uint32_t ysize32 = static_cast<uint32_t>(ysize); | 155 | 5.50M | JXL_ENSURE(xsize32 == xsize); | 156 | 5.50M | JXL_ENSURE(ysize32 == ysize); | 157 | 5.50M | Plane plane(xsize32, ysize32, sizeof(T)); | 158 | 5.50M | JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager, pre_padding)); | 159 | 5.50M | return plane; | 160 | 5.50M | } |
jxl::Plane<int>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long, unsigned long) Line | Count | Source | 149 | 391k | const size_t pre_padding = 0) { | 150 | 391k | static_assert( | 151 | 391k | sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, | 152 | 391k | "Only 1/2/4/8-byte samples are supported"); | 153 | 391k | uint32_t xsize32 = static_cast<uint32_t>(xsize); | 154 | 391k | uint32_t ysize32 = static_cast<uint32_t>(ysize); | 155 | 391k | JXL_ENSURE(xsize32 == xsize); | 156 | 391k | JXL_ENSURE(ysize32 == ysize); | 157 | 391k | Plane plane(xsize32, ysize32, sizeof(T)); | 158 | 391k | JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager, pre_padding)); | 159 | 391k | return plane; | 160 | 391k | } |
jxl::Plane<unsigned char>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long, unsigned long) Line | Count | Source | 149 | 79.1k | const size_t pre_padding = 0) { | 150 | 79.1k | static_assert( | 151 | 79.1k | sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, | 152 | 79.1k | "Only 1/2/4/8-byte samples are supported"); | 153 | 79.1k | uint32_t xsize32 = static_cast<uint32_t>(xsize); | 154 | 79.1k | uint32_t ysize32 = static_cast<uint32_t>(ysize); | 155 | 79.1k | JXL_ENSURE(xsize32 == xsize); | 156 | 79.1k | JXL_ENSURE(ysize32 == ysize); | 157 | 79.1k | Plane plane(xsize32, ysize32, sizeof(T)); | 158 | 79.1k | JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager, pre_padding)); | 159 | 79.1k | return plane; | 160 | 79.1k | } |
jxl::Plane<signed char>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long, unsigned long) Line | Count | Source | 149 | 52.4k | const size_t pre_padding = 0) { | 150 | 52.4k | static_assert( | 151 | 52.4k | sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, | 152 | 52.4k | "Only 1/2/4/8-byte samples are supported"); | 153 | 52.4k | uint32_t xsize32 = static_cast<uint32_t>(xsize); | 154 | 52.4k | uint32_t ysize32 = static_cast<uint32_t>(ysize); | 155 | 52.4k | JXL_ENSURE(xsize32 == xsize); | 156 | 52.4k | JXL_ENSURE(ysize32 == ysize); | 157 | 52.4k | Plane plane(xsize32, ysize32, sizeof(T)); | 158 | 52.4k | JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager, pre_padding)); | 159 | 52.4k | return plane; | 160 | 52.4k | } |
Unexecuted instantiation: jxl::Plane<hwy::float16_t>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long, unsigned long) Unexecuted instantiation: jxl::Plane<unsigned int>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long, unsigned long) jxl::Plane<short>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long, unsigned long) Line | Count | Source | 149 | 4.68k | const size_t pre_padding = 0) { | 150 | 4.68k | static_assert( | 151 | 4.68k | sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, | 152 | 4.68k | "Only 1/2/4/8-byte samples are supported"); | 153 | 4.68k | uint32_t xsize32 = static_cast<uint32_t>(xsize); | 154 | 4.68k | uint32_t ysize32 = static_cast<uint32_t>(ysize); | 155 | 4.68k | JXL_ENSURE(xsize32 == xsize); | 156 | 4.68k | JXL_ENSURE(ysize32 == ysize); | 157 | 4.68k | Plane plane(xsize32, ysize32, sizeof(T)); | 158 | 4.68k | JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager, pre_padding)); | 159 | 4.68k | return plane; | 160 | 4.68k | } |
|
161 | | |
162 | 59.2M | JXL_INLINE T* Row(const size_t y) { return static_cast<T*>(VoidRow(y)); } jxl::Plane<unsigned char>::Row(unsigned long) Line | Count | Source | 162 | 509k | JXL_INLINE T* Row(const size_t y) { return static_cast<T*>(VoidRow(y)); } |
jxl::Plane<float>::Row(unsigned long) Line | Count | Source | 162 | 47.4M | JXL_INLINE T* Row(const size_t y) { return static_cast<T*>(VoidRow(y)); } |
jxl::Plane<int>::Row(unsigned long) Line | Count | Source | 162 | 11.0M | JXL_INLINE T* Row(const size_t y) { return static_cast<T*>(VoidRow(y)); } |
jxl::Plane<signed char>::Row(unsigned long) Line | Count | Source | 162 | 221k | 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) |
163 | | |
164 | | // Returns pointer to const (see above). |
165 | 238M | JXL_INLINE const T* Row(const size_t y) const { |
166 | 238M | return static_cast<const T*>(VoidRow(y)); |
167 | 238M | } jxl::Plane<float>::Row(unsigned long) const Line | Count | Source | 165 | 229M | JXL_INLINE const T* Row(const size_t y) const { | 166 | 229M | return static_cast<const T*>(VoidRow(y)); | 167 | 229M | } |
jxl::Plane<int>::Row(unsigned long) const Line | Count | Source | 165 | 9.53M | JXL_INLINE const T* Row(const size_t y) const { | 166 | 9.53M | return static_cast<const T*>(VoidRow(y)); | 167 | 9.53M | } |
Unexecuted instantiation: jxl::Plane<unsigned char>::Row(unsigned long) const |
168 | | |
169 | | // Documents that the access is const. |
170 | 119M | JXL_INLINE const T* ConstRow(const size_t y) const { |
171 | 119M | return static_cast<const T*>(VoidRow(y)); |
172 | 119M | } jxl::Plane<unsigned char>::ConstRow(unsigned long) const Line | Count | Source | 170 | 3.87M | JXL_INLINE const T* ConstRow(const size_t y) const { | 171 | 3.87M | return static_cast<const T*>(VoidRow(y)); | 172 | 3.87M | } |
jxl::Plane<float>::ConstRow(unsigned long) const Line | Count | Source | 170 | 115M | JXL_INLINE const T* ConstRow(const size_t y) const { | 171 | 115M | return static_cast<const T*>(VoidRow(y)); | 172 | 115M | } |
jxl::Plane<signed char>::ConstRow(unsigned long) const Line | Count | Source | 170 | 143k | JXL_INLINE const T* ConstRow(const size_t y) const { | 171 | 143k | return static_cast<const T*>(VoidRow(y)); | 172 | 143k | } |
jxl::Plane<int>::ConstRow(unsigned long) const Line | Count | Source | 170 | 169k | JXL_INLINE const T* ConstRow(const size_t y) const { | 171 | 169k | return static_cast<const T*>(VoidRow(y)); | 172 | 169k | } |
|
173 | | |
174 | | // Returns number of pixels (some of which are padding) per row. Useful for |
175 | | // computing other rows via pointer arithmetic. WARNING: this must |
176 | | // NOT be used to determine xsize. |
177 | 1.25M | JXL_INLINE intptr_t PixelsPerRow() const { |
178 | 1.25M | return static_cast<intptr_t>(bytes_per_row_ / sizeof(T)); |
179 | 1.25M | } jxl::Plane<unsigned char>::PixelsPerRow() const Line | Count | Source | 177 | 29.1k | JXL_INLINE intptr_t PixelsPerRow() const { | 178 | 29.1k | return static_cast<intptr_t>(bytes_per_row_ / sizeof(T)); | 179 | 29.1k | } |
jxl::Plane<int>::PixelsPerRow() const Line | Count | Source | 177 | 840k | JXL_INLINE intptr_t PixelsPerRow() const { | 178 | 840k | return static_cast<intptr_t>(bytes_per_row_ / sizeof(T)); | 179 | 840k | } |
jxl::Plane<float>::PixelsPerRow() const Line | Count | Source | 177 | 384k | JXL_INLINE intptr_t PixelsPerRow() const { | 178 | 384k | return static_cast<intptr_t>(bytes_per_row_ / sizeof(T)); | 179 | 384k | } |
Unexecuted instantiation: jxl::Plane<short>::PixelsPerRow() const |
180 | | |
181 | | private: |
182 | | Plane(uint32_t xsize, uint32_t ysize, size_t sizeof_t) |
183 | 6.03M | : detail::PlaneBase(xsize, ysize, sizeof_t) {} jxl::Plane<int>::Plane(unsigned int, unsigned int, unsigned long) Line | Count | Source | 183 | 391k | : detail::PlaneBase(xsize, ysize, sizeof_t) {} |
jxl::Plane<unsigned char>::Plane(unsigned int, unsigned int, unsigned long) Line | Count | Source | 183 | 79.1k | : detail::PlaneBase(xsize, ysize, sizeof_t) {} |
jxl::Plane<float>::Plane(unsigned int, unsigned int, unsigned long) Line | Count | Source | 183 | 5.50M | : detail::PlaneBase(xsize, ysize, sizeof_t) {} |
jxl::Plane<signed char>::Plane(unsigned int, unsigned int, unsigned long) Line | Count | Source | 183 | 52.4k | : detail::PlaneBase(xsize, ysize, sizeof_t) {} |
Unexecuted instantiation: jxl::Plane<hwy::float16_t>::Plane(unsigned int, unsigned int, unsigned long) Unexecuted instantiation: jxl::Plane<unsigned int>::Plane(unsigned int, unsigned int, unsigned long) jxl::Plane<short>::Plane(unsigned int, unsigned int, unsigned long) Line | Count | Source | 183 | 4.68k | : detail::PlaneBase(xsize, ysize, sizeof_t) {} |
|
184 | | }; |
185 | | |
186 | | using ImageSB = Plane<int8_t>; |
187 | | using ImageB = Plane<uint8_t>; |
188 | | using ImageS = Plane<int16_t>; // signed integer or half-float |
189 | | using ImageU = Plane<uint16_t>; |
190 | | using ImageI = Plane<int32_t>; |
191 | | using ImageF = Plane<float>; |
192 | | using ImageD = Plane<double>; |
193 | | |
194 | | // Currently, we abuse Image to either refer to an image that owns its storage |
195 | | // or one that doesn't. In similar vein, we abuse Image* function parameters to |
196 | | // either mean "assign to me" or "fill the provided image with data". |
197 | | // Hopefully, the "assign to me" meaning will go away and most images in the |
198 | | // codebase will not be backed by own storage. When this happens we can redesign |
199 | | // Image to be a non-storage-holding view class and introduce BackedImage in |
200 | | // those places that actually need it. |
201 | | |
202 | | // NOTE: we can't use Image as a view because invariants are violated |
203 | | // (alignment and the presence of padding before/after each "row"). |
204 | | |
205 | | // A bundle of 3 same-sized images. Typically constructed by moving from three |
206 | | // rvalue references to Image. To overwrite an existing Image3 using |
207 | | // single-channel producers, we also need access to Image*. Constructing |
208 | | // temporary non-owning Image pointing to one plane of an existing Image3 risks |
209 | | // dangling references, especially if the wrapper is moved. Therefore, we |
210 | | // store an array of Image (which are compact enough that size is not a concern) |
211 | | // and provide Plane+Row accessors. |
212 | | template <typename ComponentType> |
213 | | class Image3 { |
214 | | public: |
215 | | using T = ComponentType; |
216 | | using PlaneT = jxl::Plane<T>; |
217 | | static constexpr size_t kNumPlanes = 3; |
218 | | |
219 | 441k | Image3() : planes_{PlaneT(), PlaneT(), PlaneT()} {} jxl::Image3<float>::Image3() Line | Count | Source | 219 | 188k | Image3() : planes_{PlaneT(), PlaneT(), PlaneT()} {} |
jxl::Image3<int>::Image3() Line | Count | Source | 219 | 251k | Image3() : planes_{PlaneT(), PlaneT(), PlaneT()} {} |
jxl::Image3<short>::Image3() Line | Count | Source | 219 | 1.56k | Image3() : planes_{PlaneT(), PlaneT(), PlaneT()} {} |
|
220 | | |
221 | | // Copy construction/assignment is forbidden to avoid inadvertent copies, |
222 | | // which can be very expensive. Use CopyImageTo instead. |
223 | | Image3(const Image3& other) = delete; |
224 | | Image3& operator=(const Image3& other) = delete; |
225 | | |
226 | 151k | Image3(Image3&& other) noexcept { |
227 | 607k | for (size_t i = 0; i < kNumPlanes; i++) { |
228 | 455k | planes_[i] = std::move(other.planes_[i]); |
229 | 455k | } |
230 | 151k | } jxl::Image3<float>::Image3(jxl::Image3<float>&&) Line | Count | Source | 226 | 144k | Image3(Image3&& other) noexcept { | 227 | 577k | for (size_t i = 0; i < kNumPlanes; i++) { | 228 | 432k | planes_[i] = std::move(other.planes_[i]); | 229 | 432k | } | 230 | 144k | } |
jxl::Image3<int>::Image3(jxl::Image3<int>&&) Line | Count | Source | 226 | 4.40k | Image3(Image3&& other) noexcept { | 227 | 17.6k | for (size_t i = 0; i < kNumPlanes; i++) { | 228 | 13.2k | planes_[i] = std::move(other.planes_[i]); | 229 | 13.2k | } | 230 | 4.40k | } |
Unexecuted instantiation: jxl::Image3<unsigned char>::Image3(jxl::Image3<unsigned char>&&) jxl::Image3<short>::Image3(jxl::Image3<short>&&) Line | Count | Source | 226 | 3.12k | Image3(Image3&& other) noexcept { | 227 | 12.4k | for (size_t i = 0; i < kNumPlanes; i++) { | 228 | 9.37k | planes_[i] = std::move(other.planes_[i]); | 229 | 9.37k | } | 230 | 3.12k | } |
|
231 | 136k | Image3& operator=(Image3&& other) noexcept { |
232 | 545k | for (size_t i = 0; i < kNumPlanes; i++) { |
233 | 409k | planes_[i] = std::move(other.planes_[i]); |
234 | 409k | } |
235 | 136k | return *this; |
236 | 136k | } jxl::Image3<float>::operator=(jxl::Image3<float>&&) Line | Count | Source | 231 | 132k | Image3& operator=(Image3&& other) noexcept { | 232 | 530k | for (size_t i = 0; i < kNumPlanes; i++) { | 233 | 397k | planes_[i] = std::move(other.planes_[i]); | 234 | 397k | } | 235 | 132k | return *this; | 236 | 132k | } |
jxl::Image3<int>::operator=(jxl::Image3<int>&&) Line | Count | Source | 231 | 2.20k | Image3& operator=(Image3&& other) noexcept { | 232 | 8.81k | for (size_t i = 0; i < kNumPlanes; i++) { | 233 | 6.61k | planes_[i] = std::move(other.planes_[i]); | 234 | 6.61k | } | 235 | 2.20k | return *this; | 236 | 2.20k | } |
jxl::Image3<short>::operator=(jxl::Image3<short>&&) Line | Count | Source | 231 | 1.56k | Image3& operator=(Image3&& other) noexcept { | 232 | 6.24k | for (size_t i = 0; i < kNumPlanes; i++) { | 233 | 4.68k | planes_[i] = std::move(other.planes_[i]); | 234 | 4.68k | } | 235 | 1.56k | return *this; | 236 | 1.56k | } |
|
237 | | |
238 | | static StatusOr<Image3> Create(JxlMemoryManager* memory_manager, |
239 | 75.3k | const size_t xsize, const size_t ysize) { |
240 | 75.3k | JXL_ASSIGN_OR_RETURN(PlaneT plane0, |
241 | 75.3k | PlaneT::Create(memory_manager, xsize, ysize)); |
242 | 75.3k | JXL_ASSIGN_OR_RETURN(PlaneT plane1, |
243 | 75.3k | PlaneT::Create(memory_manager, xsize, ysize)); |
244 | 75.3k | JXL_ASSIGN_OR_RETURN(PlaneT plane2, |
245 | 75.3k | PlaneT::Create(memory_manager, xsize, ysize)); |
246 | 75.3k | return Image3(std::move(plane0), std::move(plane1), std::move(plane2)); |
247 | 75.3k | } jxl::Image3<float>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long) Line | Count | Source | 239 | 71.5k | const size_t xsize, const size_t ysize) { | 240 | 71.5k | JXL_ASSIGN_OR_RETURN(PlaneT plane0, | 241 | 71.5k | PlaneT::Create(memory_manager, xsize, ysize)); | 242 | 71.5k | JXL_ASSIGN_OR_RETURN(PlaneT plane1, | 243 | 71.5k | PlaneT::Create(memory_manager, xsize, ysize)); | 244 | 71.5k | JXL_ASSIGN_OR_RETURN(PlaneT plane2, | 245 | 71.5k | PlaneT::Create(memory_manager, xsize, ysize)); | 246 | 71.5k | return Image3(std::move(plane0), std::move(plane1), std::move(plane2)); | 247 | 71.5k | } |
jxl::Image3<int>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long) Line | Count | Source | 239 | 2.20k | const size_t xsize, const size_t ysize) { | 240 | 2.20k | JXL_ASSIGN_OR_RETURN(PlaneT plane0, | 241 | 2.20k | PlaneT::Create(memory_manager, xsize, ysize)); | 242 | 2.20k | JXL_ASSIGN_OR_RETURN(PlaneT plane1, | 243 | 2.20k | PlaneT::Create(memory_manager, xsize, ysize)); | 244 | 2.20k | JXL_ASSIGN_OR_RETURN(PlaneT plane2, | 245 | 2.20k | PlaneT::Create(memory_manager, xsize, ysize)); | 246 | 2.20k | return Image3(std::move(plane0), std::move(plane1), std::move(plane2)); | 247 | 2.20k | } |
Unexecuted instantiation: jxl::Image3<unsigned char>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long) jxl::Image3<short>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long) Line | Count | Source | 239 | 1.56k | const size_t xsize, const size_t ysize) { | 240 | 1.56k | JXL_ASSIGN_OR_RETURN(PlaneT plane0, | 241 | 1.56k | PlaneT::Create(memory_manager, xsize, ysize)); | 242 | 1.56k | JXL_ASSIGN_OR_RETURN(PlaneT plane1, | 243 | 1.56k | PlaneT::Create(memory_manager, xsize, ysize)); | 244 | 1.56k | JXL_ASSIGN_OR_RETURN(PlaneT plane2, | 245 | 1.56k | PlaneT::Create(memory_manager, xsize, ysize)); | 246 | 1.56k | return Image3(std::move(plane0), std::move(plane1), std::move(plane2)); | 247 | 1.56k | } |
|
248 | | |
249 | | // Returns row pointer; usage: PlaneRow(idx_plane, y)[x] = val. |
250 | 9.95M | JXL_INLINE T* PlaneRow(const size_t c, const size_t y) { |
251 | | // Custom implementation instead of calling planes_[c].Row ensures only a |
252 | | // single multiplication is needed for PlaneRow(0..2, y). |
253 | 9.95M | PlaneRowBoundsCheck(c, y); |
254 | 9.95M | const size_t row_offset = y * planes_[0].bytes_per_row(); |
255 | 9.95M | void* row = planes_[c].bytes() + row_offset; |
256 | 9.95M | return static_cast<T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); |
257 | 9.95M | } jxl::Image3<float>::PlaneRow(unsigned long, unsigned long) Line | Count | Source | 250 | 9.88M | JXL_INLINE T* PlaneRow(const size_t c, const size_t y) { | 251 | | // Custom implementation instead of calling planes_[c].Row ensures only a | 252 | | // single multiplication is needed for PlaneRow(0..2, y). | 253 | 9.88M | PlaneRowBoundsCheck(c, y); | 254 | 9.88M | const size_t row_offset = y * planes_[0].bytes_per_row(); | 255 | 9.88M | void* row = planes_[c].bytes() + row_offset; | 256 | 9.88M | return static_cast<T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); | 257 | 9.88M | } |
jxl::Image3<int>::PlaneRow(unsigned long, unsigned long) Line | Count | Source | 250 | 69.1k | JXL_INLINE T* PlaneRow(const size_t c, const size_t y) { | 251 | | // Custom implementation instead of calling planes_[c].Row ensures only a | 252 | | // single multiplication is needed for PlaneRow(0..2, y). | 253 | 69.1k | PlaneRowBoundsCheck(c, y); | 254 | 69.1k | const size_t row_offset = y * planes_[0].bytes_per_row(); | 255 | 69.1k | void* row = planes_[c].bytes() + row_offset; | 256 | 69.1k | return static_cast<T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); | 257 | 69.1k | } |
Unexecuted instantiation: jxl::Image3<unsigned char>::PlaneRow(unsigned long, unsigned long) jxl::Image3<short>::PlaneRow(unsigned long, unsigned long) Line | Count | Source | 250 | 24 | JXL_INLINE T* PlaneRow(const size_t c, const size_t y) { | 251 | | // Custom implementation instead of calling planes_[c].Row ensures only a | 252 | | // single multiplication is needed for PlaneRow(0..2, y). | 253 | 24 | PlaneRowBoundsCheck(c, y); | 254 | 24 | const size_t row_offset = y * planes_[0].bytes_per_row(); | 255 | 24 | void* row = planes_[c].bytes() + row_offset; | 256 | 24 | return static_cast<T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); | 257 | 24 | } |
|
258 | | |
259 | | // Returns const row pointer; usage: val = PlaneRow(idx_plane, y)[x]. |
260 | 77.0M | JXL_INLINE const T* PlaneRow(const size_t c, const size_t y) const { |
261 | 77.0M | PlaneRowBoundsCheck(c, y); |
262 | 77.0M | const size_t row_offset = y * planes_[0].bytes_per_row(); |
263 | 77.0M | const void* row = planes_[c].bytes() + row_offset; |
264 | 77.0M | return static_cast<const T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); |
265 | 77.0M | } jxl::Image3<int>::PlaneRow(unsigned long, unsigned long) const Line | Count | Source | 260 | 55.0k | JXL_INLINE const T* PlaneRow(const size_t c, const size_t y) const { | 261 | 55.0k | PlaneRowBoundsCheck(c, y); | 262 | 55.0k | const size_t row_offset = y * planes_[0].bytes_per_row(); | 263 | 55.0k | const void* row = planes_[c].bytes() + row_offset; | 264 | 55.0k | return static_cast<const T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); | 265 | 55.0k | } |
jxl::Image3<float>::PlaneRow(unsigned long, unsigned long) const Line | Count | Source | 260 | 76.9M | JXL_INLINE const T* PlaneRow(const size_t c, const size_t y) const { | 261 | 76.9M | PlaneRowBoundsCheck(c, y); | 262 | 76.9M | const size_t row_offset = y * planes_[0].bytes_per_row(); | 263 | 76.9M | const void* row = planes_[c].bytes() + row_offset; | 264 | 76.9M | return static_cast<const T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); | 265 | 76.9M | } |
Unexecuted instantiation: jxl::Image3<unsigned char>::PlaneRow(unsigned long, unsigned long) const Unexecuted instantiation: jxl::Image3<short>::PlaneRow(unsigned long, unsigned long) const |
266 | | |
267 | | // Returns const row pointer, even if called from a non-const Image3. |
268 | 77.0M | JXL_INLINE const T* ConstPlaneRow(const size_t c, const size_t y) const { |
269 | 77.0M | PlaneRowBoundsCheck(c, y); |
270 | 77.0M | return PlaneRow(c, y); |
271 | 77.0M | } jxl::Image3<float>::ConstPlaneRow(unsigned long, unsigned long) const Line | Count | Source | 268 | 76.9M | JXL_INLINE const T* ConstPlaneRow(const size_t c, const size_t y) const { | 269 | 76.9M | PlaneRowBoundsCheck(c, y); | 270 | 76.9M | return PlaneRow(c, y); | 271 | 76.9M | } |
Unexecuted instantiation: jxl::Image3<unsigned char>::ConstPlaneRow(unsigned long, unsigned long) const jxl::Image3<int>::ConstPlaneRow(unsigned long, unsigned long) const Line | Count | Source | 268 | 53.3k | JXL_INLINE const T* ConstPlaneRow(const size_t c, const size_t y) const { | 269 | 53.3k | PlaneRowBoundsCheck(c, y); | 270 | 53.3k | return PlaneRow(c, y); | 271 | 53.3k | } |
|
272 | | |
273 | 43.9k | JXL_INLINE const PlaneT& Plane(size_t idx) const { return planes_[idx]; } |
274 | | |
275 | 6.99k | JXL_INLINE PlaneT& Plane(size_t idx) { return planes_[idx]; } jxl::Image3<float>::Plane(unsigned long) Line | Count | Source | 275 | 6.99k | 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) |
276 | | |
277 | 868 | void Swap(Image3& other) { |
278 | 3.47k | for (size_t c = 0; c < 3; ++c) { |
279 | 2.60k | other.planes_[c].Swap(planes_[c]); |
280 | 2.60k | } |
281 | 868 | } |
282 | | |
283 | | // Useful for pre-allocating image with some padding for alignment purposes |
284 | | // and later reporting the actual valid dimensions. May also be used to |
285 | | // un-shrink the image. Caller is responsible for ensuring xsize/ysize are <= |
286 | | // the original dimensions. |
287 | 752 | Status ShrinkTo(const size_t xsize, const size_t ysize) { |
288 | 2.25k | for (PlaneT& plane : planes_) { |
289 | 2.25k | JXL_RETURN_IF_ERROR(plane.ShrinkTo(xsize, ysize)); |
290 | 2.25k | } |
291 | 752 | return true; |
292 | 752 | } |
293 | | |
294 | | // Sizes of all three images are guaranteed to be equal. |
295 | 1.90k | JXL_INLINE JxlMemoryManager* memory_manager() const { |
296 | 1.90k | return planes_[0].memory_manager(); |
297 | 1.90k | } jxl::Image3<float>::memory_manager() const Line | Count | Source | 295 | 1.90k | JXL_INLINE JxlMemoryManager* memory_manager() const { | 296 | 1.90k | return planes_[0].memory_manager(); | 297 | 1.90k | } |
Unexecuted instantiation: jxl::Image3<unsigned char>::memory_manager() const |
298 | 5.02M | JXL_INLINE size_t xsize() const { return planes_[0].xsize(); } jxl::Image3<float>::xsize() const Line | Count | Source | 298 | 5.02M | JXL_INLINE size_t xsize() const { return planes_[0].xsize(); } |
jxl::Image3<int>::xsize() const Line | Count | Source | 298 | 4.22k | JXL_INLINE size_t xsize() const { return planes_[0].xsize(); } |
Unexecuted instantiation: jxl::Image3<unsigned char>::xsize() const jxl::Image3<short>::xsize() const Line | Count | Source | 298 | 1.59k | JXL_INLINE size_t xsize() const { return planes_[0].xsize(); } |
|
299 | 3.04M | JXL_INLINE size_t ysize() const { return planes_[0].ysize(); } jxl::Image3<float>::ysize() const Line | Count | Source | 299 | 3.04M | JXL_INLINE size_t ysize() const { return planes_[0].ysize(); } |
jxl::Image3<int>::ysize() const Line | Count | Source | 299 | 7 | JXL_INLINE size_t ysize() const { return planes_[0].ysize(); } |
Unexecuted instantiation: jxl::Image3<unsigned char>::ysize() const jxl::Image3<short>::ysize() const Line | Count | Source | 299 | 28 | JXL_INLINE size_t ysize() const { return planes_[0].ysize(); } |
|
300 | | // Returns offset [bytes] from one row to the next row of the same plane. |
301 | | // WARNING: this must NOT be used to determine xsize, nor for copying rows - |
302 | | // the valid xsize may be much less. |
303 | | JXL_INLINE size_t bytes_per_row() const { return planes_[0].bytes_per_row(); } |
304 | | // Returns number of pixels (some of which are padding) per row. Useful for |
305 | | // computing other rows via pointer arithmetic. WARNING: this must NOT be used |
306 | | // to determine xsize. |
307 | 116k | JXL_INLINE intptr_t PixelsPerRow() const { return planes_[0].PixelsPerRow(); } jxl::Image3<int>::PixelsPerRow() const Line | Count | Source | 307 | 3.99k | JXL_INLINE intptr_t PixelsPerRow() const { return planes_[0].PixelsPerRow(); } |
jxl::Image3<float>::PixelsPerRow() const Line | Count | Source | 307 | 112k | JXL_INLINE intptr_t PixelsPerRow() const { return planes_[0].PixelsPerRow(); } |
Unexecuted instantiation: jxl::Image3<short>::PixelsPerRow() const |
308 | | |
309 | | private: |
310 | 75.3k | Image3(PlaneT&& plane0, PlaneT&& plane1, PlaneT&& plane2) { |
311 | 75.3k | planes_[0] = std::move(plane0); |
312 | 75.3k | planes_[1] = std::move(plane1); |
313 | 75.3k | planes_[2] = std::move(plane2); |
314 | 75.3k | } jxl::Image3<float>::Image3(jxl::Plane<float>&&, jxl::Plane<float>&&, jxl::Plane<float>&&) Line | Count | Source | 310 | 71.5k | Image3(PlaneT&& plane0, PlaneT&& plane1, PlaneT&& plane2) { | 311 | 71.5k | planes_[0] = std::move(plane0); | 312 | 71.5k | planes_[1] = std::move(plane1); | 313 | 71.5k | planes_[2] = std::move(plane2); | 314 | 71.5k | } |
jxl::Image3<int>::Image3(jxl::Plane<int>&&, jxl::Plane<int>&&, jxl::Plane<int>&&) Line | Count | Source | 310 | 2.20k | Image3(PlaneT&& plane0, PlaneT&& plane1, PlaneT&& plane2) { | 311 | 2.20k | planes_[0] = std::move(plane0); | 312 | 2.20k | planes_[1] = std::move(plane1); | 313 | 2.20k | planes_[2] = std::move(plane2); | 314 | 2.20k | } |
Unexecuted instantiation: jxl::Image3<unsigned char>::Image3(jxl::Plane<unsigned char>&&, jxl::Plane<unsigned char>&&, jxl::Plane<unsigned char>&&) jxl::Image3<short>::Image3(jxl::Plane<short>&&, jxl::Plane<short>&&, jxl::Plane<short>&&) Line | Count | Source | 310 | 1.56k | Image3(PlaneT&& plane0, PlaneT&& plane1, PlaneT&& plane2) { | 311 | 1.56k | planes_[0] = std::move(plane0); | 312 | 1.56k | planes_[1] = std::move(plane1); | 313 | 1.56k | planes_[2] = std::move(plane2); | 314 | 1.56k | } |
|
315 | | |
316 | 164M | void PlaneRowBoundsCheck(const size_t c, const size_t y) const { |
317 | 164M | JXL_DASSERT(c < kNumPlanes && y < ysize()); |
318 | 164M | } jxl::Image3<float>::PlaneRowBoundsCheck(unsigned long, unsigned long) const Line | Count | Source | 316 | 163M | void PlaneRowBoundsCheck(const size_t c, const size_t y) const { | 317 | 163M | JXL_DASSERT(c < kNumPlanes && y < ysize()); | 318 | 163M | } |
jxl::Image3<int>::PlaneRowBoundsCheck(unsigned long, unsigned long) const Line | Count | Source | 316 | 177k | void PlaneRowBoundsCheck(const size_t c, const size_t y) const { | 317 | 177k | JXL_DASSERT(c < kNumPlanes && y < ysize()); | 318 | 177k | } |
Unexecuted instantiation: jxl::Image3<unsigned char>::PlaneRowBoundsCheck(unsigned long, unsigned long) const jxl::Image3<short>::PlaneRowBoundsCheck(unsigned long, unsigned long) const Line | Count | Source | 316 | 24 | void PlaneRowBoundsCheck(const size_t c, const size_t y) const { | 317 | 24 | JXL_DASSERT(c < kNumPlanes && y < ysize()); | 318 | 24 | } |
|
319 | | |
320 | | PlaneT planes_[kNumPlanes]; |
321 | | }; |
322 | | |
323 | | using Image3B = Image3<uint8_t>; |
324 | | using Image3S = Image3<int16_t>; |
325 | | using Image3U = Image3<uint16_t>; |
326 | | using Image3I = Image3<int32_t>; |
327 | | using Image3F = Image3<float>; |
328 | | using Image3D = Image3<double>; |
329 | | |
330 | | } // namespace jxl |
331 | | |
332 | | #endif // LIB_JXL_IMAGE_H_ |