Coverage Report

Created: 2026-08-14 08:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
17.2M
      : xsize_(0),
38
17.2M
        ysize_(0),
39
17.2M
        orig_xsize_(0),
40
17.2M
        orig_ysize_(0),
41
17.2M
        bytes_per_row_(0),
42
17.2M
        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
60.4M
  PlaneBase(PlaneBase&& other) noexcept = default;
51
52
  // Move assignment (required for std::vector)
53
253M
  PlaneBase& operator=(PlaneBase&& other) noexcept = default;
54
55
100M
  ~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
3.69k
  Status ShrinkTo(const size_t xsize, const size_t ysize) {
64
3.69k
    JXL_ENSURE(xsize <= orig_xsize_);
65
3.69k
    JXL_ENSURE(ysize <= orig_ysize_);
66
3.69k
    xsize_ = static_cast<uint32_t>(xsize);
67
3.69k
    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
3.69k
    return true;
71
3.69k
  }
72
73
  // How many pixels.
74
326M
  JXL_INLINE size_t xsize() const { return xsize_; }
75
207M
  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
106M
  JXL_INLINE size_t bytes_per_row() const { return bytes_per_row_; }
79
80
1.36M
  JXL_INLINE JxlMemoryManager* memory_manager() const {
81
1.36M
    return bytes_.memory_manager();
82
1.36M
  }
83
84
  // Raw access to byte contents, for interfacing with other libraries.
85
  // Unsigned char instead of char to avoid surprises (sign extension).
86
59.6M
  JXL_INLINE uint8_t* bytes() {
87
59.6M
    uint8_t* p = bytes_.address<uint8_t>();
88
59.6M
    return static_cast<uint8_t * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(p, 64));
89
59.6M
  }
90
46.3M
  JXL_INLINE const uint8_t* bytes() const {
91
46.3M
    const uint8_t* p = bytes_.address<uint8_t>();
92
46.3M
    return static_cast<const uint8_t * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(p, 64));
93
46.3M
  }
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
1.95G
  JXL_INLINE void* VoidRow(const size_t y) const {
101
1.95G
    JXL_DASSERT(y < ysize_);
102
1.95G
    uint8_t* row = bytes_.address<uint8_t>() + y * bytes_per_row_;
103
1.95G
    return JXL_ASSUME_ALIGNED(row, 64);
104
1.95G
  }
Unexecuted instantiation: jxl::detail::PlaneBase::VoidRow(unsigned long) const
jxl::detail::PlaneBase::VoidRow(unsigned long) const
Line
Count
Source
100
1.95G
  JXL_INLINE void* VoidRow(const size_t y) const {
101
1.95G
    JXL_DASSERT(y < ysize_);
102
1.95G
    uint8_t* row = bytes_.address<uint8_t>() + y * bytes_per_row_;
103
1.95G
    return JXL_ASSUME_ALIGNED(row, 64);
104
1.95G
  }
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
17.2M
  Plane() = default;
jxl::Plane<float>::Plane()
Line
Count
Source
145
12.6M
  Plane() = default;
jxl::Plane<int>::Plane()
Line
Count
Source
145
3.85M
  Plane() = default;
jxl::Plane<unsigned char>::Plane()
Line
Count
Source
145
199k
  Plane() = default;
jxl::Plane<signed char>::Plane()
Line
Count
Source
145
280k
  Plane() = default;
jxl::Plane<short>::Plane()
Line
Count
Source
145
189k
  Plane() = default;
Unexecuted instantiation: jxl::Plane<hwy::float16_t>::Plane()
Unexecuted instantiation: jxl::Plane<unsigned int>::Plane()
146
147
  static StatusOr<Plane> Create(JxlMemoryManager* memory_manager,
148
                                const size_t xsize, const size_t ysize,
149
22.5M
                                const size_t pre_padding = 0) {
150
22.5M
    static_assert(
151
22.5M
        sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8,
152
22.5M
        "Only 1/2/4/8-byte samples are supported");
153
22.5M
    uint32_t xsize32 = static_cast<uint32_t>(xsize);
154
22.5M
    uint32_t ysize32 = static_cast<uint32_t>(ysize);
155
22.5M
    JXL_ENSURE(xsize32 == xsize);
156
22.5M
    JXL_ENSURE(ysize32 == ysize);
157
22.5M
    Plane plane(xsize32, ysize32, sizeof(T));
158
22.5M
    JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager, pre_padding));
