forked from enlightenment/efl
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:
parent
919b32be20
commit
c7616dd738
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue