/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 | 4.77M | : xsize_(0), |
38 | 4.77M | ysize_(0), |
39 | 4.77M | orig_xsize_(0), |
40 | 4.77M | orig_ysize_(0), |
41 | 4.77M | bytes_per_row_(0), |
42 | 4.77M | 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 | 67.4M | PlaneBase(PlaneBase&& other) noexcept = default; |
51 | | |
52 | | // Move assignment (required for std::vector) |
53 | 11.0M | PlaneBase& operator=(PlaneBase&& other) noexcept = default; |
54 | | |
55 | 104M | ~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 | 86.6k | Status ShrinkTo(const size_t xsize, const size_t ysize) { |
64 | 86.6k | JXL_ENSURE(xsize <= orig_xsize_); |
65 | 86.6k | JXL_ENSURE(ysize <= orig_ysize_); |
66 | 86.6k | xsize_ = static_cast<uint32_t>(xsize); |
67 | 86.6k | 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 | 86.6k | return true; |
71 | 86.6k | } |
72 | | |
73 | | // How many pixels. |
74 | 408M | JXL_INLINE size_t xsize() const { return xsize_; } |
75 | 342M | 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 | 695M | JXL_INLINE size_t bytes_per_row() const { return bytes_per_row_; } |
79 | | |
80 | 287k | JXL_INLINE JxlMemoryManager* memory_manager() const { |
81 | 287k | return bytes_.memory_manager(); |
82 | 287k | } |
83 | | |
84 | | // Raw access to byte contents, for interfacing with other libraries. |
85 | | // Unsigned char instead of char to avoid surprises (sign extension). |
86 | 37.7M | JXL_INLINE uint8_t* bytes() { |
87 | 37.7M | uint8_t* p = bytes_.address<uint8_t>(); |
88 | 37.7M | return static_cast<uint8_t * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(p, 64)); |
89 | 37.7M | } |
90 | 657M | JXL_INLINE const uint8_t* bytes() const { |
91 | 657M | const uint8_t* p = bytes_.address<uint8_t>(); |
92 | 657M | return static_cast<const uint8_t * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(p, 64)); |
93 | 657M | } |
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 | 3.66G | JXL_INLINE void* VoidRow(const size_t y) const { |
101 | 3.66G | JXL_DASSERT(y < ysize_); |
102 | 3.66G | uint8_t* row = bytes_.address<uint8_t>() + y * bytes_per_row_; |
103 | 3.66G | return JXL_ASSUME_ALIGNED(row, 64); |
104 | 3.66G | } |
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 | 4.77M | Plane() = default; Line | Count | Source | 145 | 1.24M | Plane() = default; |
jxl::Plane<unsigned char>::Plane() Line | Count | Source | 145 | 80.4k | Plane() = default; |
jxl::Plane<signed char>::Plane() Line | Count | Source | 145 | 96.1k | Plane() = default; |
jxl::Plane<float>::Plane() Line | Count | Source | 145 | 3.30M | 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 | 52.0k | Plane() = default; |
|
146 | | |
147 | | static StatusOr<Plane> Create(JxlMemoryManager* memory_manager, |
148 | | const size_t xsize, const size_t ysize, |
149 | 32.1M | const size_t pre_padding = 0) { |
150 | 32.1M | static_assert( |
151 | 32.1M | sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, |
152 | 32.1M | "Only 1/2/4/8-byte samples are supported"); |
153 | 32.1M | uint32_t xsize32 = static_cast<uint32_t>(xsize); |
154 | 32.1M | uint32_t ysize32 = static_cast<uint32_t>(ysize); |
155 | 32.1M | JXL_ENSURE(xsize32 == xsize); |
156 | 32.1M | JXL_ENSURE(ysize32 == ysize); |
157 | 32.1M | Plane plane(xsize32, ysize32, sizeof(T)); |
158 | 32.1M | JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager, pre_padding)); |
159 | 32.1M | return plane; |
160 | 32.1M | } jxl::Plane<float>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long, unsigned long) Line | Count | Source | 149 | 30.9M | const size_t pre_padding = 0) { | 150 | 30.9M | static_assert( | 151 | 30.9M | sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, | 152 | 30.9M | "Only 1/2/4/8-byte samples are supported"); | 153 | 30.9M | uint32_t xsize32 = static_cast<uint32_t>(xsize); | 154 | 30.9M | uint32_t ysize32 = static_cast<uint32_t>(ysize); | 155 | 30.9M | JXL_ENSURE(xsize32 == xsize); | 156 | 30.9M | JXL_ENSURE(ysize32 == ysize); | 157 | 30.9M | Plane plane(xsize32, ysize32, sizeof(T)); | 158 | 30.9M | JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager, pre_padding)); | 159 | 30.9M | return plane; | 160 | 30.9M | } |
jxl::Plane<int>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long, unsigned long) Line | Count | Source | 149 | 977k | const size_t pre_padding = 0) { | 150 | 977k | static_assert( | 151 | 977k | sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, | 152 | 977k | "Only 1/2/4/8-byte samples are supported"); | 153 | 977k | uint32_t xsize32 = static_cast<uint32_t>(xsize); | 154 | 977k | uint32_t ysize32 = static_cast<uint32_t>(ysize); | 155 | 977k | JXL_ENSURE(xsize32 == xsize); | 156 | 977k | JXL_ENSURE(ysize32 == ysize); | 157 | 977k | Plane plane(xsize32, ysize32, sizeof(T)); | 158 | 977k | JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager, pre_padding)); | 159 | 977k | return plane; | 160 | 977k | } |
jxl::Plane<unsigned char>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long, unsigned long) Line | Count | Source | 149 | 100k | const size_t pre_padding = 0) { | 150 | 100k | static_assert( | 151 | 100k | sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, | 152 | 100k | "Only 1/2/4/8-byte samples are supported"); | 153 | 100k | uint32_t xsize32 = static_cast<uint32_t>(xsize); | 154 | 100k | uint32_t ysize32 = static_cast<uint32_t>(ysize); | 155 | 100k | JXL_ENSURE(xsize32 == xsize); | 156 | 100k | JXL_ENSURE(ysize32 == ysize); | 157 | 100k | Plane plane(xsize32, ysize32, sizeof(T)); | 158 | 100k | JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager, pre_padding)); | 159 | 100k | return plane; | 160 | 100k | } |
jxl::Plane<signed char>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long, unsigned long) Line | Count | Source | 149 | 63.7k | const size_t pre_padding = 0) { | 150 | 63.7k | static_assert( | 151 | 63.7k | sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, | 152 | 63.7k | "Only 1/2/4/8-byte samples are supported"); | 153 | 63.7k | uint32_t xsize32 = static_cast<uint32_t>(xsize); | 154 | 63.7k | uint32_t ysize32 = static_cast<uint32_t>(ysize); | 155 | 63.7k | JXL_ENSURE(xsize32 == xsize); | 156 | 63.7k | JXL_ENSURE(ysize32 == ysize); | 157 | 63.7k | Plane plane(xsize32, ysize32, sizeof(T)); | 158 | 63.7k | JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager, pre_padding)); | 159 | 63.7k | return plane; | 160 | 63.7k | } |
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 | 13.0k | const size_t pre_padding = 0) { | 150 | 13.0k | static_assert( | 151 | 13.0k | sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, | 152 | 13.0k | "Only 1/2/4/8-byte samples are supported"); | 153 | 13.0k | uint32_t xsize32 = static_cast<uint32_t>(xsize); | 154 | 13.0k | uint32_t ysize32 = static_cast<uint32_t>(ysize); | 155 | 13.0k | JXL_ENSURE(xsize32 == xsize); | 156 | 13.0k | JXL_ENSURE(ysize32 == ysize); | 157 | 13.0k | Plane plane(xsize32, ysize32, sizeof(T)); | 158 | 13.0k | JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager, pre_padding)); | 159 | 13.0k | return plane; | 160 | 13.0k | } |
|
161 | | |
162 | 314M | 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 | 6.36M | JXL_INLINE T* Row(const size_t y) { return static_cast<T*>(VoidRow(y)); } |
jxl::Plane<float>::Row(unsigned long) Line | Count | Source | 162 | 262M | JXL_INLINE T* Row(const size_t y) { return static_cast<T*>(VoidRow(y)); } |
jxl::Plane<int>::Row(unsigned long) Line | Count | Source | 162 | 45.2M | 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 | 451k | 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 | 2.23G | JXL_INLINE const T* Row(const size_t y) const { |
166 | 2.23G | return static_cast<const T*>(VoidRow(y)); |
167 | 2.23G | } jxl::Plane<float>::Row(unsigned long) const Line | Count | Source | 165 | 2.12G | JXL_INLINE const T* Row(const size_t y) const { | 166 | 2.12G | return static_cast<const T*>(VoidRow(y)); | 167 | 2.12G | } |
jxl::Plane<int>::Row(unsigned long) const Line | Count | Source | 165 | 110M | JXL_INLINE const T* Row(const size_t y) const { | 166 | 110M | return static_cast<const T*>(VoidRow(y)); | 167 | 110M | } |
Unexecuted instantiation: jxl::Plane<unsigned char>::Row(unsigned long) const |
168 | | |
169 | | // Documents that the access is const. |
170 | 1.11G | JXL_INLINE const T* ConstRow(const size_t y) const { |
171 | 1.11G | return static_cast<const T*>(VoidRow(y)); |
172 | 1.11G | } jxl::Plane<unsigned char>::ConstRow(unsigned long) const Line | Count | Source | 170 | 34.7M | JXL_INLINE const T* ConstRow(const size_t y) const { | 171 | 34.7M | return static_cast<const T*>(VoidRow(y)); | 172 | 34.7M | } |
jxl::Plane<float>::ConstRow(unsigned long) const Line | Count | Source | 170 | 1.07G | JXL_INLINE const T* ConstRow(const size_t y) const { | 171 | 1.07G | return static_cast<const T*>(VoidRow(y)); | 172 | 1.07G | } |
jxl::Plane<signed char>::ConstRow(unsigned long) const Line | Count | Source | 170 | 1.33M | JXL_INLINE const T* ConstRow(const size_t y) const { | 171 | 1.33M | return static_cast<const T*>(VoidRow(y)); | 172 | 1.33M | } |
jxl::Plane<int>::ConstRow(unsigned long) const Line | Count | Source | 170 | 2.07M | JXL_INLINE const T* ConstRow(const size_t y) const { | 171 | 2.07M | return static_cast<const T*>(VoidRow(y)); | 172 | 2.07M | } |
|
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 | 5.38M | JXL_INLINE ptrdiff_t PixelsPerRow() const { |
178 | 5.38M | return static_cast<ptrdiff_t>(bytes_per_row_ / sizeof(T)); |
179 | 5.38M | } jxl::Plane<unsigned char>::PixelsPerRow() const Line | Count | Source | 177 | 54.6k | JXL_INLINE ptrdiff_t PixelsPerRow() const { | 178 | 54.6k | return static_cast<ptrdiff_t>(bytes_per_row_ / sizeof(T)); | 179 | 54.6k | } |
jxl::Plane<int>::PixelsPerRow() const Line | Count | Source | 177 | 3.70M | JXL_INLINE ptrdiff_t PixelsPerRow() const { | 178 | 3.70M | return static_cast<ptrdiff_t>(bytes_per_row_ / sizeof(T)); | 179 | 3.70M | } |
jxl::Plane<float>::PixelsPerRow() const Line | Count | Source | 177 | 1.63M | JXL_INLINE ptrdiff_t PixelsPerRow() const { | 178 | 1.63M | return static_cast<ptrdiff_t>(bytes_per_row_ / sizeof(T)); | 179 | 1.63M | } |
Unexecuted instantiation: jxl::Plane<short>::PixelsPerRow() const |
180 | | |
181 | | private: |
182 | | Plane(uint32_t xsize, uint32_t ysize, size_t sizeof_t) |
183 | 32.1M | : detail::PlaneBase(xsize, ysize, sizeof_t) {}jxl::Plane<int>::Plane(unsigned int, unsigned int, unsigned long) Line | Count | Source | 183 | 977k | : detail::PlaneBase(xsize, ysize, sizeof_t) {} |
jxl::Plane<unsigned char>::Plane(unsigned int, unsigned int, unsigned long) Line | Count | Source | 183 | 100k | : detail::PlaneBase(xsize, ysize, sizeof_t) {} |
jxl::Plane<float>::Plane(unsigned int, unsigned int, unsigned long) Line | Count | Source | 183 | 30.9M | : detail::PlaneBase(xsize, ysize, sizeof_t) {} |
jxl::Plane<signed char>::Plane(unsigned int, unsigned int, unsigned long) Line | Count | Source | 183 | 63.7k | : 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 | 13.0k | : 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 | 661k | Image3() : planes_{PlaneT(), PlaneT(), PlaneT()} {}jxl::Image3<float>::Image3() Line | Count | Source | 219 | 277k | Image3() : planes_{PlaneT(), PlaneT(), PlaneT()} {} |
jxl::Image3<int>::Image3() Line | Count | Source | 219 | 379k | Image3() : planes_{PlaneT(), PlaneT(), PlaneT()} {} |
jxl::Image3<short>::Image3() Line | Count | Source | 219 | 4.33k | 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 | 282k | Image3(Image3&& other) noexcept { |
227 | 1.13M | for (size_t i = 0; i < kNumPlanes; i++) { |
228 | 848k | planes_[i] = std::move(other.planes_[i]); |
229 | 848k | } |
230 | 282k | } jxl::Image3<float>::Image3(jxl::Image3<float>&&) Line | Count | Source | 226 | 255k | Image3(Image3&& other) noexcept { | 227 | 1.02M | for (size_t i = 0; i < kNumPlanes; i++) { | 228 | 765k | planes_[i] = std::move(other.planes_[i]); | 229 | 765k | } | 230 | 255k | } |
jxl::Image3<int>::Image3(jxl::Image3<int>&&) Line | Count | Source | 226 | 18.9k | Image3(Image3&& other) noexcept { | 227 | 75.9k | for (size_t i = 0; i < kNumPlanes; i++) { | 228 | 56.9k | planes_[i] = std::move(other.planes_[i]); | 229 | 56.9k | } | 230 | 18.9k | } |
Unexecuted instantiation: jxl::Image3<unsigned char>::Image3(jxl::Image3<unsigned char>&&) jxl::Image3<short>::Image3(jxl::Image3<short>&&) Line | Count | Source | 226 | 8.67k | Image3(Image3&& other) noexcept { | 227 | 34.6k | for (size_t i = 0; i < kNumPlanes; i++) { | 228 | 26.0k | planes_[i] = std::move(other.planes_[i]); | 229 | 26.0k | } | 230 | 8.67k | } |
|
231 | 199k | Image3& operator=(Image3&& other) noexcept { |
232 | 799k | for (size_t i = 0; i < kNumPlanes; i++) { |
233 | 599k | planes_[i] = std::move(other.planes_[i]); |
234 | 599k | } |
235 | 199k | return *this; |
236 | 199k | } jxl::Image3<float>::operator=(jxl::Image3<float>&&) Line | Count | Source | 231 | 186k | Image3& operator=(Image3&& other) noexcept { | 232 | 744k | for (size_t i = 0; i < kNumPlanes; i++) { | 233 | 558k | planes_[i] = std::move(other.planes_[i]); | 234 | 558k | } | 235 | 186k | return *this; | 236 | 186k | } |
jxl::Image3<int>::operator=(jxl::Image3<int>&&) Line | Count | Source | 231 | 9.49k | Image3& operator=(Image3&& other) noexcept { | 232 | 37.9k | for (size_t i = 0; i < kNumPlanes; i++) { | 233 | 28.4k | planes_[i] = std::move(other.planes_[i]); | 234 | 28.4k | } | 235 | 9.49k | return *this; | 236 | 9.49k | } |
jxl::Image3<short>::operator=(jxl::Image3<short>&&) Line | Count | Source | 231 | 4.33k | Image3& operator=(Image3&& other) noexcept { | 232 | 17.3k | for (size_t i = 0; i < kNumPlanes; i++) { | 233 | 13.0k | planes_[i] = std::move(other.planes_[i]); | 234 | 13.0k | } | 235 | 4.33k | return *this; | 236 | 4.33k | } |
|
237 | | |
238 | | static StatusOr<Image3> Create(JxlMemoryManager* memory_manager, |
239 | 135k | const size_t xsize, const size_t ysize) { |
240 | 135k | JXL_ASSIGN_OR_RETURN(PlaneT plane0, |
241 | 135k | PlaneT::Create(memory_manager, xsize, ysize)); |
242 | 135k | JXL_ASSIGN_OR_RETURN(PlaneT plane1, |
243 | 135k | PlaneT::Create(memory_manager, xsize, ysize)); |
244 | 135k | JXL_ASSIGN_OR_RETURN(PlaneT plane2, |
245 | 135k | PlaneT::Create(memory_manager, xsize, ysize)); |
246 | 135k | return Image3(std::move(plane0), std::move(plane1), std::move(plane2)); |
247 | 135k | } jxl::Image3<float>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long) Line | Count | Source | 239 | 122k | const size_t xsize, const size_t ysize) { | 240 | 122k | JXL_ASSIGN_OR_RETURN(PlaneT plane0, | 241 | 122k | PlaneT::Create(memory_manager, xsize, ysize)); | 242 | 122k | JXL_ASSIGN_OR_RETURN(PlaneT plane1, | 243 | 122k | PlaneT::Create(memory_manager, xsize, ysize)); | 244 | 122k | JXL_ASSIGN_OR_RETURN(PlaneT plane2, | 245 | 122k | PlaneT::Create(memory_manager, xsize, ysize)); | 246 | 122k | return Image3(std::move(plane0), std::move(plane1), std::move(plane2)); | 247 | 122k | } |
jxl::Image3<int>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long) Line | Count | Source | 239 | 9.49k | const size_t xsize, const size_t ysize) { | 240 | 9.49k | JXL_ASSIGN_OR_RETURN(PlaneT plane0, | 241 | 9.49k | PlaneT::Create(memory_manager, xsize, ysize)); | 242 | 9.49k | JXL_ASSIGN_OR_RETURN(PlaneT plane1, | 243 | 9.49k | PlaneT::Create(memory_manager, xsize, ysize)); | 244 | 9.49k | JXL_ASSIGN_OR_RETURN(PlaneT plane2, | 245 | 9.49k | PlaneT::Create(memory_manager, xsize, ysize)); | 246 | 9.49k | return Image3(std::move(plane0), std::move(plane1), std::move(plane2)); | 247 | 9.49k | } |
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 | 4.33k | const size_t xsize, const size_t ysize) { | 240 | 4.33k | JXL_ASSIGN_OR_RETURN(PlaneT plane0, | 241 | 4.33k | PlaneT::Create(memory_manager, xsize, ysize)); | 242 | 4.33k | JXL_ASSIGN_OR_RETURN(PlaneT plane1, | 243 | 4.33k | PlaneT::Create(memory_manager, xsize, ysize)); | 244 | 4.33k | JXL_ASSIGN_OR_RETURN(PlaneT plane2, | 245 | 4.33k | PlaneT::Create(memory_manager, xsize, ysize)); | 246 | 4.33k | return Image3(std::move(plane0), std::move(plane1), std::move(plane2)); | 247 | 4.33k | } |
|
248 | | |
249 | | // Returns row pointer; usage: PlaneRow(idx_plane, y)[x] = val. |
250 | 37.7M | 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 | 37.7M | PlaneRowBoundsCheck(c, y); |
254 | 37.7M | const size_t row_offset = y * planes_[0].bytes_per_row(); |
255 | 37.7M | void* row = planes_[c].bytes() + row_offset; |
256 | 37.7M | return static_cast<T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); |
257 | 37.7M | } jxl::Image3<float>::PlaneRow(unsigned long, unsigned long) Line | Count | Source | 250 | 37.1M | 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 | 37.1M | PlaneRowBoundsCheck(c, y); | 254 | 37.1M | const size_t row_offset = y * planes_[0].bytes_per_row(); | 255 | 37.1M | void* row = planes_[c].bytes() + row_offset; | 256 | 37.1M | return static_cast<T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); | 257 | 37.1M | } |
jxl::Image3<int>::PlaneRow(unsigned long, unsigned long) Line | Count | Source | 250 | 593k | 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 | 593k | PlaneRowBoundsCheck(c, y); | 254 | 593k | const size_t row_offset = y * planes_[0].bytes_per_row(); | 255 | 593k | void* row = planes_[c].bytes() + row_offset; | 256 | 593k | return static_cast<T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); | 257 | 593k | } |
Unexecuted instantiation: jxl::Image3<unsigned char>::PlaneRow(unsigned long, unsigned long) jxl::Image3<short>::PlaneRow(unsigned long, unsigned long) Line | Count | Source | 250 | 1.68k | 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 | 1.68k | PlaneRowBoundsCheck(c, y); | 254 | 1.68k | const size_t row_offset = y * planes_[0].bytes_per_row(); | 255 | 1.68k | void* row = planes_[c].bytes() + row_offset; | 256 | 1.68k | return static_cast<T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); | 257 | 1.68k | } |
|
258 | | |
259 | | // Returns const row pointer; usage: val = PlaneRow(idx_plane, y)[x]. |
260 | 657M | JXL_INLINE const T* PlaneRow(const size_t c, const size_t y) const { |
261 | 657M | PlaneRowBoundsCheck(c, y); |
262 | 657M | const size_t row_offset = y * planes_[0].bytes_per_row(); |
263 | 657M | const void* row = planes_[c].bytes() + row_offset; |
264 | 657M | return static_cast<const T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); |
265 | 657M | } jxl::Image3<int>::PlaneRow(unsigned long, unsigned long) const Line | Count | Source | 260 | 487k | JXL_INLINE const T* PlaneRow(const size_t c, const size_t y) const { | 261 | 487k | PlaneRowBoundsCheck(c, y); | 262 | 487k | const size_t row_offset = y * planes_[0].bytes_per_row(); | 263 | 487k | const void* row = planes_[c].bytes() + row_offset; | 264 | 487k | return static_cast<const T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); | 265 | 487k | } |
jxl::Image3<float>::PlaneRow(unsigned long, unsigned long) const Line | Count | Source | 260 | 657M | JXL_INLINE const T* PlaneRow(const size_t c, const size_t y) const { | 261 | 657M | PlaneRowBoundsCheck(c, y); | 262 | 657M | const size_t row_offset = y * planes_[0].bytes_per_row(); | 263 | 657M | const void* row = planes_[c].bytes() + row_offset; | 264 | 657M | return static_cast<const T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64)); | 265 | 657M | } |
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 | 657M | JXL_INLINE const T* ConstPlaneRow(const size_t c, const size_t y) const { |
269 | 657M | PlaneRowBoundsCheck(c, y); |
270 | 657M | return PlaneRow(c, y); |
271 | 657M | } jxl::Image3<float>::ConstPlaneRow(unsigned long, unsigned long) const Line | Count | Source | 268 | 657M | JXL_INLINE const T* ConstPlaneRow(const size_t c, const size_t y) const { | 269 | 657M | PlaneRowBoundsCheck(c, y); | 270 | 657M | return PlaneRow(c, y); | 271 | 657M | } |
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 | 470k | JXL_INLINE const T* ConstPlaneRow(const size_t c, const size_t y) const { | 269 | 470k | PlaneRowBoundsCheck(c, y); | 270 | 470k | return PlaneRow(c, y); | 271 | 470k | } |
|
272 | | |
273 | 344k | JXL_INLINE const PlaneT& Plane(size_t idx) const { return planes_[idx]; } |
274 | | |
275 | 74.1k | JXL_INLINE PlaneT& Plane(size_t idx) { return planes_[idx]; }jxl::Image3<float>::Plane(unsigned long) Line | Count | Source | 275 | 74.1k | 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 | 2.38k | void Swap(Image3& other) { |
278 | 9.52k | for (size_t c = 0; c < 3; ++c) { |
279 | 7.14k | other.planes_[c].Swap(planes_[c]); |
280 | 7.14k | } |
281 | 2.38k | } |
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 | 7.17k | Status ShrinkTo(const size_t xsize, const size_t ysize) { |
288 | 21.5k | for (PlaneT& plane : planes_) { |
289 | 21.5k | JXL_RETURN_IF_ERROR(plane.ShrinkTo(xsize, ysize)); |
290 | 21.5k | } |
291 | 7.17k | return true; |
292 | 7.17k | } |
293 | | |
294 | | // Sizes of all three images are guaranteed to be equal. |
295 | 18.3k | JXL_INLINE JxlMemoryManager* memory_manager() const { |
296 | 18.3k | return planes_[0].memory_manager(); |
297 | 18.3k | } jxl::Image3<float>::memory_manager() const Line | Count | Source | 295 | 18.3k | JXL_INLINE JxlMemoryManager* memory_manager() const { | 296 | 18.3k | return planes_[0].memory_manager(); | 297 | 18.3k | } |
Unexecuted instantiation: jxl::Image3<unsigned char>::memory_manager() const |
298 | 273M | JXL_INLINE size_t xsize() const { return planes_[0].xsize(); }jxl::Image3<float>::xsize() const Line | Count | Source | 298 | 273M | JXL_INLINE size_t xsize() const { return planes_[0].xsize(); } |
jxl::Image3<int>::xsize() const Line | Count | Source | 298 | 29.3k | 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 | 4.93k | JXL_INLINE size_t xsize() const { return planes_[0].xsize(); } |
|
299 | 162M | JXL_INLINE size_t ysize() const { return planes_[0].ysize(); }jxl::Image3<float>::ysize() const Line | Count | Source | 299 | 162M | JXL_INLINE size_t ysize() const { return planes_[0].ysize(); } |
jxl::Image3<int>::ysize() const Line | Count | Source | 299 | 95 | 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 | 177 | 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 | 1.04M | JXL_INLINE ptrdiff_t PixelsPerRow() const { return planes_[0].PixelsPerRow(); }jxl::Image3<int>::PixelsPerRow() const Line | Count | Source | 307 | 16.6k | JXL_INLINE ptrdiff_t PixelsPerRow() const { return planes_[0].PixelsPerRow(); } |
jxl::Image3<float>::PixelsPerRow() const Line | Count | Source | 307 | 1.02M | JXL_INLINE ptrdiff_t PixelsPerRow() const { return planes_[0].PixelsPerRow(); } |
Unexecuted instantiation: jxl::Image3<short>::PixelsPerRow() const |
308 | | |
309 | | private: |
310 | 135k | Image3(PlaneT&& plane0, PlaneT&& plane1, PlaneT&& plane2) { |
311 | 135k | planes_[0] = std::move(plane0); |
312 | 135k | planes_[1] = std::move(plane1); |
313 | 135k | planes_[2] = std::move(plane2); |
314 | 135k | } jxl::Image3<float>::Image3(jxl::Plane<float>&&, jxl::Plane<float>&&, jxl::Plane<float>&&) Line | Count | Source | 310 | 122k | Image3(PlaneT&& plane0, PlaneT&& plane1, PlaneT&& plane2) { | 311 | 122k | planes_[0] = std::move(plane0); | 312 | 122k | planes_[1] = std::move(plane1); | 313 | 122k | planes_[2] = std::move(plane2); | 314 | 122k | } |
jxl::Image3<int>::Image3(jxl::Plane<int>&&, jxl::Plane<int>&&, jxl::Plane<int>&&) Line | Count | Source | 310 | 9.49k | Image3(PlaneT&& plane0, PlaneT&& plane1, PlaneT&& plane2) { | 311 | 9.49k | planes_[0] = std::move(plane0); | 312 | 9.49k | planes_[1] = std::move(plane1); | 313 | 9.49k | planes_[2] = std::move(plane2); | 314 | 9.49k | } |
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 | 4.33k | Image3(PlaneT&& plane0, PlaneT&& plane1, PlaneT&& plane2) { | 311 | 4.33k | planes_[0] = std::move(plane0); | 312 | 4.33k | planes_[1] = std::move(plane1); | 313 | 4.33k | planes_[2] = std::move(plane2); | 314 | 4.33k | } |
|
315 | | |
316 | 1.35G | void PlaneRowBoundsCheck(const size_t c, const size_t y) const { |
317 | 1.35G | JXL_DASSERT(c < kNumPlanes && y < ysize()); |
318 | 1.35G | } jxl::Image3<float>::PlaneRowBoundsCheck(unsigned long, unsigned long) const Line | Count | Source | 316 | 1.35G | void PlaneRowBoundsCheck(const size_t c, const size_t y) const { | 317 | 1.35G | JXL_DASSERT(c < kNumPlanes && y < ysize()); | 318 | 1.35G | } |
jxl::Image3<int>::PlaneRowBoundsCheck(unsigned long, unsigned long) const Line | Count | Source | 316 | 1.55M | void PlaneRowBoundsCheck(const size_t c, const size_t y) const { | 317 | 1.55M | JXL_DASSERT(c < kNumPlanes && y < ysize()); | 318 | 1.55M | } |
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 | 1.68k | void PlaneRowBoundsCheck(const size_t c, const size_t y) const { | 317 | 1.68k | JXL_DASSERT(c < kNumPlanes && y < ysize()); | 318 | 1.68k | } |
|
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_ |