From c7616dd73835cd3918e65a4c105745461e6c312d Mon Sep 17 00:00:00 2001 From: Jean-Philippe Andre Date: Thu, 20 Mar 2014 18:26:04 +0900 Subject: [PATCH] Evas filters: Fix blur corner cases with small images If the buffer size is smaller than the blurring kernel, then special precautions must be taken to properly read the source pixels. Also, fix the corner cases near the left & right edges (or top & bottom). --- src/lib/evas/filters/blur/blur_box_alpha_.c | 94 +++++++++++++-------------- src/lib/evas/filters/blur/blur_box_rgba_.c | 98 ++++++++++++++++------------- src/lib/evas/filters/evas_filter_blur.c | 8 --- 3 files changed, 102 insertions(+), 98 deletions(-) diff --git a/src/lib/evas/filters/blur/blur_box_alpha_.c b/src/lib/evas/filters/blur/blur_box_alpha_.c index 71ac943..4257a5e 100644 --- a/src/lib/evas/filters/blur/blur_box_alpha_.c +++ b/src/lib/evas/filters/blur/blur_box_alpha_.c @@ -32,6 +32,8 @@ _box_blur_alpha_horiz_step(const DATA8* restrict const srcdata, span1 = alloca(len); span2 = alloca(len); + memset(span1, 0, len); + memset(span2, 0, len); // For each line, apply as many blurs as requested for (int l = 0; l < loops; l++) @@ -50,8 +52,6 @@ _box_blur_alpha_horiz_step(const DATA8* restrict const srcdata, { const int radius = radii[run]; const int left = MIN(radius, len); - const int right = MIN(radius, (len - radius)); - int acc = 0; #if DIV_USING_BITSHIFT const int pow2 = pow2_shifts[run]; @@ -60,44 +60,46 @@ _box_blur_alpha_horiz_step(const DATA8* restrict const srcdata, const int divider = 2 * radius + 1; #endif - const DATA8* restrict sr = src; const DATA8* restrict sl = src; + const DATA8* restrict sr = src; + const DATA8* restrict sre = src + len; + const DATA8* restrict sle = src + len - radius; DATA8* restrict d = dst; + int acc = 0, count = 0; // Read-ahead & accumulate - for (int k = left; k; k--) + for (int x = left; x > 0; x--) { - acc += *sr; - sr += 1; + acc += *sr++; + count++; } // Left edge - for (int k = 0; k < left; k++) + for (int x = left; x > 0; x--) { - acc += *sr; - *d = acc / (k + left + 1); - sr += 1; - d += 1; + if (sr < sre) + { + acc += *sr++; + count++; + } + + *d++ = acc / count; } // Middle part, normal blur - for (int k = len - (2 * radius); k; k--) + while (sr < sre) { - acc += *sr; - *d = DIVIDE(acc); - acc -= *sl; - sl += 1; - sr += 1; - d += 1; + acc += *sr++; + *d++ = DIVIDE(acc); + acc -= *sl++; } // Right edge - for (int k = right; k; k--) + count = 2 * radius + 1; + while (sl < sle) { - *d = acc / (k + right); - acc -= *sl; - d += 1; - sl += 1; + *d++ = acc / (--count); + acc -= *sl++; } // More runs to go: swap spans @@ -177,8 +179,6 @@ _box_blur_alpha_vert_step(const DATA8* restrict const srcdata, { const int radius = radii[run]; const int left = MIN(radius, len); - const int right = MIN(radius, (len - radius)); - int acc = 0; #if DIV_USING_BITSHIFT const int pow2 = pow2_shifts[run]; @@ -187,44 +187,46 @@ _box_blur_alpha_vert_step(const DATA8* restrict const srcdata, const int divider = 2 * radius + 1; #endif - const DATA8* restrict sr = src; const DATA8* restrict sl = src; + const DATA8* restrict sr = src; + const DATA8* restrict sre = src + len; + const DATA8* restrict sle = src + len - radius; DATA8* restrict d = dst; + int acc = 0, count = 0; // Read-ahead & accumulate - for (int k = left; k; k--) + for (int x = left; x > 0; x--) { - acc += *sr; - sr += 1; + acc += *sr++; + count++; } // Left edge - for (int k = 0; k < left; k++) + for (int x = left; x > 0; x--) { - acc += *sr; - *d = acc / (k + left + 1); - sr += 1; - d += 1; + if (sr < sre) + { + acc += *sr++; + count++; + } + + *d++ = acc / count; } // Middle part, normal blur - for (int k = len - (2 * radius); k; k--) + while (sr < sre) { - acc += *sr; - *d = DIVIDE(acc); - acc -= *sl; - sl += 1; - sr += 1; - d += 1; + acc += *sr++; + *d++ = DIVIDE(acc); + acc -= *sl++; } // Right edge - for (int k = right; k; k--) + count = 2 * radius + 1; + while (sl < sle) { - *d = acc / (k + right); - acc -= *sl; - d += 1; - sl += 1; + *d++ = acc / (--count); + acc -= *sl++; } // More runs to go: swap spans diff --git a/src/lib/evas/filters/blur/blur_box_rgba_.c b/src/lib/evas/filters/blur/blur_box_rgba_.c index 95d381a..7c22c65 100644 --- a/src/lib/evas/filters/blur/blur_box_rgba_.c +++ b/src/lib/evas/filters/blur/blur_box_rgba_.c @@ -32,6 +32,8 @@ _box_blur_horiz_rgba_step(const DATA32* restrict const srcdata, span1 = alloca(len * sizeof(DATA32)); span2 = alloca(len * sizeof(DATA32)); + memset(span1, 0, len * sizeof(DATA32)); + memset(span2, 0, len * sizeof(DATA32)); // For each line, apply as many blurs as requested for (int l = 0; l < loops; l++) @@ -50,7 +52,6 @@ _box_blur_horiz_rgba_step(const DATA32* restrict const srcdata, { const int radius = radii[run]; const int left = MIN(radius, len); - const int right = MIN(radius, (len - radius)); #if DIV_USING_BITSHIFT const int pow2 = pow2_shifts[run]; @@ -61,39 +62,44 @@ _box_blur_horiz_rgba_step(const DATA32* restrict const srcdata, const DATA8* restrict sl = (DATA8 *) src; const DATA8* restrict sr = (DATA8 *) src; + const DATA8* restrict sre = (DATA8 *) (src + len); + const DATA8* restrict sle = (DATA8 *) (src + len - radius); DATA8* restrict d = (DATA8 *) dst; int acc[4] = {0}; - int x, k; + int count = 0; // Read-ahead - for (x = left; x; x--) + for (int x = left; x > 0; x--) { - for (k = 0; k < 4; k++) + for (int k = 0; k < 4; k++) acc[k] += sr[k]; sr += sizeof(DATA32); + count++; } // Left - for (x = 0; x < left; x++) + for (int x = left; x > 0; x--) { - for (k = 0; k < 4; k++) - acc[k] += sr[k]; - sr += sizeof(DATA32); + if (sr < sre) + { + for (int k = 0; k < 4; k++) + acc[k] += sr[k]; + sr += sizeof(DATA32); + count++; + } - const int divider = x + left + 1; - d[ALPHA] = acc[ALPHA] / divider; - d[RED] = acc[RED] / divider; - d[GREEN] = acc[GREEN] / divider; - d[BLUE] = acc[BLUE] / divider; + d[ALPHA] = acc[ALPHA] / count; + d[RED] = acc[RED] / count; + d[GREEN] = acc[GREEN] / count; + d[BLUE] = acc[BLUE] / count; d += sizeof(DATA32); } // Main part - for (x = len - (2 * radius); x > 0; x--) + for (; sr < sre; sr += sizeof(DATA32), sl += sizeof(DATA32)) { - for (k = 0; k < 4; k++) + for (int k = 0; k < 4; k++) acc[k] += sr[k]; - sr += sizeof(DATA32); d[ALPHA] = DIVIDE(acc[ALPHA]); d[RED] = DIVIDE(acc[RED]); @@ -101,24 +107,23 @@ _box_blur_horiz_rgba_step(const DATA32* restrict const srcdata, d[BLUE] = DIVIDE(acc[BLUE]); d += sizeof(DATA32); - for (k = 0; k < 4; k++) + for (int k = 0; k < 4; k++) acc[k] -= sl[k]; - sl += sizeof(DATA32); } // Right part - for (x = right; x; x--) + count = 2 * radius + 1; + for (; sl < sle; sl += sizeof(DATA32)) { - const int divider = x + right; + const int divider = --count; d[ALPHA] = acc[ALPHA] / divider; d[RED] = acc[RED] / divider; d[GREEN] = acc[GREEN] / divider; d[BLUE] = acc[BLUE] / divider; d += sizeof(DATA32); - for (k = 0; k < 4; k++) + for (int k = 0; k < 4; k++) acc[k] -= sl[k]; - sl += sizeof(DATA32); } // More runs to go: swap spans @@ -173,6 +178,8 @@ _box_blur_vert_rgba_step(const DATA32* restrict const srcdata, span1 = alloca(len * sizeof(DATA32)); span2 = alloca(len * sizeof(DATA32)); + memset(span1, 0, len * sizeof(DATA32)); + memset(span2, 0, len * sizeof(DATA32)); // For each line, apply as many blurs as requested for (int l = 0; l < loops; l++) @@ -196,7 +203,6 @@ _box_blur_vert_rgba_step(const DATA32* restrict const srcdata, { const int radius = radii[run]; const int left = MIN(radius, len); - const int right = MIN(radius, (len - radius)); #if DIV_USING_BITSHIFT const int pow2 = pow2_shifts[run]; @@ -207,39 +213,44 @@ _box_blur_vert_rgba_step(const DATA32* restrict const srcdata, const DATA8* restrict sl = (DATA8 *) src; const DATA8* restrict sr = (DATA8 *) src; + const DATA8* restrict sre = (DATA8 *) (src + len); + const DATA8* restrict sle = (DATA8 *) (src + len - radius); DATA8* restrict d = (DATA8 *) dst; int acc[4] = {0}; - int x, k; + int count = 0; // Read-ahead - for (x = left; x; x--) + for (int x = left; x > 0; x--) { - for (k = 0; k < 4; k++) + for (int k = 0; k < 4; k++) acc[k] += sr[k]; sr += sizeof(DATA32); + count++; } // Left - for (x = 0; x < left; x++) + for (int x = left; x > 0; x--) { - for (k = 0; k < 4; k++) - acc[k] += sr[k]; - sr += sizeof(DATA32); + if (sr < sre) + { + for (int k = 0; k < 4; k++) + acc[k] += sr[k]; + sr += sizeof(DATA32); + count++; + } - const int divider = x + left + 1; - d[ALPHA] = acc[ALPHA] / divider; - d[RED] = acc[RED] / divider; - d[GREEN] = acc[GREEN] / divider; - d[BLUE] = acc[BLUE] / divider; + d[ALPHA] = acc[ALPHA] / count; + d[RED] = acc[RED] / count; + d[GREEN] = acc[GREEN] / count; + d[BLUE] = acc[BLUE] / count; d += sizeof(DATA32); } // Main part - for (x = len - (2 * radius); x > 0; x--) + for (; sr < sre; sr += sizeof(DATA32), sl += sizeof(DATA32)) { - for (k = 0; k < 4; k++) + for (int k = 0; k < 4; k++) acc[k] += sr[k]; - sr += sizeof(DATA32); d[ALPHA] = DIVIDE(acc[ALPHA]); d[RED] = DIVIDE(acc[RED]); @@ -247,24 +258,23 @@ _box_blur_vert_rgba_step(const DATA32* restrict const srcdata, d[BLUE] = DIVIDE(acc[BLUE]); d += sizeof(DATA32); - for (k = 0; k < 4; k++) + for (int k = 0; k < 4; k++) acc[k] -= sl[k]; - sl += sizeof(DATA32); } // Right part - for (x = right; x; x--) + count = 2 * radius + 1; + for (; sl < sle; sl += sizeof(DATA32)) { - const int divider = x + right; + const int divider = --count; d[ALPHA] = acc[ALPHA] / divider; d[RED] = acc[RED] / divider; d[GREEN] = acc[GREEN] / divider; d[BLUE] = acc[BLUE] / divider; d += sizeof(DATA32); - for (k = 0; k < 4; k++) + for (int k = 0; k < 4; k++) acc[k] -= sl[k]; - sl += sizeof(DATA32); } // More runs to go: swap spans diff --git a/src/lib/evas/filters/evas_filter_blur.c b/src/lib/evas/filters/evas_filter_blur.c index 36a06e1..955fc64 100644 --- a/src/lib/evas/filters/evas_filter_blur.c +++ b/src/lib/evas/filters/evas_filter_blur.c @@ -73,7 +73,6 @@ _box_blur_horiz_apply_rgba(Evas_Filter_Command *cmd) EINA_SAFETY_ON_NULL_RETURN_VAL(in->image.data, EINA_FALSE); EINA_SAFETY_ON_NULL_RETURN_VAL(out->image.data, EINA_FALSE); - EINA_SAFETY_ON_FALSE_RETURN_VAL(out->cache_entry.w >= (2*r + 1), EINA_FALSE); _box_blur_horiz_rgba(in->image.data, out->image.data, radii, in->cache_entry.w, in->cache_entry.h); @@ -103,7 +102,6 @@ _box_blur_vert_apply_rgba(Evas_Filter_Command *cmd) EINA_SAFETY_ON_NULL_RETURN_VAL(in->image.data, EINA_FALSE); EINA_SAFETY_ON_NULL_RETURN_VAL(out->image.data, EINA_FALSE); - EINA_SAFETY_ON_FALSE_RETURN_VAL(out->cache_entry.h >= (2*r + 1), EINA_FALSE); _box_blur_vert_rgba(in->image.data, out->image.data, radii, in->cache_entry.w, in->cache_entry.h); @@ -151,7 +149,6 @@ _box_blur_horiz_apply_alpha(Evas_Filter_Command *cmd) EINA_SAFETY_ON_NULL_RETURN_VAL(in->image.data8, EINA_FALSE); EINA_SAFETY_ON_NULL_RETURN_VAL(out->image.data8, EINA_FALSE); - EINA_SAFETY_ON_FALSE_RETURN_VAL(out->cache_entry.w >= (2*r + 1), EINA_FALSE); _box_blur_horiz_alpha(in->image.data8, out->image.data8, radii, in->cache_entry.w, in->cache_entry.h); @@ -181,7 +178,6 @@ _box_blur_vert_apply_alpha(Evas_Filter_Command *cmd) EINA_SAFETY_ON_NULL_RETURN_VAL(in->image.data8, EINA_FALSE); EINA_SAFETY_ON_NULL_RETURN_VAL(out->image.data8, EINA_FALSE); - EINA_SAFETY_ON_FALSE_RETURN_VAL(out->cache_entry.h >= (2*r + 1), EINA_FALSE); _box_blur_vert_alpha(in->image.data8, out->image.data8, radii, in->cache_entry.w, in->cache_entry.h); @@ -317,7 +313,6 @@ _gaussian_blur_horiz_apply_alpha(Evas_Filter_Command *cmd) EINA_SAFETY_ON_NULL_RETURN_VAL(in->image.data8, EINA_FALSE); EINA_SAFETY_ON_NULL_RETURN_VAL(out->image.data8, EINA_FALSE); - EINA_SAFETY_ON_FALSE_RETURN_VAL(out->cache_entry.w >= (2*r + 1), EINA_FALSE); _gaussian_blur_horiz_alpha(in->image.data8, out->image.data8, r, in->cache_entry.w, in->cache_entry.h); @@ -341,7 +336,6 @@ _gaussian_blur_vert_apply_alpha(Evas_Filter_Command *cmd) EINA_SAFETY_ON_NULL_RETURN_VAL(in->image.data8, EINA_FALSE); EINA_SAFETY_ON_NULL_RETURN_VAL(out->image.data8, EINA_FALSE); - EINA_SAFETY_ON_FALSE_RETURN_VAL(out->cache_entry.h >= (2*r + 1), EINA_FALSE); _gaussian_blur_vert_alpha(in->image.data8, out->image.data8, r, in->cache_entry.w, in->cache_entry.h); @@ -365,7 +359,6 @@ _gaussian_blur_horiz_apply_rgba(Evas_Filter_Command *cmd) EINA_SAFETY_ON_NULL_RETURN_VAL(in->image.data, EINA_FALSE); EINA_SAFETY_ON_NULL_RETURN_VAL(out->image.data, EINA_FALSE); - EINA_SAFETY_ON_FALSE_RETURN_VAL(out->cache_entry.w >= (2*r + 1), EINA_FALSE); _gaussian_blur_horiz_rgba(in->image.data, out->image.data, r, in->cache_entry.w, in->cache_entry.h); @@ -389,7 +382,6 @@ _gaussian_blur_vert_apply_rgba(Evas_Filter_Command *cmd) EINA_SAFETY_ON_NULL_RETURN_VAL(in->image.data, EINA_FALSE); EINA_SAFETY_ON_NULL_RETURN_VAL(out->image.data, EINA_FALSE); - EINA_SAFETY_ON_FALSE_RETURN_VAL(out->cache_entry.h >= (2*r + 1), EINA_FALSE); _gaussian_blur_vert_rgba(in->image.data, out->image.data, r, in->cache_entry.w, in->cache_entry.h); -- 2.7.4