Blender V5.0
filter.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cmath>
10
11#include "MEM_guardedalloc.h"
12
13#include "BLI_math_base.h"
14#include "BLI_utildefines.h"
15
16#include "IMB_filter.hh"
17#include "IMB_imbuf.hh"
18#include "IMB_imbuf_types.hh"
19
20static void filtcolum(uchar *point, int y, int skip)
21{
22 uint c1, c2, c3, error;
23 uchar *point2;
24
25 if (y > 1) {
26 c1 = c2 = *point;
27 point2 = point;
28 error = 2;
29 for (y--; y > 0; y--) {
30 point2 += skip;
31 c3 = *point2;
32 c1 += (c2 << 1) + c3 + error;
33 error = c1 & 3;
34 *point = c1 >> 2;
35 point = point2;
36 c1 = c2;
37 c2 = c3;
38 }
39 *point = (c1 + (c2 << 1) + c2 + error) >> 2;
40 }
41}
42
43static void filtcolumf(float *point, int y, int skip)
44{
45 float c1, c2, c3, *point2;
46
47 if (y > 1) {
48 c1 = c2 = *point;
49 point2 = point;
50 for (y--; y > 0; y--) {
51 point2 += skip;
52 c3 = *point2;
53 c1 += (c2 * 2) + c3;
54 *point = 0.25f * c1;
55 point = point2;
56 c1 = c2;
57 c2 = c3;
58 }
59 *point = 0.25f * (c1 + (c2 * 2) + c2);
60 }
61}
62
63void IMB_filtery(ImBuf *ibuf)
64{
65 uchar *point = ibuf->byte_buffer.data;
66 float *pointf = ibuf->float_buffer.data;
67
68 int x = ibuf->x;
69 int y = ibuf->y;
70 int skip = x << 2;
71
72 for (; x > 0; x--) {
73 if (point) {
74 if (ibuf->planes > 24) {
75 filtcolum(point, y, skip);
76 }
77 point++;
78 filtcolum(point, y, skip);
79 point++;
80 filtcolum(point, y, skip);
81 point++;
82 filtcolum(point, y, skip);
83 point++;
84 }
85 if (pointf) {
86 if (ibuf->planes > 24) {
87 filtcolumf(pointf, y, skip);
88 }
89 pointf++;
90 filtcolumf(pointf, y, skip);
91 pointf++;
92 filtcolumf(pointf, y, skip);
93 pointf++;
94 filtcolumf(pointf, y, skip);
95 pointf++;
96 }
97 }
98}
99
100void IMB_mask_filter_extend(char *mask, int width, int height)
101{
102 const char *row1, *row2, *row3;
103 int rowlen, x, y;
104 char *temprect;
105
106 rowlen = width;
107
108 /* make a copy, to prevent flooding */
109 temprect = static_cast<char *>(MEM_dupallocN(mask));
110
111 for (y = 1; y <= height; y++) {
112 /* setup rows */
113 row1 = (char *)(temprect + (y - 2) * rowlen);
114 row2 = row1 + rowlen;
115 row3 = row2 + rowlen;
116 if (y == 1) {
117 row1 = row2;
118 }
119 else if (y == height) {
120 row3 = row2;
121 }
122
123 for (x = 0; x < rowlen; x++) {
124 if (mask[((y - 1) * rowlen) + x] == 0) {
125 if (*row1 || *row2 || *row3 || *(row1 + 1) || *(row3 + 1)) {
126 mask[((y - 1) * rowlen) + x] = FILTER_MASK_MARGIN;
127 }
128 else if ((x != rowlen - 1) && (*(row1 + 2) || *(row2 + 2) || *(row3 + 2))) {
129 mask[((y - 1) * rowlen) + x] = FILTER_MASK_MARGIN;
130 }
131 }
132
133 if (x != 0) {
134 row1++;
135 row2++;
136 row3++;
137 }
138 }
139 }
140
141 MEM_freeN(temprect);
142}
143
144void IMB_mask_clear(ImBuf *ibuf, const char *mask, int val)
145{
146 int x, y;
147 if (ibuf->float_buffer.data) {
148 for (x = 0; x < ibuf->x; x++) {
149 for (y = 0; y < ibuf->y; y++) {
150 if (mask[ibuf->x * y + x] == val) {
151 float *col = ibuf->float_buffer.data + 4 * (ibuf->x * y + x);
152 col[0] = col[1] = col[2] = col[3] = 0.0f;
153 }
154 }
155 }
156 }
157 else {
158 /* char buffer */
159 for (x = 0; x < ibuf->x; x++) {
160 for (y = 0; y < ibuf->y; y++) {
161 if (mask[ibuf->x * y + x] == val) {
162 char *col = (char *)(ibuf->byte_buffer.data + 4 * ibuf->x * y + x);
163 col[0] = col[1] = col[2] = col[3] = 0;
164 }
165 }
166 }
167 }
168}
169
170static int filter_make_index(const int x, const int y, const int w, const int h)
171{
172 if (x < 0 || x >= w || y < 0 || y >= h) {
173 return -1; /* return bad index */
174 }
175
176 return y * w + x;
177}
178
180 const void *buffer, const char *mask, const int index, const int depth, const bool is_float)
181{
182 int res = 0;
183
184 if (index >= 0) {
185 const int alpha_index = depth * index + (depth - 1);
186
187 if (mask != nullptr) {
188 res = mask[index] != 0 ? 1 : 0;
189 }
190 else if ((is_float && ((const float *)buffer)[alpha_index] != 0.0f) ||
191 (!is_float && ((const uchar *)buffer)[alpha_index] != 0))
192 {
193 res = 1;
194 }
195 }
196
197 return res;
198}
199
200void IMB_filter_extend(ImBuf *ibuf, char *mask, int filter)
201{
202 const int width = ibuf->x;
203 const int height = ibuf->y;
204 const int depth = 4; /* always 4 channels */
205 const int chsize = ibuf->float_buffer.data ? sizeof(float) : sizeof(uchar);
206 const size_t bsize = size_t(width) * height * depth * chsize;
207 const bool is_float = (ibuf->float_buffer.data != nullptr);
208 void *dstbuf = MEM_dupallocN(ibuf->float_buffer.data ? (void *)ibuf->float_buffer.data :
209 (void *)ibuf->byte_buffer.data);
210 char *dstmask = mask == nullptr ? nullptr : (char *)MEM_dupallocN(mask);
211 void *srcbuf = ibuf->float_buffer.data ? (void *)ibuf->float_buffer.data :
212 (void *)ibuf->byte_buffer.data;
213 char *srcmask = mask;
214 int cannot_early_out = 1, r, n, k, i, j, c;
215 float weight[25];
216
217 /* build a weights buffer */
218 n = 1;
219
220#if 0
221 k = 0;
222 for (i = -n; i <= n; i++) {
223 for (j = -n; j <= n; j++) {
224 weight[k++] = sqrt(float(i) * i + j * j);
225 }
226 }
227#endif
228
229 weight[0] = 1;
230 weight[1] = 2;
231 weight[2] = 1;
232 weight[3] = 2;
233 weight[4] = 0;
234 weight[5] = 2;
235 weight[6] = 1;
236 weight[7] = 2;
237 weight[8] = 1;
238
239 /* run passes */
240 for (r = 0; cannot_early_out == 1 && r < filter; r++) {
241 int x, y;
242 cannot_early_out = 0;
243
244 for (y = 0; y < height; y++) {
245 for (x = 0; x < width; x++) {
246 const int index = filter_make_index(x, y, width, height);
247
248 /* only update unassigned pixels */
249 if (!check_pixel_assigned(srcbuf, srcmask, index, depth, is_float)) {
250 float tmp[4];
251 float wsum = 0;
252 float acc[4] = {0, 0, 0, 0};
253 k = 0;
254
256 srcbuf, srcmask, filter_make_index(x - 1, y, width, height), depth, is_float) ||
258 srcbuf, srcmask, filter_make_index(x + 1, y, width, height), depth, is_float) ||
260 srcbuf, srcmask, filter_make_index(x, y - 1, width, height), depth, is_float) ||
262 srcbuf, srcmask, filter_make_index(x, y + 1, width, height), depth, is_float))
263 {
264 for (i = -n; i <= n; i++) {
265 for (j = -n; j <= n; j++) {
266 if (i != 0 || j != 0) {
267 const int tmpindex = filter_make_index(x + i, y + j, width, height);
268
269 if (check_pixel_assigned(srcbuf, srcmask, tmpindex, depth, is_float)) {
270 if (is_float) {
271 for (c = 0; c < depth; c++) {
272 tmp[c] = ((const float *)srcbuf)[depth * tmpindex + c];
273 }
274 }
275 else {
276 for (c = 0; c < depth; c++) {
277 tmp[c] = float(((const uchar *)srcbuf)[depth * tmpindex + c]);
278 }
279 }
280
281 wsum += weight[k];
282
283 for (c = 0; c < depth; c++) {
284 acc[c] += weight[k] * tmp[c];
285 }
286 }
287 }
288 k++;
289 }
290 }
291
292 if (wsum != 0) {
293 for (c = 0; c < depth; c++) {
294 acc[c] /= wsum;
295 }
296
297 if (is_float) {
298 for (c = 0; c < depth; c++) {
299 ((float *)dstbuf)[depth * index + c] = acc[c];
300 }
301 }
302 else {
303 for (c = 0; c < depth; c++) {
304 ((uchar *)dstbuf)[depth * index + c] = acc[c] > 255 ?
305 255 :
306 (acc[c] < 0 ? 0 :
307 uchar(roundf(acc[c])));
308 }
309 }
310
311 if (dstmask != nullptr) {
312 dstmask[index] = FILTER_MASK_MARGIN; /* assigned */
313 }
314 cannot_early_out = 1;
315 }
316 }
317 }
318 }
319 }
320
321 /* keep the original buffer up to date. */
322 memcpy(srcbuf, dstbuf, bsize);
323 if (dstmask != nullptr) {
324 memcpy(srcmask, dstmask, size_t(width) * height);
325 }
326 }
327
328 /* free memory */
329 MEM_freeN(dstbuf);
330 if (dstmask != nullptr) {
331 MEM_freeN(dstmask);
332 }
333}
334
335void IMB_premultiply_rect(uint8_t *rect, char planes, int w, int h)
336{
337 uint8_t *cp;
338 int x, y, val;
339
340 if (planes == 24) { /* put alpha at 255 */
341 cp = rect;
342
343 for (y = 0; y < h; y++) {
344 for (x = 0; x < w; x++, cp += 4) {
345 cp[3] = 255;
346 }
347 }
348 }
349 else {
350 cp = rect;
351
352 for (y = 0; y < h; y++) {
353 for (x = 0; x < w; x++, cp += 4) {
354 val = cp[3];
355 cp[0] = (cp[0] * val) >> 8;
356 cp[1] = (cp[1] * val) >> 8;
357 cp[2] = (cp[2] * val) >> 8;
358 }
359 }
360 }
361}
362
363void IMB_premultiply_rect_float(float *rect_float, int channels, int w, int h)
364{
365 float val, *cp;
366 int x, y;
367
368 if (channels == 4) {
369 cp = rect_float;
370 for (y = 0; y < h; y++) {
371 for (x = 0; x < w; x++, cp += 4) {
372 val = cp[3];
373 cp[0] = cp[0] * val;
374 cp[1] = cp[1] * val;
375 cp[2] = cp[2] * val;
376 }
377 }
378 }
379}
380
382{
383 if (ibuf == nullptr) {
384 return;
385 }
386
387 if (ibuf->byte_buffer.data) {
388 IMB_premultiply_rect(ibuf->byte_buffer.data, ibuf->planes, ibuf->x, ibuf->y);
389 }
390
391 if (ibuf->float_buffer.data) {
392 IMB_premultiply_rect_float(ibuf->float_buffer.data, ibuf->channels, ibuf->x, ibuf->y);
393 }
394}
395
396void IMB_unpremultiply_rect(uint8_t *rect, char planes, int w, int h)
397{
398 uchar *cp;
399 int x, y;
400 float val;
401
402 if (planes == 24) { /* put alpha at 255 */
403 cp = rect;
404
405 for (y = 0; y < h; y++) {
406 for (x = 0; x < w; x++, cp += 4) {
407 cp[3] = 255;
408 }
409 }
410 }
411 else {
412 cp = rect;
413
414 for (y = 0; y < h; y++) {
415 for (x = 0; x < w; x++, cp += 4) {
416 val = cp[3] != 0 ? 1.0f / float(cp[3]) : 1.0f;
417 cp[0] = unit_float_to_uchar_clamp(cp[0] * val);
418 cp[1] = unit_float_to_uchar_clamp(cp[1] * val);
419 cp[2] = unit_float_to_uchar_clamp(cp[2] * val);
420 }
421 }
422 }
423}
424
425void IMB_unpremultiply_rect_float(float *rect_float, int channels, int w, int h)
426{
427 float val, *fp;
428 int x, y;
429
430 if (channels == 4) {
431 fp = rect_float;
432 for (y = 0; y < h; y++) {
433 for (x = 0; x < w; x++, fp += 4) {
434 val = fp[3] != 0.0f ? 1.0f / fp[3] : 1.0f;
435 fp[0] = fp[0] * val;
436 fp[1] = fp[1] * val;
437 fp[2] = fp[2] * val;
438 }
439 }
440 }
441}
442
444{
445 if (ibuf == nullptr) {
446 return;
447 }
448
449 if (ibuf->byte_buffer.data) {
450 IMB_unpremultiply_rect(ibuf->byte_buffer.data, ibuf->planes, ibuf->x, ibuf->y);
451 }
452
453 if (ibuf->float_buffer.data) {
454 IMB_unpremultiply_rect_float(ibuf->float_buffer.data, ibuf->channels, ibuf->x, ibuf->y);
455 }
456}
unsigned char uchar
unsigned int uint
Function declarations for filter.cc.
#define FILTER_MASK_MARGIN
Definition IMB_imbuf.hh:289
Read Guarded memory(de)allocation.
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
nullptr float
#define roundf(x)
void IMB_premultiply_alpha(ImBuf *ibuf)
Definition filter.cc:381
void IMB_unpremultiply_rect_float(float *rect_float, int channels, int w, int h)
Definition filter.cc:425
void IMB_premultiply_rect_float(float *rect_float, int channels, int w, int h)
Definition filter.cc:363
void IMB_mask_filter_extend(char *mask, int width, int height)
Definition filter.cc:100
void IMB_unpremultiply_alpha(ImBuf *ibuf)
Definition filter.cc:443
static void filtcolumf(float *point, int y, int skip)
Definition filter.cc:43
void IMB_mask_clear(ImBuf *ibuf, const char *mask, int val)
Definition filter.cc:144
static void filtcolum(uchar *point, int y, int skip)
Definition filter.cc:20
void IMB_filtery(ImBuf *ibuf)
Definition filter.cc:63
void IMB_unpremultiply_rect(uint8_t *rect, char planes, int w, int h)
Definition filter.cc:396
void IMB_premultiply_rect(uint8_t *rect, char planes, int w, int h)
Definition filter.cc:335
void IMB_filter_extend(ImBuf *ibuf, char *mask, int filter)
Definition filter.cc:200
static int filter_make_index(const int x, const int y, const int w, const int h)
Definition filter.cc:170
static int check_pixel_assigned(const void *buffer, const char *mask, const int index, const int depth, const bool is_float)
Definition filter.cc:179
uint col
#define filter
#define sqrt
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
MINLINE unsigned char unit_float_to_uchar_clamp(float val)
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
static void error(const char *str)
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
unsigned char planes
i
Definition text_draw.cc:230