159
22.5M
    return plane;
160
22.5M
  }
jxl::Plane<float>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long, unsigned long)
Line
Count
Source
149
17.1M
                                const size_t pre_padding = 0) {
150
17.1M
    static_assert(
151
17.1M
        sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8,
152
17.1M
        "Only 1/2/4/8-byte samples are supported");
153
17.1M
    uint32_t xsize32 = static_cast<uint32_t>(xsize);
154
17.1M
    uint32_t ysize32 = static_cast<uint32_t>(ysize);
155
17.1M
    JXL_ENSURE(xsize32 == xsize);
156
17.1M
    JXL_ENSURE(ysize32 == ysize);
157
17.1M
    Plane plane(xsize32, ysize32, sizeof(T));
158
17.1M
    JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager, pre_padding));
159
17.1M
    return plane;
160
17.1M
  }
jxl::Plane<int>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long, unsigned long)
Line
Count
Source
149
4.81M
                                const size_t pre_padding = 0) {
150
4.81M
    static_assert(
151
4.81M
        sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8,
152
4.81M
        "Only 1/2/4/8-byte samples are supported");
153
4.81M
    uint32_t xsize32 = static_cast<uint32_t>(xsize);
154
4.81M
    uint32_t ysize32 = static_cast<uint32_t>(ysize);
155
4.81M
    JXL_ENSURE(xsize32 == xsize);
156
4.81M
    JXL_ENSURE(ysize32 == ysize);
157
4.81M
    Plane plane(xsize32, ysize32, sizeof(T));
158
4.81M
    JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager, pre_padding));
159
4.81M
    return plane;
160
4.81M
  }
jxl::Plane<short>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long, unsigned long)
Line
Count
Source
149
47.4k
                                const size_t pre_padding = 0) {
150
47.4k
    static_assert(
151
47.4k
        sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8,
152
47.4k
        "Only 1/2/4/8-byte samples are supported");
153
47.4k
    uint32_t xsize32 = static_cast<uint32_t>(xsize);
154
47.4k
    uint32_t ysize32 = static_cast<uint32_t>(ysize);
155
47.4k
    JXL_ENSURE(xsize32 == xsize);
156
47.4k
    JXL_ENSURE(ysize32 == ysize);
157
47.4k
    Plane plane(xsize32, ysize32, sizeof(T));
158
47.4k
    JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager, pre_padding));
159
47.4k
    return plane;
160
47.4k
  }
jxl::Plane<unsigned char>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long, unsigned long)
Line
Count
Source
149
332k
                                const size_t pre_padding = 0) {
150
332k
    static_assert(
151
332k
        sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8,
152
332k
        "Only 1/2/4/8-byte samples are supported");
153
332k
    uint32_t xsize32 = static_cast<uint32_t>(xsize);
154
332k
    uint32_t ysize32 = static_cast<uint32_t>(ysize);
155
332k
    JXL_ENSURE(xsize32 == xsize);
156
332k
    JXL_ENSURE(ysize32 == ysize);
157
332k
    Plane plane(xsize32, ysize32, sizeof(T));
158
332k
    JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager, pre_padding));
159
332k
    return plane;
160
332k
  }
jxl::Plane<signed char>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long, unsigned long)
Line
Count
Source
149
221k
                                const size_t pre_padding = 0) {
150
221k
    static_assert(
151
221k
        sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8,
152
221k
        "Only 1/2/4/8-byte samples are supported");
153
221k
    uint32_t xsize32 = static_cast<uint32_t>(xsize);
154
221k
    uint32_t ysize32 = static_cast<uint32_t>(ysize);
155
221k
    JXL_ENSURE(xsize32 == xsize);
156
221k
    JXL_ENSURE(ysize32 == ysize);
157
221k
    Plane plane(xsize32, ysize32, sizeof(T));
158
221k
    JXL_RETURN_IF_ERROR(plane.Allocate(memory_manager, pre_padding));
159
221k
    return plane;
160
221k
  }
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)
161
162
1.31G
  JXL_INLINE T* Row(const size_t y) { return static_cast<T*>(VoidRow(y)); }
jxl::Plane<int>::Row(unsigned long)
Line
Count
Source
162
1.01G
  JXL_INLINE T* Row(const size_t y) { return static_cast<T*>(VoidRow(y)); }
jxl::Plane<float>::Row(unsigned long)
Line
Count
Source
162
294M
  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
1.71M
  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
162
1.97M
  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)
163
164
  // Returns pointer to const (see above).
165
613M
  JXL_INLINE const T* Row(const size_t y) const {
166
613M
    return static_cast<const T*>(VoidRow(y));
167
613M
  }
jxl::Plane<int>::Row(unsigned long) const
Line
Count
Source
165
603M
  JXL_INLINE const T* Row(const size_t y) const {
166
603M
    return static_cast<const T*>(VoidRow(y));
167
603M
  }
jxl::Plane<float>::Row(unsigned long) const
Line
Count
Source
165
9.54M
  JXL_INLINE const T* Row(const size_t y) const {
166
9.54M
    return static_cast<const T*>(VoidRow(y));
167
9.54M
  }
Unexecuted instantiation: jxl::Plane<unsigned char>::Row(unsigned long) const
168
169
  // Documents that the access is const.
170
31.9M
  JXL_INLINE const T* ConstRow(const size_t y) const {
171
31.9M
    return static_cast<const T*>(VoidRow(y));
172
31.9M
  }
jxl::Plane<float>::ConstRow(unsigned long) const
Line
Count
Source
170
24.1M
  JXL_INLINE const T* ConstRow(const size_t y) const {
171
24.1M
    return static_cast<const T*>(VoidRow(y));
172
24.1M
  }
jxl::Plane<unsigned char>::ConstRow(unsigned long) const
Line
Count
Source
170
3.35M
  JXL_INLINE const T* ConstRow(const size_t y) const {
171
3.35M
    return static_cast<const T*>(VoidRow(y));
172
3.35M
  }
jxl::Plane<int>::ConstRow(unsigned long) const
Line
Count
Source
170
3.09M
  JXL_INLINE const T* ConstRow(const size_t y) const {
171
3.09M
    return static_cast<const T*>(VoidRow(y));
172
3.09M
  }
jxl::Plane<signed char>::ConstRow(unsigned long) const
Line
Count
Source
170
1.28M
  JXL_INLINE const T* ConstRow(const size_t y) const {
171
1.28M
    return static_cast<const T*>(VoidRow(y));
172
1.28M
  }
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
53.2M
  JXL_INLINE ptrdiff_t PixelsPerRow() const {
178
53.2M
    return static_cast<ptrdiff_t>(bytes_per_row_ / sizeof(T));
179
53.2M
  }
jxl::Plane<int>::PixelsPerRow() const
Line
Count
Source
177
51.6M
  JXL_INLINE ptrdiff_t PixelsPerRow() const {
178
51.6M
    return static_cast<ptrdiff_t>(bytes_per_row_ / sizeof(T));
179
51.6M
  }
jxl::Plane<unsigned char>::PixelsPerRow() const
Line
Count
Source
177
123k
  JXL_INLINE ptrdiff_t PixelsPerRow() const {
178
123k
    return static_cast<ptrdiff_t>(bytes_per_row_ / sizeof(T));
179
123k
  }
Unexecuted instantiation: jxl::Plane<short>::PixelsPerRow() const
jxl::Plane<float>::PixelsPerRow() const
Line
Count
Source
177
1.47M
  JXL_INLINE ptrdiff_t PixelsPerRow() const {
178
1.47M
    return static_cast<ptrdiff_t>(bytes_per_row_ / sizeof(T));
179
1.47M
  }
180
181
 private:
182
  Plane(uint32_t xsize, uint32_t ysize, size_t sizeof_t)
183
22.5M
      : detail::PlaneBase(xsize, ysize, sizeof_t) {}
jxl::Plane<int>::Plane(unsigned int, unsigned int, unsigned long)
Line
Count
Source
183
4.81M
      : detail::PlaneBase(xsize, ysize, sizeof_t) {}
jxl::Plane<float>::Plane(unsigned int, unsigned int, unsigned long)
Line
Count
Source
183
17.1M
      : detail::PlaneBase(xsize, ysize, sizeof_t) {}
