/src/libjxl/lib/jxl/image_ops.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) the JPEG XL Project Authors. All rights reserved. |
2 | | // |
3 | | // Use of this source code is governed by a BSD-style |
4 | | // license that can be found in the LICENSE file. |
5 | | |
6 | | #ifndef LIB_JXL_IMAGE_OPS_H_ |
7 | | #define LIB_JXL_IMAGE_OPS_H_ |
8 | | |
9 | | // Operations on images. |
10 | | |
11 | | #include <algorithm> |
12 | | #include <array> |
13 | | #include <limits> |
14 | | #include <vector> |
15 | | |
16 | | #include "lib/jxl/base/profiler.h" |
17 | | #include "lib/jxl/base/status.h" |
18 | | #include "lib/jxl/common.h" |
19 | | #include "lib/jxl/image.h" |
20 | | |
21 | | namespace jxl { |
22 | | |
23 | | template <typename T> |
24 | 1.45k | void CopyImageTo(const Plane<T>& from, Plane<T>* JXL_RESTRICT to) { |
25 | 1.45k | PROFILER_ZONE("CopyImage1"); |
26 | 1.45k | JXL_ASSERT(SameSize(from, *to)); |
27 | 1.45k | if (from.ysize() == 0 || from.xsize() == 0) return; |
28 | 95.7k | for (size_t y = 0; y < from.ysize(); ++y) { |
29 | 94.3k | const T* JXL_RESTRICT row_from = from.ConstRow(y); |
30 | 94.3k | T* JXL_RESTRICT row_to = to->Row(y); |
31 | 94.3k | memcpy(row_to, row_from, from.xsize() * sizeof(T)); |
32 | 94.3k | } |
33 | 1.40k | } Unexecuted instantiation: void jxl::CopyImageTo<float>(jxl::Plane<float> const&, jxl::Plane<float>*) void jxl::CopyImageTo<int>(jxl::Plane<int> const&, jxl::Plane<int>*) Line | Count | Source | 24 | 1.45k | void CopyImageTo(const Plane<T>& from, Plane<T>* JXL_RESTRICT to) { | 25 | 1.45k | PROFILER_ZONE("CopyImage1"); | 26 | 1.45k | JXL_ASSERT(SameSize(from, *to)); | 27 | 1.45k | if (from.ysize() == 0 || from.xsize() == 0) return; | 28 | 95.7k | for (size_t y = 0; y < from.ysize(); ++y) { | 29 | 94.3k | const T* JXL_RESTRICT row_from = from.ConstRow(y); | 30 | 94.3k | T* JXL_RESTRICT row_to = to->Row(y); | 31 | 94.3k | memcpy(row_to, row_from, from.xsize() * sizeof(T)); | 32 | 94.3k | } | 33 | 1.40k | } |
|
34 | | |
35 | | // DEPRECATED - prefer to preallocate result. |
36 | | template <typename T> |
37 | 1.18k | Plane<T> CopyImage(const Plane<T>& from) { |
38 | 1.18k | Plane<T> to(from.xsize(), from.ysize()); |
39 | 1.18k | CopyImageTo(from, &to); |
40 | 1.18k | return to; |
41 | 1.18k | } Unexecuted instantiation: jxl::Plane<float> jxl::CopyImage<float>(jxl::Plane<float> const&) jxl::Plane<int> jxl::CopyImage<int>(jxl::Plane<int> const&) Line | Count | Source | 37 | 1.18k | Plane<T> CopyImage(const Plane<T>& from) { | 38 | 1.18k | Plane<T> to(from.xsize(), from.ysize()); | 39 | 1.18k | CopyImageTo(from, &to); | 40 | 1.18k | return to; | 41 | 1.18k | } |
|
42 | | |
43 | | // Copies `from:rect_from` to `to:rect_to`. |
44 | | template <typename T> |
45 | | void CopyImageTo(const Rect& rect_from, const Plane<T>& from, |
46 | 201k | const Rect& rect_to, Plane<T>* JXL_RESTRICT to) { |
47 | 201k | PROFILER_ZONE("CopyImageR"); |
48 | 201k | JXL_DASSERT(SameSize(rect_from, rect_to)); |
49 | 201k | JXL_DASSERT(rect_from.IsInside(from)); |
50 | 201k | JXL_DASSERT(rect_to.IsInside(*to)); |
51 | 201k | if (rect_from.xsize() == 0) return; |
52 | 5.52M | for (size_t y = 0; y < rect_from.ysize(); ++y) { |
53 | 5.34M | const T* JXL_RESTRICT row_from = rect_from.ConstRow(from, y); |
54 | 5.34M | T* JXL_RESTRICT row_to = rect_to.Row(to, y); |
55 | 5.34M | memcpy(row_to, row_from, rect_from.xsize() * sizeof(T)); |
56 | 5.34M | } |
57 | 179k | } void jxl::CopyImageTo<float>(jxl::RectT<unsigned long> const&, jxl::Plane<float> const&, jxl::RectT<unsigned long> const&, jxl::Plane<float>*) Line | Count | Source | 46 | 174k | const Rect& rect_to, Plane<T>* JXL_RESTRICT to) { | 47 | 174k | PROFILER_ZONE("CopyImageR"); | 48 | 174k | JXL_DASSERT(SameSize(rect_from, rect_to)); | 49 | 174k | JXL_DASSERT(rect_from.IsInside(from)); | 50 | 174k | JXL_DASSERT(rect_to.IsInside(*to)); | 51 | 174k | if (rect_from.xsize() == 0) return; | 52 | 4.43M | for (size_t y = 0; y < rect_from.ysize(); ++y) { | 53 | 4.28M | const T* JXL_RESTRICT row_from = rect_from.ConstRow(from, y); | 54 | 4.28M | T* JXL_RESTRICT row_to = rect_to.Row(to, y); | 55 | 4.28M | memcpy(row_to, row_from, rect_from.xsize() * sizeof(T)); | 56 | 4.28M | } | 57 | 153k | } |
void jxl::CopyImageTo<int>(jxl::RectT<unsigned long> const&, jxl::Plane<int> const&, jxl::RectT<unsigned long> const&, jxl::Plane<int>*) Line | Count | Source | 46 | 26.9k | const Rect& rect_to, Plane<T>* JXL_RESTRICT to) { | 47 | 26.9k | PROFILER_ZONE("CopyImageR"); | 48 | 26.9k | JXL_DASSERT(SameSize(rect_from, rect_to)); | 49 | 26.9k | JXL_DASSERT(rect_from.IsInside(from)); | 50 | 26.9k | JXL_DASSERT(rect_to.IsInside(*to)); | 51 | 26.9k | if (rect_from.xsize() == 0) return; | 52 | 1.09M | for (size_t y = 0; y < rect_from.ysize(); ++y) { | 53 | 1.06M | const T* JXL_RESTRICT row_from = rect_from.ConstRow(from, y); | 54 | 1.06M | T* JXL_RESTRICT row_to = rect_to.Row(to, y); | 55 | 1.06M | memcpy(row_to, row_from, rect_from.xsize() * sizeof(T)); | 56 | 1.06M | } | 57 | 26.9k | } |
|
58 | | |
59 | | // DEPRECATED - Returns a copy of the "image" pixels that lie in "rect". |
60 | | template <typename T> |
61 | | Plane<T> CopyImage(const Rect& rect, const Plane<T>& image) { |
62 | | Plane<T> copy(rect.xsize(), rect.ysize()); |
63 | | CopyImageTo(rect, image, ©); |
64 | | return copy; |
65 | | } |
66 | | |
67 | | // Copies `from:rect_from` to `to:rect_to`. |
68 | | template <typename T> |
69 | | void CopyImageTo(const Rect& rect_from, const Image3<T>& from, |
70 | 0 | const Rect& rect_to, Image3<T>* JXL_RESTRICT to) { |
71 | 0 | PROFILER_ZONE("CopyImageR"); |
72 | 0 | JXL_ASSERT(SameSize(rect_from, rect_to)); |
73 | 0 | for (size_t c = 0; c < 3; c++) { |
74 | 0 | CopyImageTo(rect_from, from.Plane(c), rect_to, &to->Plane(c)); |
75 | 0 | } |
76 | 0 | } |
77 | | |
78 | | template <typename T, typename U> |
79 | | void ConvertPlaneAndClamp(const Rect& rect_from, const Plane<T>& from, |
80 | 10.9k | const Rect& rect_to, Plane<U>* JXL_RESTRICT to) { |
81 | 10.9k | PROFILER_ZONE("ConvertPlane"); |
82 | 10.9k | JXL_ASSERT(SameSize(rect_from, rect_to)); |
83 | 10.9k | using M = decltype(T() + U()); |
84 | 84.0k | for (size_t y = 0; y < rect_to.ysize(); ++y) { |
85 | 73.1k | const T* JXL_RESTRICT row_from = rect_from.ConstRow(from, y); |
86 | 73.1k | U* JXL_RESTRICT row_to = rect_to.Row(to, y); |
87 | 341k | for (size_t x = 0; x < rect_to.xsize(); ++x) { |
88 | 268k | row_to[x] = |
89 | 268k | std::min<M>(std::max<M>(row_from[x], std::numeric_limits<U>::min()), |
90 | 268k | std::numeric_limits<U>::max()); |
91 | 268k | } |
92 | 73.1k | } |
93 | 10.9k | } |
94 | | |
95 | | // Copies `from` to `to`. |
96 | | template <typename T> |
97 | 0 | void CopyImageTo(const T& from, T* JXL_RESTRICT to) { |
98 | 0 | return CopyImageTo(Rect(from), from, Rect(*to), to); |
99 | 0 | } |
100 | | |
101 | | // Copies `from:rect_from` to `to`. |
102 | | template <typename T> |
103 | | void CopyImageTo(const Rect& rect_from, const T& from, T* JXL_RESTRICT to) { |
104 | | return CopyImageTo(rect_from, from, Rect(*to), to); |
105 | | } |
106 | | |
107 | | // Copies `from` to `to:rect_to`. |
108 | | template <typename T> |
109 | 0 | void CopyImageTo(const T& from, const Rect& rect_to, T* JXL_RESTRICT to) { |
110 | 0 | return CopyImageTo(Rect(from), from, rect_to, to); |
111 | 0 | } |
112 | | |
113 | | // Copies `from:rect_from` to `to:rect_to`; also copies `padding` pixels of |
114 | | // border around `from:rect_from`, in all directions, whenever they are inside |
115 | | // the first image. |
116 | | template <typename T> |
117 | | void CopyImageToWithPadding(const Rect& from_rect, const T& from, |
118 | 0 | size_t padding, const Rect& to_rect, T* to) { |
119 | 0 | size_t xextra0 = std::min(padding, from_rect.x0()); |
120 | 0 | size_t xextra1 = |
121 | 0 | std::min(padding, from.xsize() - from_rect.x0() - from_rect.xsize()); |
122 | 0 | size_t yextra0 = std::min(padding, from_rect.y0()); |
123 | 0 | size_t yextra1 = |
124 | 0 | std::min(padding, from.ysize() - from_rect.y0() - from_rect.ysize()); |
125 | 0 | JXL_DASSERT(to_rect.x0() >= xextra0); |
126 | 0 | JXL_DASSERT(to_rect.y0() >= yextra0); |
127 | | |
128 | 0 | return CopyImageTo(Rect(from_rect.x0() - xextra0, from_rect.y0() - yextra0, |
129 | 0 | from_rect.xsize() + xextra0 + xextra1, |
130 | 0 | from_rect.ysize() + yextra0 + yextra1), |
131 | 0 | from, |
132 | 0 | Rect(to_rect.x0() - xextra0, to_rect.y0() - yextra0, |
133 | 0 | to_rect.xsize() + xextra0 + xextra1, |
134 | 0 | to_rect.ysize() + yextra0 + yextra1), |
135 | 0 | to); |
136 | 0 | } |
137 | | |
138 | | // DEPRECATED - prefer to preallocate result. |
139 | | template <typename T> |
140 | 0 | Image3<T> CopyImage(const Image3<T>& from) { |
141 | 0 | Image3<T> copy(from.xsize(), from.ysize()); |
142 | 0 | CopyImageTo(from, ©); |
143 | 0 | return copy; |
144 | 0 | } |
145 | | |
146 | | // DEPRECATED - prefer to preallocate result. |
147 | | template <typename T> |
148 | | Image3<T> CopyImage(const Rect& rect, const Image3<T>& from) { |
149 | | Image3<T> to(rect.xsize(), rect.ysize()); |
150 | | CopyImageTo(rect, from.Plane(0), to.Plane(0)); |
151 | | CopyImageTo(rect, from.Plane(1), to.Plane(1)); |
152 | | CopyImageTo(rect, from.Plane(2), to.Plane(2)); |
153 | | return to; |
154 | | } |
155 | | |
156 | | // Sets "thickness" pixels on each border to "value". This is faster than |
157 | | // initializing the entire image and overwriting valid/interior pixels. |
158 | | template <typename T> |
159 | | void SetBorder(const size_t thickness, const T value, Image3<T>* image) { |
160 | | const size_t xsize = image->xsize(); |
161 | | const size_t ysize = image->ysize(); |
162 | | // Top: fill entire row |
163 | | for (size_t c = 0; c < 3; ++c) { |
164 | | for (size_t y = 0; y < std::min(thickness, ysize); ++y) { |
165 | | T* JXL_RESTRICT row = image->PlaneRow(c, y); |
166 | | std::fill(row, row + xsize, value); |
167 | | } |
168 | | |
169 | | // Bottom: fill entire row |
170 | | for (size_t y = ysize - thickness; y < ysize; ++y) { |
171 | | T* JXL_RESTRICT row = image->PlaneRow(c, y); |
172 | | std::fill(row, row + xsize, value); |
173 | | } |
174 | | |
175 | | // Left/right: fill the 'columns' on either side, but only if the image is |
176 | | // big enough that they don't already belong to the top/bottom rows. |
177 | | if (ysize >= 2 * thickness) { |
178 | | for (size_t y = thickness; y < ysize - thickness; ++y) { |
179 | | T* JXL_RESTRICT row = image->PlaneRow(c, y); |
180 | | std::fill(row, row + thickness, value); |
181 | | std::fill(row + xsize - thickness, row + xsize, value); |
182 | | } |
183 | | } |
184 | | } |
185 | | } |
186 | | |
187 | | template <class ImageIn, class ImageOut> |
188 | | void Subtract(const ImageIn& image1, const ImageIn& image2, ImageOut* out) { |
189 | | using T = typename ImageIn::T; |
190 | | const size_t xsize = image1.xsize(); |
191 | | const size_t ysize = image1.ysize(); |
192 | | JXL_CHECK(xsize == image2.xsize()); |
193 | | JXL_CHECK(ysize == image2.ysize()); |
194 | | |
195 | | for (size_t y = 0; y < ysize; ++y) { |
196 | | const T* const JXL_RESTRICT row1 = image1.Row(y); |
197 | | const T* const JXL_RESTRICT row2 = image2.Row(y); |
198 | | T* const JXL_RESTRICT row_out = out->Row(y); |
199 | | for (size_t x = 0; x < xsize; ++x) { |
200 | | row_out[x] = row1[x] - row2[x]; |
201 | | } |
202 | | } |
203 | | } |
204 | | |
205 | | // In-place. |
206 | | template <typename Tin, typename Tout> |
207 | | void SubtractFrom(const Plane<Tin>& what, Plane<Tout>* to) { |
208 | | const size_t xsize = what.xsize(); |
209 | | const size_t ysize = what.ysize(); |
210 | | for (size_t y = 0; y < ysize; ++y) { |
211 | | const Tin* JXL_RESTRICT row_what = what.ConstRow(y); |
212 | | Tout* JXL_RESTRICT row_to = to->Row(y); |
213 | | for (size_t x = 0; x < xsize; ++x) { |
214 | | row_to[x] -= row_what[x]; |
215 | | } |
216 | | } |
217 | | } |
218 | | |
219 | | // In-place. |
220 | | template <typename Tin, typename Tout> |
221 | | void AddTo(const Plane<Tin>& what, Plane<Tout>* to) { |
222 | | const size_t xsize = what.xsize(); |
223 | | const size_t ysize = what.ysize(); |
224 | | for (size_t y = 0; y < ysize; ++y) { |
225 | | const Tin* JXL_RESTRICT row_what = what.ConstRow(y); |
226 | | Tout* JXL_RESTRICT row_to = to->Row(y); |
227 | | for (size_t x = 0; x < xsize; ++x) { |
228 | | row_to[x] += row_what[x]; |
229 | | } |
230 | | } |
231 | | } |
232 | | |
233 | | template <typename Tin, typename Tout> |
234 | | void AddTo(Rect rectFrom, const Plane<Tin>& what, Rect rectTo, |
235 | | Plane<Tout>* to) { |
236 | | JXL_ASSERT(SameSize(rectFrom, rectTo)); |
237 | | const size_t xsize = rectTo.xsize(); |
238 | | const size_t ysize = rectTo.ysize(); |
239 | | for (size_t y = 0; y < ysize; ++y) { |
240 | | const Tin* JXL_RESTRICT row_what = rectFrom.ConstRow(what, y); |
241 | | Tout* JXL_RESTRICT row_to = rectTo.Row(to, y); |
242 | | for (size_t x = 0; x < xsize; ++x) { |
243 | | row_to[x] += row_what[x]; |
244 | | } |
245 | | } |
246 | | } |
247 | | |
248 | | // Returns linear combination of two grayscale images. |
249 | | template <typename T> |
250 | | Plane<T> LinComb(const T lambda1, const Plane<T>& image1, const T lambda2, |
251 | | const Plane<T>& image2) { |
252 | | const size_t xsize = image1.xsize(); |
253 | | const size_t ysize = image1.ysize(); |
254 | | JXL_CHECK(xsize == image2.xsize()); |
255 | | JXL_CHECK(ysize == image2.ysize()); |
256 | | Plane<T> out(xsize, ysize); |
257 | | for (size_t y = 0; y < ysize; ++y) { |
258 | | const T* const JXL_RESTRICT row1 = image1.Row(y); |
259 | | const T* const JXL_RESTRICT row2 = image2.Row(y); |
260 | | T* const JXL_RESTRICT row_out = out.Row(y); |
261 | | for (size_t x = 0; x < xsize; ++x) { |
262 | | row_out[x] = lambda1 * row1[x] + lambda2 * row2[x]; |
263 | | } |
264 | | } |
265 | | return out; |
266 | | } |
267 | | |
268 | | // Returns a pixel-by-pixel multiplication of image by lambda. |
269 | | template <typename T> |
270 | | Plane<T> ScaleImage(const T lambda, const Plane<T>& image) { |
271 | | Plane<T> out(image.xsize(), image.ysize()); |
272 | | for (size_t y = 0; y < image.ysize(); ++y) { |
273 | | const T* const JXL_RESTRICT row = image.Row(y); |
274 | | T* const JXL_RESTRICT row_out = out.Row(y); |
275 | | for (size_t x = 0; x < image.xsize(); ++x) { |
276 | | row_out[x] = lambda * row[x]; |
277 | | } |
278 | | } |
279 | | return out; |
280 | | } |
281 | | |
282 | | // Multiplies image by lambda in-place |
283 | | template <typename T> |
284 | | void ScaleImage(const T lambda, Plane<T>* image) { |
285 | | for (size_t y = 0; y < image->ysize(); ++y) { |
286 | | T* const JXL_RESTRICT row = image->Row(y); |
287 | | for (size_t x = 0; x < image->xsize(); ++x) { |
288 | | row[x] = lambda * row[x]; |
289 | | } |
290 | | } |
291 | | } |
292 | | |
293 | | template <typename T> |
294 | | Plane<T> Product(const Plane<T>& a, const Plane<T>& b) { |
295 | | Plane<T> c(a.xsize(), a.ysize()); |
296 | | for (size_t y = 0; y < a.ysize(); ++y) { |
297 | | const T* const JXL_RESTRICT row_a = a.Row(y); |
298 | | const T* const JXL_RESTRICT row_b = b.Row(y); |
299 | | T* const JXL_RESTRICT row_c = c.Row(y); |
300 | | for (size_t x = 0; x < a.xsize(); ++x) { |
301 | | row_c[x] = row_a[x] * row_b[x]; |
302 | | } |
303 | | } |
304 | | return c; |
305 | | } |
306 | | |
307 | | float DotProduct(const ImageF& a, const ImageF& b); |
308 | | |
309 | | template <typename T> |
310 | 8.90k | void FillImage(const T value, Plane<T>* image) { |
311 | 530k | for (size_t y = 0; y < image->ysize(); ++y) { |
312 | 521k | T* const JXL_RESTRICT row = image->Row(y); |
313 | 23.0M | for (size_t x = 0; x < image->xsize(); ++x) { |
314 | 22.5M | row[x] = value; |
315 | 22.5M | } |
316 | 521k | } |
317 | 8.90k | } void jxl::FillImage<unsigned char>(unsigned char, jxl::Plane<unsigned char>*) Line | Count | Source | 310 | 2.92k | void FillImage(const T value, Plane<T>* image) { | 311 | 353k | for (size_t y = 0; y < image->ysize(); ++y) { | 312 | 350k | T* const JXL_RESTRICT row = image->Row(y); | 313 | 6.77M | for (size_t x = 0; x < image->xsize(); ++x) { | 314 | 6.42M | row[x] = value; | 315 | 6.42M | } | 316 | 350k | } | 317 | 2.92k | } |
Unexecuted instantiation: void jxl::FillImage<int>(int, jxl::Plane<int>*) void jxl::FillImage<float>(float, jxl::Plane<float>*) Line | Count | Source | 310 | 5.98k | void FillImage(const T value, Plane<T>* image) { | 311 | 177k | for (size_t y = 0; y < image->ysize(); ++y) { | 312 | 171k | T* const JXL_RESTRICT row = image->Row(y); | 313 | 16.3M | for (size_t x = 0; x < image->xsize(); ++x) { | 314 | 16.1M | row[x] = value; | 315 | 16.1M | } | 316 | 171k | } | 317 | 5.98k | } |
|
318 | | |
319 | | template <typename T> |
320 | 1.84M | void ZeroFillImage(Plane<T>* image) { |
321 | 1.84M | if (image->xsize() == 0) return; |
322 | 17.2M | for (size_t y = 0; y < image->ysize(); ++y) { |
323 | 16.9M | T* const JXL_RESTRICT row = image->Row(y); |
324 | 16.9M | memset(row, 0, image->xsize() * sizeof(T)); |
325 | 16.9M | } |
326 | 298k | } void jxl::ZeroFillImage<int>(jxl::Plane<int>*) Line | Count | Source | 320 | 1.79M | void ZeroFillImage(Plane<T>* image) { | 321 | 1.79M | if (image->xsize() == 0) return; | 322 | 16.9M | for (size_t y = 0; y < image->ysize(); ++y) { | 323 | 16.7M | T* const JXL_RESTRICT row = image->Row(y); | 324 | 16.7M | memset(row, 0, image->xsize() * sizeof(T)); | 325 | 16.7M | } | 326 | 250k | } |
Unexecuted instantiation: void jxl::ZeroFillImage<short>(jxl::Plane<short>*) void jxl::ZeroFillImage<unsigned char>(jxl::Plane<unsigned char>*) Line | Count | Source | 320 | 75 | void ZeroFillImage(Plane<T>* image) { | 321 | 75 | if (image->xsize() == 0) return; | 322 | 255 | for (size_t y = 0; y < image->ysize(); ++y) { | 323 | 180 | T* const JXL_RESTRICT row = image->Row(y); | 324 | 180 | memset(row, 0, image->xsize() * sizeof(T)); | 325 | 180 | } | 326 | 75 | } |
void jxl::ZeroFillImage<signed char>(jxl::Plane<signed char>*) Line | Count | Source | 320 | 48.1k | void ZeroFillImage(Plane<T>* image) { | 321 | 48.1k | if (image->xsize() == 0) return; | 322 | 267k | for (size_t y = 0; y < image->ysize(); ++y) { | 323 | 219k | T* const JXL_RESTRICT row = image->Row(y); | 324 | 219k | memset(row, 0, image->xsize() * sizeof(T)); | 325 | 219k | } | 326 | 48.1k | } |
|
327 | | |
328 | | // Mirrors out of bounds coordinates and returns valid coordinates unchanged. |
329 | | // We assume the radius (distance outside the image) is small compared to the |
330 | | // image size, otherwise this might not terminate. |
331 | | // The mirror is outside the last column (border pixel is also replicated). |
332 | 17.2M | static inline int64_t Mirror(int64_t x, const int64_t xsize) { |
333 | 17.2M | JXL_DASSERT(xsize != 0); |
334 | | |
335 | | // TODO(janwas): replace with branchless version |
336 | 36.2M | while (x < 0 || x >= xsize) { |
337 | 18.9M | if (x < 0) { |
338 | 9.48M | x = -x - 1; |
339 | 9.48M | } else { |
340 | 9.46M | x = 2 * xsize - 1 - x; |
341 | 9.46M | } |
342 | 18.9M | } |
343 | 17.2M | return x; |
344 | 17.2M | } Unexecuted instantiation: decode.cc:jxl::Mirror(long, long) Unexecuted instantiation: decode_to_jpeg.cc:jxl::Mirror(long, long) Unexecuted instantiation: entropy_coder.cc:jxl::Mirror(long, long) Unexecuted instantiation: frame_header.cc:jxl::Mirror(long, long) Unexecuted instantiation: icc_codec.cc:jxl::Mirror(long, long) Unexecuted instantiation: icc_codec_common.cc:jxl::Mirror(long, long) Unexecuted instantiation: image.cc:jxl::Mirror(long, long) Unexecuted instantiation: image_metadata.cc:jxl::Mirror(long, long) Unexecuted instantiation: dec_jpeg_data_writer.cc:jxl::Mirror(long, long) Unexecuted instantiation: loop_filter.cc:jxl::Mirror(long, long) Unexecuted instantiation: encoding.cc:jxl::Mirror(long, long) Unexecuted instantiation: modular_image.cc:jxl::Mirror(long, long) Unexecuted instantiation: transform.cc:jxl::Mirror(long, long) Unexecuted instantiation: quant_weights.cc:jxl::Mirror(long, long) Unexecuted instantiation: quantizer.cc:jxl::Mirror(long, long) Unexecuted instantiation: aux_out.cc:jxl::Mirror(long, long) Unexecuted instantiation: color_encoding_internal.cc:jxl::Mirror(long, long) Unexecuted instantiation: color_management.cc:jxl::Mirror(long, long) Unexecuted instantiation: dec_external_image.cc:jxl::Mirror(long, long) Unexecuted instantiation: dec_frame.cc:jxl::Mirror(long, long) Unexecuted instantiation: dec_group.cc:jxl::Mirror(long, long) Unexecuted instantiation: dec_modular.cc:jxl::Mirror(long, long) Unexecuted instantiation: dec_noise.cc:jxl::Mirror(long, long) Unexecuted instantiation: dec_patch_dictionary.cc:jxl::Mirror(long, long) Unexecuted instantiation: dec_xyb.cc:jxl::Mirror(long, long) Unexecuted instantiation: epf.cc:jxl::Mirror(long, long) Unexecuted instantiation: image_bundle.cc:jxl::Mirror(long, long) Unexecuted instantiation: dec_ma.cc:jxl::Mirror(long, long) Unexecuted instantiation: rct.cc:jxl::Mirror(long, long) Unexecuted instantiation: squeeze.cc:jxl::Mirror(long, long) Unexecuted instantiation: opsin_params.cc:jxl::Mirror(long, long) Unexecuted instantiation: passes_state.cc:jxl::Mirror(long, long) Unexecuted instantiation: simple_render_pipeline.cc:jxl::Mirror(long, long) Unexecuted instantiation: splines.cc:jxl::Mirror(long, long) Unexecuted instantiation: toc.cc:jxl::Mirror(long, long) Unexecuted instantiation: ac_strategy.cc:jxl::Mirror(long, long) Unexecuted instantiation: blending.cc:jxl::Mirror(long, long) Unexecuted instantiation: chroma_from_luma.cc:jxl::Mirror(long, long) Unexecuted instantiation: coeff_order.cc:jxl::Mirror(long, long) Unexecuted instantiation: compressed_dc.cc:jxl::Mirror(long, long) Unexecuted instantiation: dec_cache.cc:jxl::Mirror(long, long) low_memory_render_pipeline.cc:jxl::Mirror(long, long) Line | Count | Source | 332 | 17.2M | static inline int64_t Mirror(int64_t x, const int64_t xsize) { | 333 | 17.2M | JXL_DASSERT(xsize != 0); | 334 | | | 335 | | // TODO(janwas): replace with branchless version | 336 | 36.2M | while (x < 0 || x >= xsize) { | 337 | 18.9M | if (x < 0) { | 338 | 9.48M | x = -x - 1; | 339 | 9.48M | } else { | 340 | 9.46M | x = 2 * xsize - 1 - x; | 341 | 9.46M | } | 342 | 18.9M | } | 343 | 17.2M | return x; | 344 | 17.2M | } |
Unexecuted instantiation: stage_blending.cc:jxl::Mirror(long, long) Unexecuted instantiation: stage_epf.cc:jxl::Mirror(long, long) Unexecuted instantiation: stage_noise.cc:jxl::Mirror(long, long) Unexecuted instantiation: stage_patches.cc:jxl::Mirror(long, long) Unexecuted instantiation: stage_splines.cc:jxl::Mirror(long, long) Unexecuted instantiation: stage_write.cc:jxl::Mirror(long, long) |
345 | | |
346 | | // Wrap modes for ensuring X/Y coordinates are in the valid range [0, size): |
347 | | |
348 | | // Mirrors (repeating the edge pixel once). Useful for convolutions. |
349 | | struct WrapMirror { |
350 | 0 | JXL_INLINE int64_t operator()(const int64_t coord, const int64_t size) const { |
351 | 0 | return Mirror(coord, size); |
352 | 0 | } |
353 | | }; |
354 | | |
355 | | // Returns the same coordinate: required for TFNode with Border(), or useful |
356 | | // when we know "coord" is already valid (e.g. interior of an image). |
357 | | struct WrapUnchanged { |
358 | 0 | JXL_INLINE int64_t operator()(const int64_t coord, int64_t /*size*/) const { |
359 | 0 | return coord; |
360 | 0 | } |
361 | | }; |
362 | | |
363 | | // Similar to Wrap* but for row pointers (reduces Row() multiplications). |
364 | | |
365 | | class WrapRowMirror { |
366 | | public: |
367 | | template <class ImageOrView> |
368 | | WrapRowMirror(const ImageOrView& image, size_t ysize) |
369 | | : first_row_(image.ConstRow(0)), last_row_(image.ConstRow(ysize - 1)) {} |
370 | | |
371 | | const float* operator()(const float* const JXL_RESTRICT row, |
372 | 0 | const int64_t stride) const { |
373 | 0 | if (row < first_row_) { |
374 | 0 | const int64_t num_before = first_row_ - row; |
375 | 0 | // Mirrored; one row before => row 0, two before = row 1, ... |
376 | 0 | return first_row_ + num_before - stride; |
377 | 0 | } |
378 | 0 | if (row > last_row_) { |
379 | 0 | const int64_t num_after = row - last_row_; |
380 | 0 | // Mirrored; one row after => last row, two after = last - 1, ... |
381 | 0 | return last_row_ - num_after + stride; |
382 | 0 | } |
383 | 0 | return row; |
384 | 0 | } |
385 | | |
386 | | private: |
387 | | const float* const JXL_RESTRICT first_row_; |
388 | | const float* const JXL_RESTRICT last_row_; |
389 | | }; |
390 | | |
391 | | struct WrapRowUnchanged { |
392 | | JXL_INLINE const float* operator()(const float* const JXL_RESTRICT row, |
393 | 0 | int64_t /*stride*/) const { |
394 | 0 | return row; |
395 | 0 | } |
396 | | }; |
397 | | |
398 | | // Sets "thickness" pixels on each border to "value". This is faster than |
399 | | // initializing the entire image and overwriting valid/interior pixels. |
400 | | template <typename T> |
401 | | void SetBorder(const size_t thickness, const T value, Plane<T>* image) { |
402 | | const size_t xsize = image->xsize(); |
403 | | const size_t ysize = image->ysize(); |
404 | | // Top: fill entire row |
405 | | for (size_t y = 0; y < std::min(thickness, ysize); ++y) { |
406 | | T* const JXL_RESTRICT row = image->Row(y); |
407 | | std::fill(row, row + xsize, value); |
408 | | } |
409 | | |
410 | | // Bottom: fill entire row |
411 | | for (size_t y = ysize - thickness; y < ysize; ++y) { |
412 | | T* const JXL_RESTRICT row = image->Row(y); |
413 | | std::fill(row, row + xsize, value); |
414 | | } |
415 | | |
416 | | // Left/right: fill the 'columns' on either side, but only if the image is |
417 | | // big enough that they don't already belong to the top/bottom rows. |
418 | | if (ysize >= 2 * thickness) { |
419 | | for (size_t y = thickness; y < ysize - thickness; ++y) { |
420 | | T* const JXL_RESTRICT row = image->Row(y); |
421 | | std::fill(row, row + thickness, value); |
422 | | std::fill(row + xsize - thickness, row + xsize, value); |
423 | | } |
424 | | } |
425 | | } |
426 | | |
427 | | // Computes the minimum and maximum pixel value. |
428 | | template <typename T> |
429 | | void ImageMinMax(const Plane<T>& image, T* const JXL_RESTRICT min, |
430 | | T* const JXL_RESTRICT max) { |
431 | | *min = std::numeric_limits<T>::max(); |
432 | | *max = std::numeric_limits<T>::lowest(); |
433 | | for (size_t y = 0; y < image.ysize(); ++y) { |
434 | | const T* const JXL_RESTRICT row = image.Row(y); |
435 | | for (size_t x = 0; x < image.xsize(); ++x) { |
436 | | *min = std::min(*min, row[x]); |
437 | | *max = std::max(*max, row[x]); |
438 | | } |
439 | | } |
440 | | } |
441 | | |
442 | | // Copies pixels, scaling their value relative to the "from" min/max by |
443 | | // "to_range". Example: U8 [0, 255] := [0.0, 1.0], to_range = 1.0 => |
444 | | // outputs [0.0, 1.0]. |
445 | | template <typename FromType, typename ToType> |
446 | | void ImageConvert(const Plane<FromType>& from, const float to_range, |
447 | | Plane<ToType>* const JXL_RESTRICT to) { |
448 | | JXL_ASSERT(SameSize(from, *to)); |
449 | | FromType min_from, max_from; |
450 | | ImageMinMax(from, &min_from, &max_from); |
451 | | const float scale = to_range / (max_from - min_from); |
452 | | for (size_t y = 0; y < from.ysize(); ++y) { |
453 | | const FromType* const JXL_RESTRICT row_from = from.Row(y); |
454 | | ToType* const JXL_RESTRICT row_to = to->Row(y); |
455 | | for (size_t x = 0; x < from.xsize(); ++x) { |
456 | | row_to[x] = static_cast<ToType>((row_from[x] - min_from) * scale); |
457 | | } |
458 | | } |
459 | | } |
460 | | |
461 | | template <typename From> |
462 | | Plane<float> ConvertToFloat(const Plane<From>& from) { |
463 | | float factor = 1.0f / std::numeric_limits<From>::max(); |
464 | | if (std::is_same<From, double>::value || std::is_same<From, float>::value) { |
465 | | factor = 1.0f; |
466 | | } |
467 | | Plane<float> to(from.xsize(), from.ysize()); |
468 | | for (size_t y = 0; y < from.ysize(); ++y) { |
469 | | const From* const JXL_RESTRICT row_from = from.Row(y); |
470 | | float* const JXL_RESTRICT row_to = to.Row(y); |
471 | | for (size_t x = 0; x < from.xsize(); ++x) { |
472 | | row_to[x] = row_from[x] * factor; |
473 | | } |
474 | | } |
475 | | return to; |
476 | | } |
477 | | |
478 | | template <typename T> |
479 | | Plane<T> ImageFromPacked(const std::vector<T>& packed, const size_t xsize, |
480 | | const size_t ysize) { |
481 | | Plane<T> out(xsize, ysize); |
482 | | for (size_t y = 0; y < ysize; ++y) { |
483 | | T* const JXL_RESTRICT row = out.Row(y); |
484 | | const T* const JXL_RESTRICT packed_row = &packed[y * xsize]; |
485 | | memcpy(row, packed_row, xsize * sizeof(T)); |
486 | | } |
487 | | return out; |
488 | | } |
489 | | |
490 | | // Computes independent minimum and maximum values for each plane. |
491 | | template <typename T> |
492 | | void Image3MinMax(const Image3<T>& image, const Rect& rect, |
493 | | std::array<T, 3>* out_min, std::array<T, 3>* out_max) { |
494 | | for (size_t c = 0; c < 3; ++c) { |
495 | | T min = std::numeric_limits<T>::max(); |
496 | | T max = std::numeric_limits<T>::min(); |
497 | | for (size_t y = 0; y < rect.ysize(); ++y) { |
498 | | const T* JXL_RESTRICT row = rect.ConstPlaneRow(image, c, y); |
499 | | for (size_t x = 0; x < rect.xsize(); ++x) { |
500 | | min = std::min(min, row[x]); |
501 | | max = std::max(max, row[x]); |
502 | | } |
503 | | } |
504 | | (*out_min)[c] = min; |
505 | | (*out_max)[c] = max; |
506 | | } |
507 | | } |
508 | | |
509 | | // Computes independent minimum and maximum values for each plane. |
510 | | template <typename T> |
511 | | void Image3MinMax(const Image3<T>& image, std::array<T, 3>* out_min, |
512 | | std::array<T, 3>* out_max) { |
513 | | Image3MinMax(image, Rect(image), out_min, out_max); |
514 | | } |
515 | | |
516 | | template <typename T> |
517 | | void Image3Max(const Image3<T>& image, std::array<T, 3>* out_max) { |
518 | | for (size_t c = 0; c < 3; ++c) { |
519 | | T max = std::numeric_limits<T>::min(); |
520 | | for (size_t y = 0; y < image.ysize(); ++y) { |
521 | | const T* JXL_RESTRICT row = image.ConstPlaneRow(c, y); |
522 | | for (size_t x = 0; x < image.xsize(); ++x) { |
523 | | max = std::max(max, row[x]); |
524 | | } |
525 | | } |
526 | | (*out_max)[c] = max; |
527 | | } |
528 | | } |
529 | | |
530 | | // Computes the sum of the pixels in `rect`. |
531 | | template <typename T> |
532 | | T ImageSum(const Plane<T>& image, const Rect& rect) { |
533 | | T result = 0; |
534 | | for (size_t y = 0; y < rect.ysize(); ++y) { |
535 | | const T* JXL_RESTRICT row = rect.ConstRow(image, y); |
536 | | for (size_t x = 0; x < rect.xsize(); ++x) { |
537 | | result += row[x]; |
538 | | } |
539 | | } |
540 | | return result; |
541 | | } |
542 | | |
543 | | template <typename T> |
544 | | T ImageSum(const Plane<T>& image) { |
545 | | return ImageSum(image, Rect(image)); |
546 | | } |
547 | | |
548 | | template <typename T> |
549 | | std::array<T, 3> Image3Sum(const Image3<T>& image, const Rect& rect) { |
550 | | std::array<T, 3> out_sum = 0; |
551 | | for (size_t c = 0; c < 3; ++c) { |
552 | | (out_sum)[c] = ImageSum(image.Plane(c), rect); |
553 | | } |
554 | | return out_sum; |
555 | | } |
556 | | |
557 | | template <typename T> |
558 | | std::array<T, 3> Image3Sum(const Image3<T>& image) { |
559 | | return Image3Sum(image, Rect(image)); |
560 | | } |
561 | | |
562 | | template <typename T> |
563 | | std::vector<T> PackedFromImage(const Plane<T>& image, const Rect& rect) { |
564 | | const size_t xsize = rect.xsize(); |
565 | | const size_t ysize = rect.ysize(); |
566 | | std::vector<T> packed(xsize * ysize); |
567 | | for (size_t y = 0; y < rect.ysize(); ++y) { |
568 | | memcpy(&packed[y * xsize], rect.ConstRow(image, y), xsize * sizeof(T)); |
569 | | } |
570 | | return packed; |
571 | | } |
572 | | |
573 | | template <typename T> |
574 | | std::vector<T> PackedFromImage(const Plane<T>& image) { |
575 | | return PackedFromImage(image, Rect(image)); |
576 | | } |
577 | | |
578 | | // Computes the median pixel value. |
579 | | template <typename T> |
580 | | T ImageMedian(const Plane<T>& image, const Rect& rect) { |
581 | | std::vector<T> pixels = PackedFromImage(image, rect); |
582 | | return Median(&pixels); |
583 | | } |
584 | | |
585 | | template <typename T> |
586 | | T ImageMedian(const Plane<T>& image) { |
587 | | return ImageMedian(image, Rect(image)); |
588 | | } |
589 | | |
590 | | template <typename T> |
591 | | std::array<T, 3> Image3Median(const Image3<T>& image, const Rect& rect) { |
592 | | std::array<T, 3> out_median; |
593 | | for (size_t c = 0; c < 3; ++c) { |
594 | | (out_median)[c] = ImageMedian(image.Plane(c), rect); |
595 | | } |
596 | | return out_median; |
597 | | } |
598 | | |
599 | | template <typename T> |
600 | | std::array<T, 3> Image3Median(const Image3<T>& image) { |
601 | | return Image3Median(image, Rect(image)); |
602 | | } |
603 | | |
604 | | template <typename FromType, typename ToType> |
605 | | void Image3Convert(const Image3<FromType>& from, const float to_range, |
606 | | Image3<ToType>* const JXL_RESTRICT to) { |
607 | | JXL_ASSERT(SameSize(from, *to)); |
608 | | std::array<FromType, 3> min_from, max_from; |
609 | | Image3MinMax(from, &min_from, &max_from); |
610 | | float scales[3]; |
611 | | for (size_t c = 0; c < 3; ++c) { |
612 | | scales[c] = to_range / (max_from[c] - min_from[c]); |
613 | | } |
614 | | float scale = std::min(scales[0], std::min(scales[1], scales[2])); |
615 | | for (size_t c = 0; c < 3; ++c) { |
616 | | for (size_t y = 0; y < from.ysize(); ++y) { |
617 | | const FromType* JXL_RESTRICT row_from = from.ConstPlaneRow(c, y); |
618 | | ToType* JXL_RESTRICT row_to = to->PlaneRow(c, y); |
619 | | for (size_t x = 0; x < from.xsize(); ++x) { |
620 | | const float to = (row_from[x] - min_from[c]) * scale; |
621 | | row_to[x] = static_cast<ToType>(to); |
622 | | } |
623 | | } |
624 | | } |
625 | | } |
626 | | |
627 | | template <typename From> |
628 | | Image3F ConvertToFloat(const Image3<From>& from) { |
629 | | return Image3F(ConvertToFloat(from.Plane(0)), ConvertToFloat(from.Plane(1)), |
630 | | ConvertToFloat(from.Plane(2))); |
631 | | } |
632 | | |
633 | | template <typename Tin, typename Tout> |
634 | | void Subtract(const Image3<Tin>& image1, const Image3<Tin>& image2, |
635 | | Image3<Tout>* out) { |
636 | | const size_t xsize = image1.xsize(); |
637 | | const size_t ysize = image1.ysize(); |
638 | | JXL_CHECK(xsize == image2.xsize()); |
639 | | JXL_CHECK(ysize == image2.ysize()); |
640 | | |
641 | | for (size_t c = 0; c < 3; ++c) { |
642 | | for (size_t y = 0; y < ysize; ++y) { |
643 | | const Tin* const JXL_RESTRICT row1 = image1.ConstPlaneRow(c, y); |
644 | | const Tin* const JXL_RESTRICT row2 = image2.ConstPlaneRow(c, y); |
645 | | Tout* const JXL_RESTRICT row_out = out->PlaneRow(c, y); |
646 | | for (size_t x = 0; x < xsize; ++x) { |
647 | | row_out[x] = row1[x] - row2[x]; |
648 | | } |
649 | | } |
650 | | } |
651 | | } |
652 | | |
653 | | template <typename Tin, typename Tout> |
654 | | void SubtractFrom(const Image3<Tin>& what, Image3<Tout>* to) { |
655 | | const size_t xsize = what.xsize(); |
656 | | const size_t ysize = what.ysize(); |
657 | | for (size_t c = 0; c < 3; ++c) { |
658 | | for (size_t y = 0; y < ysize; ++y) { |
659 | | const Tin* JXL_RESTRICT row_what = what.ConstPlaneRow(c, y); |
660 | | Tout* JXL_RESTRICT row_to = to->PlaneRow(c, y); |
661 | | for (size_t x = 0; x < xsize; ++x) { |
662 | | row_to[x] -= row_what[x]; |
663 | | } |
664 | | } |
665 | | } |
666 | | } |
667 | | |
668 | | template <typename Tin, typename Tout> |
669 | | void AddTo(const Image3<Tin>& what, Image3<Tout>* to) { |
670 | | const size_t xsize = what.xsize(); |
671 | | const size_t ysize = what.ysize(); |
672 | | for (size_t c = 0; c < 3; ++c) { |
673 | | for (size_t y = 0; y < ysize; ++y) { |
674 | | const Tin* JXL_RESTRICT row_what = what.ConstPlaneRow(c, y); |
675 | | Tout* JXL_RESTRICT row_to = to->PlaneRow(c, y); |
676 | | for (size_t x = 0; x < xsize; ++x) { |
677 | | row_to[x] += row_what[x]; |
678 | | } |
679 | | } |
680 | | } |
681 | | } |
682 | | |
683 | | // Adds `what` of the size of `rect` to `to` in the position of `rect`. |
684 | | template <typename Tin, typename Tout> |
685 | | void AddTo(const Rect& rect, const Image3<Tin>& what, Image3<Tout>* to) { |
686 | | const size_t xsize = what.xsize(); |
687 | | const size_t ysize = what.ysize(); |
688 | | JXL_ASSERT(xsize == rect.xsize()); |
689 | | JXL_ASSERT(ysize == rect.ysize()); |
690 | | for (size_t c = 0; c < 3; ++c) { |
691 | | for (size_t y = 0; y < ysize; ++y) { |
692 | | const Tin* JXL_RESTRICT row_what = what.ConstPlaneRow(c, y); |
693 | | Tout* JXL_RESTRICT row_to = rect.PlaneRow(to, c, y); |
694 | | for (size_t x = 0; x < xsize; ++x) { |
695 | | row_to[x] += row_what[x]; |
696 | | } |
697 | | } |
698 | | } |
699 | | } |
700 | | |
701 | | template <typename T> |
702 | | Image3<T> ScaleImage(const T lambda, const Image3<T>& image) { |
703 | | Image3<T> out(image.xsize(), image.ysize()); |
704 | | for (size_t c = 0; c < 3; ++c) { |
705 | | for (size_t y = 0; y < image.ysize(); ++y) { |
706 | | const T* JXL_RESTRICT row = image.ConstPlaneRow(c, y); |
707 | | T* JXL_RESTRICT row_out = out.PlaneRow(c, y); |
708 | | for (size_t x = 0; x < image.xsize(); ++x) { |
709 | | row_out[x] = lambda * row[x]; |
710 | | } |
711 | | } |
712 | | } |
713 | | return out; |
714 | | } |
715 | | |
716 | | // Multiplies image by lambda in-place |
717 | | template <typename T> |
718 | | void ScaleImage(const T lambda, Image3<T>* image) { |
719 | | for (size_t c = 0; c < 3; ++c) { |
720 | | for (size_t y = 0; y < image->ysize(); ++y) { |
721 | | T* const JXL_RESTRICT row = image->PlaneRow(c, y); |
722 | | for (size_t x = 0; x < image->xsize(); ++x) { |
723 | | row[x] = lambda * row[x]; |
724 | | } |
725 | | } |
726 | | } |
727 | | } |
728 | | |
729 | | // Initializes all planes to the same "value". |
730 | | template <typename T> |
731 | | void FillImage(const T value, Image3<T>* image) { |
732 | | for (size_t c = 0; c < 3; ++c) { |
733 | | for (size_t y = 0; y < image->ysize(); ++y) { |
734 | | T* JXL_RESTRICT row = image->PlaneRow(c, y); |
735 | | for (size_t x = 0; x < image->xsize(); ++x) { |
736 | | row[x] = value; |
737 | | } |
738 | | } |
739 | | } |
740 | | } |
741 | | |
742 | | template <typename T> |
743 | | void FillPlane(const T value, Plane<T>* image) { |
744 | | for (size_t y = 0; y < image->ysize(); ++y) { |
745 | | T* JXL_RESTRICT row = image->Row(y); |
746 | | for (size_t x = 0; x < image->xsize(); ++x) { |
747 | | row[x] = value; |
748 | | } |
749 | | } |
750 | | } |
751 | | |
752 | | template <typename T> |
753 | | void FillImage(const T value, Image3<T>* image, Rect rect) { |
754 | | for (size_t c = 0; c < 3; ++c) { |
755 | | for (size_t y = 0; y < rect.ysize(); ++y) { |
756 | | T* JXL_RESTRICT row = rect.PlaneRow(image, c, y); |
757 | | for (size_t x = 0; x < rect.xsize(); ++x) { |
758 | | row[x] = value; |
759 | | } |
760 | | } |
761 | | } |
762 | | } |
763 | | |
764 | | template <typename T> |
765 | 0 | void FillPlane(const T value, Plane<T>* image, Rect rect) { |
766 | 0 | for (size_t y = 0; y < rect.ysize(); ++y) { |
767 | 0 | T* JXL_RESTRICT row = rect.Row(image, y); |
768 | 0 | for (size_t x = 0; x < rect.xsize(); ++x) { |
769 | 0 | row[x] = value; |
770 | 0 | } |
771 | 0 | } |
772 | 0 | } |
773 | | |
774 | | template <typename T> |
775 | 16 | void ZeroFillImage(Image3<T>* image) { |
776 | 64 | for (size_t c = 0; c < 3; ++c) { |
777 | 96 | for (size_t y = 0; y < image->ysize(); ++y) { |
778 | 48 | T* JXL_RESTRICT row = image->PlaneRow(c, y); |
779 | 48 | if (image->xsize() != 0) memset(row, 0, image->xsize() * sizeof(T)); |
780 | 48 | } |
781 | 48 | } |
782 | 16 | } void jxl::ZeroFillImage<int>(jxl::Image3<int>*) Line | Count | Source | 775 | 8 | void ZeroFillImage(Image3<T>* image) { | 776 | 32 | for (size_t c = 0; c < 3; ++c) { | 777 | 48 | for (size_t y = 0; y < image->ysize(); ++y) { | 778 | 24 | T* JXL_RESTRICT row = image->PlaneRow(c, y); | 779 | 24 | if (image->xsize() != 0) memset(row, 0, image->xsize() * sizeof(T)); | 780 | 24 | } | 781 | 24 | } | 782 | 8 | } |
void jxl::ZeroFillImage<short>(jxl::Image3<short>*) Line | Count | Source | 775 | 8 | void ZeroFillImage(Image3<T>* image) { | 776 | 32 | for (size_t c = 0; c < 3; ++c) { | 777 | 48 | for (size_t y = 0; y < image->ysize(); ++y) { | 778 | 24 | T* JXL_RESTRICT row = image->PlaneRow(c, y); | 779 | 24 | if (image->xsize() != 0) memset(row, 0, image->xsize() * sizeof(T)); | 780 | 24 | } | 781 | 24 | } | 782 | 8 | } |
|
783 | | |
784 | | template <typename T> |
785 | | void ZeroFillPlane(Plane<T>* image, Rect rect) { |
786 | | for (size_t y = 0; y < rect.ysize(); ++y) { |
787 | | T* JXL_RESTRICT row = rect.Row(image, y); |
788 | | memset(row, 0, rect.xsize() * sizeof(T)); |
789 | | } |
790 | | } |
791 | | |
792 | | // Pad an image with xborder columns on each vertical side and yboder rows |
793 | | // above and below, mirroring the image. |
794 | | Image3F PadImageMirror(const Image3F& in, size_t xborder, size_t yborder); |
795 | | |
796 | | // Same as above, but operates in-place. Assumes that the `in` image was |
797 | | // allocated large enough. |
798 | | void PadImageToBlockMultipleInPlace(Image3F* JXL_RESTRICT in); |
799 | | |
800 | | // Downsamples an image by a given factor. |
801 | | void DownsampleImage(Image3F* opsin, size_t factor); |
802 | | void DownsampleImage(ImageF* image, size_t factor); |
803 | | |
804 | | } // namespace jxl |
805 | | |
806 | | #endif // LIB_JXL_IMAGE_OPS_H_ |