diff --git a/ChangeLog b/ChangeLog index c116ed2af8..ce7eaa4d83 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2003-03-17 Sven Neumann + + Applied patches from David Necas that fix + incorrect RGBA resampling in a number of plug-ins: + + * plug-ins/common/fractaltrace.c: fixes bug #72873. + * plug-ins/common/tiler.c: fixes bug #72875. + * plug-ins/common/waves.c: fixes bug #72870. + * plug-ins/common/whirlpinch.c: fixes bug #72871. + 2003-03-17 Michael Natterer * app/core/core-enums.[ch]: added GIMP_UNDO_CHANNEL_COLOR. diff --git a/plug-ins/common/fractaltrace.c b/plug-ins/common/fractaltrace.c index 26a6121f5b..0060c272f5 100644 --- a/plug-ins/common/fractaltrace.c +++ b/plug-ins/common/fractaltrace.c @@ -337,6 +337,7 @@ pixels_get (gint x, } } +#include static void pixels_get_biliner (gdouble x, gdouble y, @@ -346,6 +347,7 @@ pixels_get_biliner (gdouble x, gdouble a, b, c, d; gint x1, y1, x2, y2; gdouble dx, dy; + gdouble alpha; x1 = (gint) floor (x); x2 = x1 + 1; @@ -364,14 +366,25 @@ pixels_get_biliner (gdouble x, pixels_get (x1, y2, &C); pixels_get (x2, y2, &D); - pixel->r = (guchar) (a * (gdouble) A.r + b * (gdouble) B.r + - c * (gdouble) C.r + d * (gdouble) D.r); - pixel->g = (guchar) (a * (gdouble) A.g + b * (gdouble) B.g + - c * (gdouble) C.g + d * (gdouble) D.g); - pixel->b = (guchar) (a * (gdouble) A.b + b * (gdouble) B.b + - c * (gdouble) C.b + d * (gdouble) D.b); - pixel->a = (guchar) (a * (gdouble) A.a + b * (gdouble) B.a + - c * (gdouble) C.a + d * (gdouble) D.a); + alpha = 1.0001*(a * (gdouble) A.a + b * (gdouble) B.a + + c * (gdouble) C.a + d * (gdouble) D.a); + pixel->a = (guchar) alpha; + + if (pixel->a) + { + pixel->r = (guchar) ((a * (gdouble) A.r * A.a + + b * (gdouble) B.r * B.a + + c * (gdouble) C.r * C.a + + d * (gdouble) D.r * D.a) / alpha); + pixel->g = (guchar) ((a * (gdouble) A.g * A.a + + b * (gdouble) B.g * B.a + + c * (gdouble) C.g * C.a + + d * (gdouble) D.g * D.a) / alpha); + pixel->b = (guchar) ((a * (gdouble) A.b * A.a + + b * (gdouble) B.b * B.a + + c * (gdouble) C.b * C.a + + d * (gdouble) D.b * D.a) / alpha); + } } static void @@ -531,15 +544,26 @@ dialog_preview_setpixel (gint x, gint y, pixel_t *pixel) { + guchar grayshade; + + if (pixel->a) + grayshade = pixel->r; + else + grayshade = + (((x % (GIMP_CHECK_SIZE * 2) < GIMP_CHECK_SIZE) ? + (y % (GIMP_CHECK_SIZE * 2) < GIMP_CHECK_SIZE) : + (y % (GIMP_CHECK_SIZE * 2) > GIMP_CHECK_SIZE)) ? + GIMP_CHECK_LIGHT : GIMP_CHECK_DARK) * 255; + switch (preview.bpp) { case 1: - preview.pixels[y][x*preview.bpp] = pixel->r; + preview.pixels[y][x * preview.bpp] = grayshade; break; case 3: - preview.pixels[y][x*preview.bpp] = pixel->r; - preview.pixels[y][x*preview.bpp+1] = pixel->g; - preview.pixels[y][x*preview.bpp+2] = pixel->b; + preview.pixels[y][x * preview.bpp] = grayshade; + preview.pixels[y][x * preview.bpp + 1] = pixel->a ? pixel->g : grayshade; + preview.pixels[y][x * preview.bpp + 2] = pixel->a ? pixel->b : grayshade; break; } } @@ -651,9 +675,11 @@ dialog_preview_draw (void) break; case OUTSIDE_TYPE_BLACK: pixel.r = pixel.g = pixel.b = 0; + pixel.a = 255; break; case OUTSIDE_TYPE_WHITE: pixel.r = pixel.g = pixel.b = 255; + pixel.a = 255; break; } } diff --git a/plug-ins/common/tiler.c b/plug-ins/common/tiler.c index bb977b9bf1..d72b869052 100644 --- a/plug-ins/common/tiler.c +++ b/plug-ins/common/tiler.c @@ -35,12 +35,6 @@ static void run (gchar *name, GimpParam **return_vals); static void tile (GimpDrawable *drawable); -static gint scale (gint width, - gint height, - gint x, - gint y, - gint data); - GimpPlugInInfo PLUG_IN_INFO = { @@ -119,43 +113,70 @@ run (gchar *name, gimp_drawable_detach (drawable); } -static gint -scale (gint width, - gint height, - gint x, - gint y, - gint data) +static void +weld_pixels (guchar *dest1, + guchar *dest2, + gint width, + gint height, + gint x, + gint y, + guint bpp, + guchar *src1, + guchar *src2) { - gint A = width/2-1; - gint B = height/2-1; - gint a, b; + gdouble a = (ABS(x - width) - 1)/ (gdouble) (width - 1); + gdouble b = (ABS(y - height) - 1) / (gdouble) (height - 1); + gdouble w; + guint i; - if (x < width/2) - a = width/2 - x - 1; + /* mimic ambiguous point handling in original algorithm */ + if (a < 1e-8 && b > 0.99999999) + w = 1.0; + else if (a > 0.99999999 && b < 1e-8) + w = 0.0; else - a = x - width/2 - (width & 1); + w = 1.0 - a*b/(a*b + (1.0 - a)*(1.0 - b)); - if (y < height/2) - b = height/2 - y -1; + for (i = 0; i < bpp; i++) + dest1[i] = dest2[i] = (guchar) (w * src1[i] + (1.0 - w) * src2[i]); +} + +static void +weld_pixels_alpha (guchar *dest1, + guchar *dest2, + gint width, + gint height, + gint x, + gint y, + guint bpp, + guchar *src1, + guchar *src2) +{ + gdouble a = (ABS(x - width) - 1)/ (gdouble) (width - 1); + gdouble b = (ABS(y - height) - 1) / (gdouble) (height - 1); + gdouble w; + gdouble alpha; + guint ai = bpp-1; + guint i; + + /* mimic ambiguous point handling in original algorithm */ + if (a < 1e-8 && b > 0.99999999) + w = 1.0; + else if (a > 0.99999999 && b < 1e-8) + w = 0.0; else - b = y - height/2 - (height & 1); - - if ((B*adrawable_id); + has_alpha = gimp_drawable_has_alpha (drawable->drawable_id); height = y2 - y1; width = x2 - x1; @@ -196,6 +220,8 @@ tile_region (GimpDrawable *drawable, gboolean left, off_x = -w - wodd; } + asymmetry_correction = !wodd && !left; + gimp_pixel_rgn_init (&src1_rgn, drawable, rgn1_x, y1, w, h, FALSE, FALSE); gimp_pixel_rgn_init (&dest1_rgn, drawable, rgn1_x, y1, w, h, TRUE, TRUE); gimp_pixel_rgn_init (&src2_rgn, drawable, rgn2_x, y1 + h + hodd, @@ -224,22 +250,30 @@ tile_region (GimpDrawable *drawable, gboolean left, guchar *d2 = dest2; gint col = src1_rgn.x - x1; - for (x = 0; x < src1_rgn.w; x++, col++) - { - gint c; - - for (c = 0; c < bpp; c++) - { - gint val = scale (width, height, col, row, s1[c]) + - scale (width, height, col + off_x, row + h + hodd, s2[c]); - - d1[c] = d2[c] = (val > 255) ? 255 : val; - } - s1 += bpp; - s2 += bpp; - d1 += bpp; - d2 += bpp; - } + if (has_alpha) + { + for (x = 0; x < src1_rgn.w; x++, col++) + { + weld_pixels_alpha (d1, d2, w, h, col + asymmetry_correction, + row, bpp, s1, s2); + s1 += bpp; + s2 += bpp; + d1 += bpp; + d2 += bpp; + } + } + else + { + for (x = 0; x < src1_rgn.w; x++, col++) + { + weld_pixels (d1, d2, w, h, col + asymmetry_correction, + row, bpp, s1, s2); + s1 += bpp; + s2 += bpp; + d1 += bpp; + d2 += bpp; + } + } src1 += src1_rgn.rowstride; src2 += src2_rgn.rowstride; diff --git a/plug-ins/common/waves.c b/plug-ins/common/waves.c index 05d635d08b..4542462537 100644 --- a/plug-ins/common/waves.c +++ b/plug-ins/common/waves.c @@ -80,6 +80,7 @@ static void wave (guchar *src, gint width, gint height, gint bypp, + gboolean has_alpha, gdouble amplitude, gdouble wavelength, gdouble phase, @@ -216,11 +217,12 @@ pluginCore (piArgs *argp, gint retval=0; GimpPixelRgn srcPr, dstPr; guchar *src, *dst; - guint width, height, bpp; + guint width, height, bpp, has_alpha; width = drawable->width; height = drawable->height; bpp = drawable->bpp; + has_alpha = gimp_drawable_has_alpha (drawable->drawable_id); src = g_new (guchar, width * height * bpp); dst = g_new (guchar, width * height * bpp); @@ -228,8 +230,9 @@ pluginCore (piArgs *argp, gimp_pixel_rgn_init (&dstPr, drawable, 0, 0, width, height, TRUE, TRUE); gimp_pixel_rgn_get_rect (&srcPr, src, 0, 0, width, height); - wave (src, dst, width, height, bpp, argp->amplitude, argp->wavelength, - argp->phase, argp->type==0, argp->reflective, 1); + wave (src, dst, width, height, bpp, has_alpha, + argp->amplitude, argp->wavelength, argp->phase, + argp->type==0, argp->reflective, 1); gimp_pixel_rgn_set_rect (&dstPr, dst, 0, 0, width, height); g_free (src); @@ -416,6 +419,7 @@ waves_do_preview (void) dst = g_new (guchar, preview->width * preview->height * preview->bpp); wave (preview->cache, dst, preview->width, preview->height, preview->bpp, + preview->bpp == 2 || preview->bpp == 4, argp->amplitude * preview->scale_x, argp->wavelength * preview->scale_x, argp->phase, argp->type == 0, argp->reflective, 0); @@ -464,6 +468,8 @@ mw_preview_new (GtkWidget *parent, GimpDrawable *drawable) gtk_widget_show (pframe); preview = gimp_fixme_preview_new (drawable, FALSE); + /* FIXME: this forces gimp_fixme_preview to set its alpha correctly */ + gimp_fixme_preview_fill_scaled (preview, drawable); gtk_container_add (GTK_CONTAINER (pframe), preview->widget); gtk_widget_show (preview->widget); @@ -501,6 +507,7 @@ wave (guchar *src, gint width, gint height, gint bypp, + gboolean has_alpha, gdouble amplitude, gdouble wavelength, gdouble phase, @@ -526,10 +533,8 @@ wave (guchar *src, gint xi, yi; - guchar values[4]; - guchar val; - - gint k; + guchar *values[4]; + guchar zeroes[4] = { 0, 0, 0, 0 }; phase = phase * G_PI / 180; rowsiz = width * bypp; @@ -643,32 +648,28 @@ wave (guchar *src, x2_in = WITHIN (0, xi + 1, width - 1); y2_in = WITHIN (0, yi + 1, height - 1); - for (k = 0; k < bypp; k++) - { - if (x1_in && y1_in) - values[0] = *(p + k); - else - values[0] = 0; + if (x1_in && y1_in) + values[0] = p; + else + values[0] = zeroes; - if (x2_in && y1_in) - values[1] = *(p + bypp + k); - else - values[1] = 0; + if (x2_in && y1_in) + values[1] = p + bypp; + else + values[1] = zeroes; - if (x1_in && y2_in) - values[2] = *(p + rowsiz + k); - else - values[2] = 0; + if (x1_in && y2_in) + values[2] = p + rowsiz; + else + values[2] = zeroes; - if (x2_in && y2_in) - values[3] = *(p + bypp + k + rowsiz); - else - values[3] = 0; + if (x2_in && y2_in) + values[3] = p + bypp + rowsiz; + else + values[3] = zeroes; - val = gimp_bilinear_8 (needx, needy, values); - - *dest++ = val; - } + gimp_bilinear_pixels_8 (dest, needx, needy, bypp, has_alpha, values); + dest += bypp; } dst += rowsiz; diff --git a/plug-ins/common/whirlpinch.c b/plug-ins/common/whirlpinch.c index 69ba1a6856..72c6c105fb 100644 --- a/plug-ins/common/whirlpinch.c +++ b/plug-ins/common/whirlpinch.c @@ -350,8 +350,7 @@ whirl_pinch (void) guchar *top_row, *bot_row; guchar *top_p, *bot_p; gint row, col; - guchar pixel[4][4]; - guchar values[4]; + guchar **pixel; double whirl; double cx, cy; int ix, iy; @@ -361,6 +360,9 @@ whirl_pinch (void) /* Initialize rows */ top_row = g_malloc (img_bpp * sel_width); bot_row = g_malloc (img_bpp * sel_width); + pixel = g_new (guchar *, 4); + for (i = 0; i < 4; i++) + pixel[i] = g_new (guchar, 4); /* Initialize pixel region */ gimp_pixel_rgn_init (&dest_rgn, drawable, @@ -408,16 +410,9 @@ whirl_pinch (void) gimp_pixel_fetcher_get_pixel (pft, ix, iy + 1, pixel[2]); gimp_pixel_fetcher_get_pixel (pft, ix + 1, iy + 1, pixel[3]); - for (i = 0; i < img_bpp; i++) - { - values[0] = pixel[0][i]; - values[1] = pixel[1][i]; - values[2] = pixel[2][i]; - values[3] = pixel[3][i]; - - *top_p++ = gimp_bilinear_8 (cx, cy, values); - } - + gimp_bilinear_pixels_8 (top_p, cx, cy, img_bpp, img_has_alpha, + pixel); + top_p += img_bpp; /* Bottom */ cx = cen_x + (cen_x - cx); @@ -438,17 +433,9 @@ whirl_pinch (void) gimp_pixel_fetcher_get_pixel (pfb, ix, iy + 1, pixel[2]); gimp_pixel_fetcher_get_pixel (pfb, ix + 1, iy + 1, pixel[3]); - for (i = 0; i < img_bpp; i++) - { - values[0] = pixel[0][i]; - values[1] = pixel[1][i]; - values[2] = pixel[2][i]; - values[3] = pixel[3][i]; - - *bot_p++ = gimp_bilinear_8 (cx, cy, values); - } - - bot_p -= 2 * img_bpp; /* We move backwards! */ + gimp_bilinear_pixels_8 (bot_p, cx, cy, img_bpp, img_has_alpha, + pixel); + bot_p -= img_bpp; } else { @@ -492,6 +479,9 @@ whirl_pinch (void) gimp_pixel_fetcher_destroy (pft); gimp_pixel_fetcher_destroy (pfb); + for (i = 0; i < 4; i++) + g_free (pixel[i]); + g_free (pixel); g_free (top_row); g_free (bot_row);