jxl::Plane<short>::Plane(unsigned int, unsigned int, unsigned long)
Line
Count
Source
183
47.4k
      : detail::PlaneBase(xsize, ysize, sizeof_t) {}
jxl::Plane<unsigned char>::Plane(unsigned int, unsigned int, unsigned long)
Line
Count
Source
183
332k
      : detail::PlaneBase(xsize, ysize, sizeof_t) {}
jxl::Plane<signed char>::Plane(unsigned int, unsigned int, unsigned long)
Line
Count
Source
183
221k
      : 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)
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
193
// Currently, we abuse Image to either refer to an image that owns its storage
194
// or one that doesn't. In similar vein, we abuse Image* function parameters to
195
// either mean "assign to me" or "fill the provided image with data".
196
// Hopefully, the "assign to me" meaning will go away and most images in the
197
// codebase will not be backed by own storage. When this happens we can redesign
198
// Image to be a non-storage-holding view class and introduce BackedImage in
199
// those places that actually need it.
200
201
// NOTE: we can't use Image as a view because invariants are violated
202
// (alignment and the presence of padding before/after each "row").
203
204
// A bundle of 3 same-sized images. Typically constructed by moving from three
205
// rvalue references to Image. To overwrite an existing Image3 using
206
// single-channel producers, we also need access to Image*. Constructing
207
// temporary non-owning Image pointing to one plane of an existing Image3 risks
208
// dangling references, especially if the wrapper is moved. Therefore, we
209
// store an array of Image (which are compact enough that size is not a concern)
210
// and provide Plane+Row accessors.
211
template <typename ComponentType>
212
class Image3 {
213
 public:
214
  using T = ComponentType;
215
  using PlaneT = jxl::Plane<T>;
216
  static constexpr size_t kNumPlanes = 3;
217
218
1.90M
  Image3() : planes_{PlaneT(), PlaneT(), PlaneT()} {}
jxl::Image3<float>::Image3()
Line
Count
Source
218
704k
  Image3() : planes_{PlaneT(), PlaneT(), PlaneT()} {}
jxl::Image3<int>::Image3()
Line
Count
Source
218
1.18M
  Image3() : planes_{PlaneT(), PlaneT(), PlaneT()} {}
jxl::Image3<short>::Image3()
Line
Count
Source
218
15.8k
  Image3() : planes_{PlaneT(), PlaneT(), PlaneT()} {}
219
220
  // Copy construction/assignment is forbidden to avoid inadvertent copies,
221
  // which can be very expensive. Use CopyImageTo instead.
222
  Image3(const Image3& other) = delete;
223
  Image3& operator=(const Image3& other) = delete;
224
225
624k
  Image3(Image3&& other) noexcept {
226
2.49M
    for (size_t i = 0; i < kNumPlanes; i++) {
227
1.87M
      planes_[i] = std::move(other.planes_[i]);
228
1.87M
    }
229
624k
  }
jxl::Image3<short>::Image3(jxl::Image3<short>&&)
Line
Count
Source
225
31.6k
  Image3(Image3&& other) noexcept {
226
126k
    for (size_t i = 0; i < kNumPlanes; i++) {
227
94.9k
      planes_[i] = std::move(other.planes_[i]);
228
94.9k
    }
229
31.6k
  }
jxl::Image3<int>::Image3(jxl::Image3<int>&&)
Line
Count
Source
225
58.2k
  Image3(Image3&& other) noexcept {
226
233k
    for (size_t i = 0; i < kNumPlanes; i++) {
227
174k
      planes_[i] = std::move(other.planes_[i]);
228
174k
    }
229
58.2k
  }
jxl::Image3<float>::Image3(jxl::Image3<float>&&)
Line
Count
Source
225
534k
  Image3(Image3&& other) noexcept {
226
2.13M
    for (size_t i = 0; i < kNumPlanes; i++) {
227
1.60M
      planes_[i] = std::move(other.planes_[i]);
228
1.60M
    }
229
534k
  }
Unexecuted instantiation: jxl::Image3<unsigned char>::Image3(jxl::Image3<unsigned char>&&)
230
619k
  Image3& operator=(Image3&& other) noexcept {
231
2.47M
    for (size_t i = 0; i < kNumPlanes; i++) {
232
1.85M
      planes_[i] = std::move(other.planes_[i]);
233
1.85M
    }
234
619k
    return *this;
235
619k
  }
jxl::Image3<float>::operator=(jxl::Image3<float>&&)
Line
Count
Source
230
574k
  Image3& operator=(Image3&& other) noexcept {
231
2.29M
    for (size_t i = 0; i < kNumPlanes; i++) {
232
1.72M
      planes_[i] = std::move(other.planes_[i]);
233
1.72M
    }
234
574k
    return *this;
235
574k
  }
jxl::Image3<short>::operator=(jxl::Image3<short>&&)
Line
Count
Source
230
15.8k
  Image3& operator=(Image3&& other) noexcept {
231
63.3k
    for (size_t i = 0; i < kNumPlanes; i++) {
232
47.4k
      planes_[i] = std::move(other.planes_[i]);
233
47.4k
    }
234
15.8k
    return *this;
235
15.8k
  }
jxl::Image3<int>::operator=(jxl::Image3<int>&&)
Line
Count
Source
230
29.1k
  Image3& operator=(Image3&& other) noexcept {
231
116k
    for (size_t i = 0; i < kNumPlanes; i++) {
232
87.4k
      planes_[i] = std::move(other.planes_[i]);
233
87.4k
    }
234
29.1k
    return *this;
235
29.1k
  }
236
237
  static StatusOr<Image3> Create(JxlMemoryManager* memory_manager,
238
308k
                                 const size_t xsize, const size_t ysize) {
239
308k
    JXL_ASSIGN_OR_RETURN(PlaneT plane0,
240
308k
                         PlaneT::Create(memory_manager, xsize, ysize));
241
308k
    JXL_ASSIGN_OR_RETURN(PlaneT plane1,
242
308k
                         PlaneT::Create(memory_manager, xsize, ysize));
243
308k
    JXL_ASSIGN_OR_RETURN(PlaneT plane2,
244
308k
                         PlaneT::Create(memory_manager, xsize, ysize));
245
308k
    return Image3(std::move(plane0), std::move(plane1), std::move(plane2));
246
308k
  }
jxl::Image3<float>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long)
Line
Count
Source
238
263k
                                 const size_t xsize, const size_t ysize) {
239
263k
    JXL_ASSIGN_OR_RETURN(PlaneT plane0,
240
263k
                         PlaneT::Create(memory_manager, xsize, ysize));
241
263k
    JXL_ASSIGN_OR_RETURN(PlaneT plane1,
242
263k
                         PlaneT::Create(memory_manager, xsize, ysize));
243
263k
    JXL_ASSIGN_OR_RETURN(PlaneT plane2,
244
263k
                         PlaneT::Create(memory_manager, xsize, ysize));
245
263k
    return Image3(std::move(plane0), std::move(plane1), std::move(plane2));
246
263k
  }
jxl::Image3<short>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long)
Line
Count
Source
238
15.8k
                                 const size_t xsize, const size_t ysize) {
239
15.8k
    JXL_ASSIGN_OR_RETURN(PlaneT plane0,
240
15.8k
                         PlaneT::Create(memory_manager, xsize, ysize));
241
15.8k
    JXL_ASSIGN_OR_RETURN(PlaneT plane1,
242
15.8k
                         PlaneT::Create(memory_manager, xsize, ysize));
243
15.8k
    JXL_ASSIGN_OR_RETURN(PlaneT plane2,
244
15.8k
                         PlaneT::Create(memory_manager, xsize, ysize));
245
15.8k
    return Image3(std::move(plane0), std::move(plane1), std::move(plane2));
246
15.8k
  }
jxl::Image3<int>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long)
Line
Count
Source
238
29.1k
                                 const size_t xsize, const size_t ysize) {
239
29.1k
    JXL_ASSIGN_OR_RETURN(PlaneT plane0,
240
29.1k
                         PlaneT::Create(memory_manager, xsize, ysize));
241
29.1k
    JXL_ASSIGN_OR_RETURN(PlaneT plane1,
242
29.1k
                         PlaneT::Create(memory_manager, xsize, ysize));
243
29.1k
    JXL_ASSIGN_OR_RETURN(PlaneT plane2,
244
29.1k
                         PlaneT::Create(memory_manager, xsize, ysize));
245
29.1k
    return Image3(std::move(plane0), std::move(plane1), std::move(plane2));
246
29.1k
  }
