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).
This commit is contained in:
Jean-Philippe Andre 2014-03-20 18:26:04 +09:00
parent 919b32be20
commit c7616dd738
3 changed files with 102 additions and 98 deletions

View File

@ -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

View File

@ -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

View File

@ -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);