[gegl] Bug 680184: 'gegl_buffer_get' returns different values for the same pixel
- From: Ãyvind KolÃs <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] Bug 680184: 'gegl_buffer_get' returns different values for the same pixel
- Date: Mon, 4 Feb 2013 06:50:02 +0000 (UTC)
commit b3767e7f7daf23d0ea5208708864bcc05e70823a
Author: Massimo Valentini <mvalentini src gnome org>
Date: Thu Aug 9 17:27:25 2012 +0200
Bug 680184: 'gegl_buffer_get' returns different values for the same pixel
gegl/buffer/gegl-buffer-access.c | 444 ++++++++++++--------------------------
1 files changed, 142 insertions(+), 302 deletions(-)
---
diff --git a/gegl/buffer/gegl-buffer-access.c b/gegl/buffer/gegl-buffer-access.c
index e6ec2a0..8885982 100644
--- a/gegl/buffer/gegl-buffer-access.c
+++ b/gegl/buffer/gegl-buffer-access.c
@@ -1190,12 +1190,16 @@ gegl_buffer_iterate_read_dispatch (GeglBuffer *buffer,
GeglRectangle abyss = buffer->abyss;
GeglRectangle abyss_factored = abyss;
GeglRectangle roi_factored = *roi;
- gint factor = 1<<level;
+ const gint factor = 1 << level;
+ const gint x1 = buffer->shift_x + abyss.x;
+ const gint y1 = buffer->shift_y + abyss.y;
+ const gint x2 = buffer->shift_x + abyss.x + abyss.width;
+ const gint y2 = buffer->shift_y + abyss.y + abyss.height;
- abyss_factored.x = (buffer->shift_x + abyss.x) / factor;
- abyss_factored.y = (buffer->shift_y + abyss.y) / factor;
- abyss_factored.width /= factor;
- abyss_factored.height /= factor;
+ abyss_factored.x = (x1 + (x1 < 0 ? 1 - factor : 0)) / factor;
+ abyss_factored.y = (y1 + (y1 < 0 ? 1 - factor : 0)) / factor;
+ abyss_factored.width = (x2 + (x2 < 0 ? 0 : factor - 1)) / factor - abyss_factored.x;
+ abyss_factored.height = (y2 + (y2 < 0 ? 0 : factor - 1)) / factor - abyss_factored.y;
roi_factored.x = (buffer->shift_x + roi_factored.x) / factor;
roi_factored.y = (buffer->shift_y + roi_factored.y) / factor;
@@ -1299,161 +1303,73 @@ gegl_buffer_set (GeglBuffer *buffer,
gegl_buffer_unlock (buffer);
}
-
-#if 0
-/*
- * slow nearest neighbour resampler that seems to be
- * completely correct.
- */
-
-static void
-resample_nearest (void *dest_buf,
- void *source_buf,
- gint dest_w,
- gint dest_h,
- gint source_w,
- gint source_h,
- gdouble offset_x,
- gdouble offset_y,
- gdouble scale,
- gint bpp,
- gint rowstride)
-{
- gint x, y;
-
- if (rowstride == GEGL_AUTO_ROWSTRIDE)
- rowstride = dest_w * bpp;
-
- for (y = 0; y < dest_h; y++)
- {
- gint sy;
- guchar *dst;
- guchar *src_base;
-
- sy = (y + offset_y) / scale;
-
-
- if (sy >= source_h)
- sy = source_h - 1;
-
- dst = ((guchar *) dest_buf) + y * rowstride;
- src_base = ((guchar *) source_buf) + sy * source_w * bpp;
-
- for (x = 0; x < dest_w; x++)
- {
- gint sx;
- guchar *src;
- sx = (x + offset_x) / scale;
-
- if (sx >= source_w)
- sx = source_w - 1;
- src = src_base + sx * bpp;
-
- memcpy (dst, src, bpp);
- dst += bpp;
- }
- }
-}
+#ifdef BOXFILTER_FLOAT
+typedef float T;
+#define double2T(a) (a)
+#define projectionT babl_type ("float")
+#define T_components babl_format_get_n_components (format)
+#else
+typedef guchar T;
+#define double2T(a) (lrint (a))
+#define projectionT babl_type ("u8")
+#define T_components bpp
#endif
+#define EPSILON 1.e-6
-/* Optimized|obfuscated version of the nearest neighbour resampler
- * XXX: seems to contains some very slight inprecision in the rendering.
- */
static void
-resample_nearest (void *dest_buf,
- void *source_buf,
- gint dest_w,
- gint dest_h,
- gint source_w,
- gint source_h,
- gdouble offset_x,
- gdouble offset_y,
- gdouble scale,
- gint bpp,
- gint rowstride)
+resample_nearest (guchar *dst,
+ const guchar *src,
+ const GeglRectangle *dst_rect,
+ const GeglRectangle *src_rect,
+ const gint src_stride,
+ const gdouble scale,
+ const gint bpp,
+ const gint dst_stride)
{
- gint x, y;
- guint xdiff, ydiff, xstart, sy;
+ int i, j;
- if (rowstride == GEGL_AUTO_ROWSTRIDE)
- rowstride = dest_w * bpp;
-
- xdiff = 65536 / scale;
- ydiff = 65536 / scale;
- xstart = (offset_x * 65536) / scale;
- sy = (offset_y * 65536) / scale;
-
- for (y = 0; y < dest_h; y++)
+ for (i = 0; i < dst_rect->height; i++)
{
- guchar *dst;
- guchar *src_base;
- guint sx;
- guint px = 0;
- guchar *src;
-
- if (sy >= source_h << 16)
- sy = (source_h - 1) << 16;
-
- dst = ((guchar *) dest_buf) + y * rowstride;
- src_base = ((guchar *) source_buf) + (sy >> 16) * source_w * bpp;
+ const gdouble sy = (dst_rect->y + .5 + i) / scale - src_rect->y;
+ const gint ii = floor (sy + EPSILON);
- sx = xstart;
- src = src_base;
-
- /* this is the loop that is actually properly optimized,
- * portions of the setup is done for all the rows outside the y
- * loop as well */
- for (x = 0; x < dest_w; x++)
+ for (j = 0; j < dst_rect->width; j++)
{
- gint diff;
- gint ssx = sx>>16;
- if ( (diff = ssx - px) > 0)
- {
- if (ssx < source_w)
- src += diff * bpp;
- px += diff;
- }
- memcpy (dst, src, bpp);
- dst += bpp;
- sx += xdiff;
+ const gdouble sx = (dst_rect->x + .5 + j) / scale - src_rect->x;
+ const gint jj = floor (sx + EPSILON);
+
+ memcpy (&dst[i * dst_stride + j * bpp],
+ &src[ii * src_stride + jj * bpp],
+ bpp);
}
- sy += ydiff;
}
}
static inline void
-box_filter (guint left_weight,
- guint center_weight,
- guint right_weight,
- guint top_weight,
- guint middle_weight,
- guint bottom_weight,
- guint sum,
- const guchar **src, /* the 9 surrounding source pixels */
- guchar *dest,
- gint components)
+box_filter (gdouble left_weight,
+ gdouble center_weight,
+ gdouble right_weight,
+ gdouble top_weight,
+ gdouble middle_weight,
+ gdouble bottom_weight,
+ const T **src, /* the 9 surrounding source pixels */
+ T *dest,
+ gint components)
{
- /* NOTE: this box filter presumes pre-multiplied alpha, if there
- * is alpha.
- */
- guint lt, lm, lb;
- guint ct, cm, cb;
- guint rt, rm, rb;
-
- lt = left_weight * top_weight;
- lm = left_weight * middle_weight;
- lb = left_weight * bottom_weight;
- ct = center_weight * top_weight;
- cm = center_weight * middle_weight;
- cb = center_weight * bottom_weight;
- rt = right_weight * top_weight;
- rm = right_weight * middle_weight;
- rb = right_weight * bottom_weight;
+ const gdouble lt = left_weight * top_weight;
+ const gdouble lm = left_weight * middle_weight;
+ const gdouble lb = left_weight * bottom_weight;
+ const gdouble ct = center_weight * top_weight;
+ const gdouble cm = center_weight * middle_weight;
+ const gdouble cb = center_weight * bottom_weight;
+ const gdouble rt = right_weight * top_weight;
+ const gdouble rm = right_weight * middle_weight;
+ const gdouble rb = right_weight * bottom_weight;
#define docomponent(i) \
- dest[i] = (src[0][i] * lt + src[3][i] * lm + src[6][i] * lb + \
- src[1][i] * ct + src[4][i] * cm + src[7][i] * cb + \
- src[2][i] * rt + src[5][i] * rm + src[8][i] * rb) / sum
+ dest[i] = double2T (src[0][i] * lt + src[3][i] * lm + src[6][i] * lb + \
+ src[1][i] * ct + src[4][i] * cm + src[7][i] * cb + \
+ src[2][i] * rt + src[5][i] * rm + src[8][i] * rb)
switch (components)
{
case 5: docomponent(4);
@@ -1466,100 +1382,43 @@ box_filter (guint left_weight,
}
static void
-resample_boxfilter_u8 (void *dest_buf,
- void *source_buf,
- gint dest_w,
- gint dest_h,
- gint source_w,
- gint source_h,
- gdouble offset_x,
- gdouble offset_y,
- gdouble scale,
- gint components,
- gint rowstride)
+resample_boxfilter_T (guchar *dest_buf,
+ const guchar *source_buf,
+ const GeglRectangle *dst_rect,
+ const GeglRectangle *src_rect,
+ const gint s_rowstride,
+ const gdouble scale,
+ const gint components,
+ const gint d_rowstride)
{
- gint x, y;
- gint iscale = scale * 256;
- gint s_rowstride = source_w * components;
- gint d_rowstride = dest_w * components;
-
- gint footprint_x;
- gint footprint_y;
- guint foosum;
-
- guint left_weight;
- guint center_weight;
- guint right_weight;
-
- guint top_weight;
- guint middle_weight;
- guint bottom_weight;
+ gdouble left_weight, center_weight, right_weight;
+ gdouble top_weight, middle_weight, bottom_weight;
+ const T *src[9];
+ gint x, y;
- footprint_y = (1.0 / scale) * 256;
- footprint_x = (1.0 / scale) * 256;
- foosum = footprint_x * footprint_y;
-
- if (rowstride != GEGL_AUTO_ROWSTRIDE)
- d_rowstride = rowstride;
-
- for (y = 0; y < dest_h; y++)
+ for (y = 0; y < dst_rect->height; y++)
{
- gint sy;
- gint dy;
- guchar *dst;
- const guchar *src_base;
- gint sx;
- gint xdelta;
-
- sy = ((y + offset_y) * 65536) / iscale;
-
- if (sy >= (source_h - 1) << 8)
- sy = (source_h - 2) << 8;/* is this the right thing to do? */
+ const gdouble sy = (dst_rect->y + y + .5) / scale - src_rect->y;
+ const gint ii = floor (sy);
+ T *dst = (T*)(dest_buf + y * d_rowstride);
+ const guchar *src_base = source_buf + ii * s_rowstride;
- dy = sy & 255;
-
- dst = ((guchar *) dest_buf) + y * d_rowstride;
- src_base = ((guchar *) source_buf) + (sy >> 8) * s_rowstride;
-
- if (dy > footprint_y / 2)
- top_weight = 0;
- else
- top_weight = footprint_y / 2 - dy;
-
- if (0xff - dy > footprint_y / 2)
- bottom_weight = 0;
- else
- bottom_weight = footprint_y / 2 - (0xff - dy);
+ top_weight = MAX (0., .5 - scale * (sy - ii));
+ bottom_weight = MAX (0., .5 - scale * ((ii + 1 ) - sy));
+ middle_weight = 1. - top_weight - bottom_weight;
- middle_weight = footprint_y - top_weight - bottom_weight;
-
- sx = (offset_x *65536) / iscale;
- xdelta = 65536/iscale;
-
- /* XXX: needs quite a bit of optimization */
- for (x = 0; x < dest_w; x++)
+ for (x = 0; x < dst_rect->width; x++)
{
- gint dx;
- const guchar *src[9];
+ const gdouble sx = (dst_rect->x + x + .5) / scale - src_rect->x;
+ const gint jj = floor (sx);
- /*sx = (x << 16) / iscale;*/
- dx = sx & 255;
+ left_weight = MAX (0., .5 - scale * (sx - jj));
+ right_weight = MAX (0., .5 - scale * ((jj + 1) - sx));
+ center_weight = 1. - left_weight - right_weight;
- if (dx > footprint_x / 2)
- left_weight = 0;
- else
- left_weight = footprint_x / 2 - dx;
-
- if (0xff - dx > footprint_x / 2)
- right_weight = 0;
- else
- right_weight = footprint_x / 2 - (0xff - dx);
-
- center_weight = footprint_x - left_weight - right_weight;
-
- src[4] = src_base + (sx >> 8) * components;
- src[1] = src[4] - s_rowstride;
- src[7] = src[4] + s_rowstride;
+ src[4] = (const T*)src_base + jj * components;
+ src[1] = (const T*)(src_base - s_rowstride) + jj * components;
+ src[7] = (const T*)(src_base + s_rowstride) + jj * components;
src[2] = src[1] + components;
src[5] = src[4] + components;
@@ -1569,46 +1428,17 @@ resample_boxfilter_u8 (void *dest_buf,
src[3] = src[4] - components;
src[6] = src[7] - components;
- if ((sx >>8) - 1<0)
- {
- src[0]=src[1];
- src[3]=src[4];
- src[6]=src[7];
- }
- if ((sy >> 8) - 1 < 0)
- {
- src[0]=src[3];
- src[1]=src[4];
- src[2]=src[5];
- }
- if ((sx >>8) + 1 >= source_w)
- {
- src[2]=src[1];
- src[5]=src[4];
- src[8]=src[7];
- break;
- }
- if ((sy >> 8) + 1 >= source_h)
- {
- src[6]=src[3];
- src[7]=src[4];
- src[8]=src[5];
- }
-
box_filter (left_weight,
center_weight,
right_weight,
top_weight,
middle_weight,
bottom_weight,
- foosum,
src, /* the 9 surrounding source pixels */
dst,
components);
-
dst += components;
- sx += xdelta;
}
}
}
@@ -1667,77 +1497,87 @@ gegl_buffer_get_unlocked (GeglBuffer *buffer,
else
{
gint level = 0;
- gint buf_width = rect->width / scale;
- gint buf_height = rect->height / scale;
+ gint buf_width;
+ gint buf_height;
gint bpp = babl_format_get_bytes_per_pixel (format);
GeglRectangle sample_rect;
void *sample_buf;
+ gint x1 = floor (rect->x / scale + EPSILON);
+ gint x2 = ceil ((rect->x + rect->width) / scale - EPSILON);
+ gint y1 = floor (rect->y / scale + EPSILON);
+ gint y2 = ceil ((rect->y + rect->height) / scale - EPSILON);
gint factor = 1;
- gdouble offset_x;
- gdouble offset_y;
-
- sample_rect.x = floor(rect->x/scale);
- sample_rect.y = floor(rect->y/scale);
- sample_rect.width = buf_width;
- sample_rect.height = buf_height;
+ gint stride;
+ gint offset = 0;
while (scale <= 0.5)
{
+ x1 = 0 < x1 ? x1 / 2 : (x1 - 1) / 2;
+ y1 = 0 < y1 ? y1 / 2 : (y1 - 1) / 2;
+ x2 = 0 < x2 ? (x2 + 1) / 2 : x2 / 2;
+ y2 = 0 < y2 ? (y2 + 1) / 2 : y2 / 2;
scale *= 2;
factor *= 2;
level++;
}
- buf_width /= factor;
- buf_height /= factor;
+ buf_width = x2 - x1;
+ buf_height = y2 - y1;
/* ensure we always have some data to sample from */
- sample_rect.width += factor * 2;
- sample_rect.height += factor * 2;
- buf_width += 2;
- buf_height += 2;
+ if (scale != 1.0 && scale < 1.99 &&
+ babl_format_get_type (format, 0) == projectionT)
+ {
+ buf_width += 2;
+ buf_height += 2;
+ offset = (buf_width + 1) * bpp;
+ }
+
+ sample_rect.x = factor * x1;
+ sample_rect.y = factor * y1;
+ sample_rect.width = factor * (x2 - x1);
+ sample_rect.height = factor * (y2 - y1);
- offset_x = rect->x-floor(rect->x/scale) * scale;
- offset_y = rect->y-floor(rect->y/scale) * scale;
+ sample_buf = scale == 1.0 ? dest_buf : g_malloc0 (buf_height * buf_width * bpp);
+ stride = scale == 1.0 ? rowstride : buf_width * bpp;
- sample_buf = g_malloc (buf_width * buf_height * bpp);
- gegl_buffer_iterate_read_dispatch (buffer, &sample_rect, sample_buf, GEGL_AUTO_ROWSTRIDE,
+ gegl_buffer_iterate_read_dispatch (buffer, &sample_rect, (guchar*)sample_buf + offset, stride,
format, level, repeat_mode);
-#if 1
- /* slows testing of rendering code speed too much for now and
- * no time to make a fast implementation
- */
- if (babl_format_get_type (format, 0) == babl_type ("u8")
- && !(level == 0 && scale > 1.99))
+ if (scale == 1.0)
+ return;
+
+ if (rowstride == GEGL_AUTO_ROWSTRIDE)
+ rowstride = rect->width * bpp;
+
+ if (scale <= 1.99 && babl_format_get_type (format, 0) == projectionT)
{ /* do box-filter resampling if we're 8bit (which projections are) */
+ sample_rect.x = x1 - 1;
+ sample_rect.y = y1 - 1;
+ sample_rect.width = x2 - x1 + 2;
+ sample_rect.height = y2 - y1 + 2;
- /* XXX: use box-filter also for > 1.99 when testing and probably
- * later, there are some bugs when doing so
- */
- resample_boxfilter_u8 (dest_buf,
+ resample_boxfilter_T (dest_buf,
sample_buf,
- rect->width,
- rect->height,
- buf_width,
- buf_height,
- offset_x,
- offset_y,
+ rect,
+ &sample_rect,
+ buf_width * bpp,
scale,
- bpp,
+ T_components,
rowstride);
}
else
-#endif
{
+ sample_rect.x = x1;
+ sample_rect.y = y1;
+ sample_rect.width = x2 - x1;
+ sample_rect.height = y2 - y1;
+
resample_nearest (dest_buf,
sample_buf,
- rect->width,
- rect->height,
- buf_width,
- buf_height,
- offset_x,
- offset_y,
+ rect,
+ &sample_rect,
+ buf_width * bpp,
scale,
bpp,
rowstride);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]