Unexecuted instantiation: jxl::Image3<unsigned char>::Create(JxlMemoryManagerStruct*, unsigned long, unsigned long)
247
248
  // Returns row pointer; usage: PlaneRow(idx_plane, y)[x] = val.
249
59.6M
  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
59.6M
    PlaneRowBoundsCheck(c, y);
253
59.6M
    const size_t row_offset = y * planes_[0].bytes_per_row();
254
59.6M
    void* row = planes_[c].bytes() + row_offset;
255
59.6M
    return static_cast<T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64));
256
59.6M
  }
jxl::Image3<int>::PlaneRow(unsigned long, unsigned long)
Line
Count
Source
249
1.93M
  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
1.93M
    PlaneRowBoundsCheck(c, y);
253
1.93M
    const size_t row_offset = y * planes_[0].bytes_per_row();
254
1.93M
    void* row = planes_[c].bytes() + row_offset;
255
1.93M
    return static_cast<T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64));
256
1.93M
  }
jxl::Image3<float>::PlaneRow(unsigned long, unsigned long)
Line
Count
Source
249
57.7M
  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
57.7M
    PlaneRowBoundsCheck(c, y);
253
57.7M
    const size_t row_offset = y * planes_[0].bytes_per_row();
254
57.7M
    void* row = planes_[c].bytes() + row_offset;
255
57.7M
    return static_cast<T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64));
256
57.7M
  }
jxl::Image3<short>::PlaneRow(unsigned long, unsigned long)
Line
Count
Source
249
10.3k
  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
10.3k
    PlaneRowBoundsCheck(c, y);
253
10.3k
    const size_t row_offset = y * planes_[0].bytes_per_row();
254
10.3k
    void* row = planes_[c].bytes() + row_offset;
255
10.3k
    return static_cast<T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64));
256
10.3k
  }
Unexecuted instantiation: jxl::Image3<unsigned char>::PlaneRow(unsigned long, unsigned long)
257
258
  // Returns const row pointer; usage: val = PlaneRow(idx_plane, y)[x].
259
46.3M
  JXL_INLINE const T* PlaneRow(const size_t c, const size_t y) const {
260
46.3M
    PlaneRowBoundsCheck(c, y);
261
46.3M
    const size_t row_offset = y * planes_[0].bytes_per_row();
262
46.3M
    const void* row = planes_[c].bytes() + row_offset;
263
46.3M
    return static_cast<const T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64));
264
46.3M
  }
jxl::Image3<int>::PlaneRow(unsigned long, unsigned long) const
Line
Count
Source
259
1.79M
  JXL_INLINE const T* PlaneRow(const size_t c, const size_t y) const {
260
1.79M
    PlaneRowBoundsCheck(c, y);
261
1.79M
    const size_t row_offset = y * planes_[0].bytes_per_row();
262
1.79M
    const void* row = planes_[c].bytes() + row_offset;
263
1.79M
    return static_cast<const T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64));
264
1.79M
  }
Unexecuted instantiation: jxl::Image3<short>::PlaneRow(unsigned long, unsigned long) const
jxl::Image3<float>::PlaneRow(unsigned long, unsigned long) const
Line
Count
Source
259
44.5M
  JXL_INLINE const T* PlaneRow(const size_t c, const size_t y) const {
260
44.5M
    PlaneRowBoundsCheck(c, y);
261
44.5M
    const size_t row_offset = y * planes_[0].bytes_per_row();
262
44.5M
    const void* row = planes_[c].bytes() + row_offset;
263
44.5M
    return static_cast<const T * JXL_RESTRICT>(JXL_ASSUME_ALIGNED(row, 64));
264
44.5M
  }
Unexecuted instantiation: jxl::Image3<unsigned char>::PlaneRow(unsigned long, unsigned long) const
265
266
  // Returns const row pointer, even if called from a non-const Image3.
267
46.3M
  JXL_INLINE const T* ConstPlaneRow(const size_t c, const size_t y) const {
268
46.3M
    PlaneRowBoundsCheck(c, y);
269
46.3M
    return PlaneRow(c, y);
270
46.3M
  }
jxl::Image3<float>::ConstPlaneRow(unsigned long, unsigned long) const
Line
Count
Source
267
44.5M
  JXL_INLINE const T* ConstPlaneRow(const size_t c, const size_t y) const {
268
44.5M
    PlaneRowBoundsCheck(c, y);
269
44.5M
    return PlaneRow(c, y);
270
44.5M
  }
jxl::Image3<int>::ConstPlaneRow(unsigned long, unsigned long) const
Line
Count
Source
267
1.79M
  JXL_INLINE const T* ConstPlaneRow(const size_t c, const size_t y) const {
268
1.79M
    PlaneRowBoundsCheck(c, y);
269
1.79M
    return PlaneRow(c, y);
270
1.79M
  }
Unexecuted instantiation: jxl::Image3<unsigned char>::ConstPlaneRow(unsigned long, unsigned long) const
271
272
253k
  JXL_INLINE const PlaneT& Plane(size_t idx) const { return planes_[idx]; }
273
274
20.2k
  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)
jxl::Image3<float>::Plane(unsigned long)
Line
Count
Source
274
20.2k
  JXL_INLINE PlaneT& Plane(size_t idx) { return planes_[idx]; }
275
276
7.55k
  void Swap(Image3& other) {
277
30.2k
    for (size_t c = 0; c < 3; ++c) {
278
22.6k
      other.planes_[c].Swap(planes_[c]);
279
22.6k
    }
280
7.55k
  }
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
1.13k
  Status ShrinkTo(const size_t xsize, const size_t ysize) {
287
3.40k
    for (PlaneT& plane : planes_) {
288
3.40k
      JXL_RETURN_IF_ERROR(plane.ShrinkTo(xsize, ysize));
289
3.40k
    }
290
1.13k
    return true;
291
1.13k
  }
292
293
  // Sizes of all three images are guaranteed to be equal.
294
2.55k
  JXL_INLINE JxlMemoryManager* memory_manager() const {
295
2.55k
    return planes_[0].memory_manager();
296
2.55k
  }
jxl::Image3<float>::memory_manager() const
Line
Count
Source
294
2.55k
  JXL_INLINE JxlMemoryManager* memory_manager() const {
295
2.55k
    return planes_[0].memory_manager();
296
2.55k
  }
Unexecuted instantiation: jxl::Image3<unsigned char>::memory_manager() const
297
113M
  JXL_INLINE size_t xsize() const { return planes_[0].xsize(); }
jxl::Image3<int>::xsize() const
Line
Count
Source
297
52.4k
  JXL_INLINE size_t xsize() const { return planes_[0].xsize(); }
jxl::Image3<float>::xsize() const
Line
Count
Source
297
113M
  JXL_INLINE size_t xsize() const { return planes_[0].xsize(); }
jxl::Image3<short>::xsize() const
Line
Count
Source
297
31.8k
  JXL_INLINE size_t xsize() const { return planes_[0].xsize(); }
Unexecuted instantiation: jxl::Image3<unsigned char>::xsize() const
298
159M
  JXL_INLINE size_t ysize() const { return planes_[0].ysize(); }
jxl::Image3<int>::ysize() const
Line
Count
Source
298
5.51M
  JXL_INLINE size_t ysize() const { return planes_[0].ysize(); }
jxl::Image3<float>::ysize() const
Line
Count
Source
298
154M
  JXL_INLINE size_t ysize() const { return planes_[0].ysize(); }
jxl::Image3<short>::ysize() const
Line
Count
Source
298
10.8k
  JXL_INLINE size_t ysize() const { return planes_[0].ysize(); }
Unexecuted instantiation: jxl::Image3<unsigned char>::ysize() const
299
  // Returns offset [bytes] from one row to the next row of the same plane.
300
  // WARNING: this must NOT be used to determine xsize, nor for copying rows -
301
  // the valid xsize may be much less.
302
  JXL_INLINE size_t bytes_per_row() const { return planes_[0].bytes_per_row(); }
303
  // Returns number of pixels (some of which are padding) per row. Useful for
304
  // computing other rows via pointer arithmetic. WARNING: this must NOT be used
305
  // to determine xsize.
306
126k
  JXL_INLINE ptrdiff_t PixelsPerRow() const { return planes_[0].PixelsPerRow(); }
jxl::Image3<int>::PixelsPerRow() const
Line
Count
Source
306
82.4k
  JXL_INLINE ptrdiff_t PixelsPerRow() const { return planes_[0].PixelsPerRow(); }
Unexecuted instantiation: jxl::Image3<short>::PixelsPerRow() const
jxl::Image3<float>::PixelsPerRow() const
Line
Count
Source
306
43.6k
  JXL_INLINE ptrdiff_t PixelsPerRow() const { return planes_[0].PixelsPerRow(); }
307
308
 private:
309
308k
  Image3(PlaneT&& plane0, PlaneT&& plane1, PlaneT&& plane2) {
310
308k
    planes_[0] = std::move(plane0);
311
308k
    planes_[1] = std::move(plane1);
312
308k
    planes_[2] = std::move(plane2);
313
308k
  }
jxl::Image3<short>::Image3(jxl::Plane<short>&&, jxl::Plane<short>&&, jxl::Plane<short>&&)
Line
Count
Source
309
15.8k
  Image3(PlaneT&& plane0, PlaneT&& plane1, PlaneT&& plane2) {
310
15.8k
    planes_[0] = std::move(plane0);
311
15.8k
    planes_[1] = std::move(plane1);
312
15.8k
    planes_[2] = std::move(plane2);
313
15.8k
  }
jxl::Image3<int>::Image3(jxl::Plane<int>&&, jxl::Plane<int>&&, jxl::Plane<int>&&)
Line
Count
Source
309
29.1k
  Image3(PlaneT&& plane0, PlaneT&& plane1, PlaneT&& plane2) {
310
29.1k
    planes_[0] = std::move(plane0);
311
29.1k
    planes_[1] = std::move(plane1);
312
29.1k
    planes_[2] = std::move(plane2);
313
29.1k
  }
jxl::Image3<float>::Image3(jxl::Plane<float>&&, jxl::Plane<float>&&, jxl::Plane<float>&&)
Line
Count
Source
309
263k
  Image3(PlaneT&& plane0, PlaneT&& plane1, PlaneT&& plane2) {
310
263k
    planes_[0] = std::move(plane0);
311
263k
    planes_[1] = std::move(plane1);
312
263k
    planes_[2] = std::move(plane2);
313
263k
  }
Unexecuted instantiation: jxl::Image3<unsigned char>::Image3(jxl::Plane<unsigned char>&&, jxl::Plane<unsigned char>&&, jxl::Plane<unsigned char>&&)
314
315
152M
  void PlaneRowBoundsCheck(const size_t c, const size_t y) const {
316
152M
    JXL_DASSERT(c < kNumPlanes && y < ysize());
317
152M
  }
jxl::Image3<int>::PlaneRowBoundsCheck(unsigned long, unsigned long) const
Line
Count
Source
315
5.51M
  void PlaneRowBoundsCheck(const size_t c, const size_t y) const {
316
5.51M
    JXL_DASSERT(c < kNumPlanes && y < ysize());
317
5.51M
  }
jxl::Image3<float>::PlaneRowBoundsCheck(unsigned long, unsigned long) const
Line
Count
Source
315
146M
  void PlaneRowBoundsCheck(const size_t c, const size_t y) const {
316
146M
    JXL_DASSERT(c < kNumPlanes && y < ysize());
317
146M
  }
jxl::Image3<short>::PlaneRowBoundsCheck(unsigned long, unsigned long) const
Line
Count
Source
315
10.3k
  void PlaneRowBoundsCheck(const size_t c, const size_t y) const {
316
10.3k
    JXL_DASSERT(c < kNumPlanes && y < ysize());
317
10.3k
  }
Unexecuted instantiation: jxl::Image3<unsigned char>::PlaneRowBoundsCheck(unsigned long, unsigned long) const
318
319
  PlaneT planes_[kNumPlanes];
320
};
321
322
using Image3B = Image3<uint8_t>;
323
using Image3S = Image3<int16_t>;
324
using Image3U = Image3<uint16_t>;
325
using Image3I = Image3<int32_t>;
326
using Image3F = Image3<float>;
327
328
}  // namespace jxl
329
330
#endif  // LIB_JXL_IMAGE_H_