From 0e2fba2396dbe7f15338a5391624ada0403fdbf1 Mon Sep 17 00:00:00 2001 From: David Capello Date: Sun, 14 Jun 2009 19:05:43 +0000 Subject: [PATCH] Added image_fixup_transparent_colors function. Fixed image_resize. --- src/commands/cmd_sprite_size.cpp | 24 +++-- src/raster/image.cpp | 153 +++++++++++++++++++++++++++---- src/raster/image.h | 1 + 3 files changed, 152 insertions(+), 26 deletions(-) diff --git a/src/commands/cmd_sprite_size.cpp b/src/commands/cmd_sprite_size.cpp index ddda27d88..b63fa9d63 100644 --- a/src/commands/cmd_sprite_size.cpp +++ b/src/commands/cmd_sprite_size.cpp @@ -92,6 +92,7 @@ protected: int h = scale_y(image->h); Image* new_image = image_new(image->imgtype, MAX(1, w), MAX(1, h)); + image_fixup_transparent_colors(image); image_resize(image, new_image, m_resize_method, get_current_palette(), @@ -108,17 +109,26 @@ protected: // resize mask if (m_sprite->mask->bitmap) { - int w = scale_x(m_sprite->mask->bitmap->w); - int h = scale_y(m_sprite->mask->bitmap->h); + Image* old_bitmap = image_crop(m_sprite->mask->bitmap, -1, -1, + m_sprite->mask->bitmap->w+2, + m_sprite->mask->bitmap->h+2, 0); + + int w = scale_x(old_bitmap->w); + int h = scale_y(old_bitmap->h); Mask* new_mask = mask_new(); mask_replace(new_mask, - scale_x(m_sprite->mask->x), - scale_y(m_sprite->mask->y), MAX(1, w), MAX(1, h)); - - image_resize(m_sprite->mask->bitmap, new_mask->bitmap, - RESIZE_METHOD_NEAREST_NEIGHBOR, + scale_x(m_sprite->mask->x-1), + scale_y(m_sprite->mask->y-1), MAX(1, w), MAX(1, h)); + image_resize(old_bitmap, new_mask->bitmap, + m_resize_method, get_current_palette(), orig_rgb_map); + image_free(old_bitmap); + + // reshrink + mask_intersect(new_mask, + new_mask->x, new_mask->y, + new_mask->w, new_mask->h); undoable.copy_to_current_mask(new_mask); mask_free(new_mask); diff --git a/src/raster/image.cpp b/src/raster/image.cpp index 3ef183417..a943a17c4 100644 --- a/src/raster/image.cpp +++ b/src/raster/image.cpp @@ -318,15 +318,106 @@ void image_ellipsefill(Image* image, int x1, int y1, int x2, int y2, int color) /* } */ /* } */ -/********************************************************************* - Allegro <-> Image - *********************************************************************/ - void image_to_allegro(const Image* image, BITMAP *bmp, int x, int y) { image->to_allegro(bmp, x, y); } +/** + * This routine does not modify the image to the human eye, but + * internally tries to fixup all colors that are completelly + * transparent (alpha = 0) with the average of its 4-neighbors. + */ +void image_fixup_transparent_colors(Image* image) +{ + int x, y, u, v; + + switch (image->imgtype) { + + case IMAGE_RGB: { + ase_uint32 c; + int r, g, b, count; + + for (y=0; yh; ++y) { + for (x=0; xw; ++x) { + c = image_getpixel_fast(image, x, y); + + // if this is a completelly-transparent pixel... + if (_rgba_geta(c) == 0) { + count = 0; + r = g = b = 0; + + for (v=y-1; v<=y+1; ++v) { + for (u=x-1; u<=x+1; ++u) { + if ((u >= 0) && (v >= 0) && (u < image->w) && (v < image->h)) { + c = image_getpixel_fast(image, u, v); + if (_rgba_geta(c) > 0) { + r += _rgba_getr(c); + g += _rgba_getg(c); + b += _rgba_getb(c); + ++count; + } + } + } + } + + if (count > 0) { + r /= count; + g /= count; + b /= count; + image_putpixel_fast(image, x, y, _rgba(r, g, b, 0)); + } + } + } + } + break; + } + + case IMAGE_GRAYSCALE: { + ase_uint16 c; + int k, count; + + for (y=0; yh; ++y) { + for (x=0; xw; ++x) { + c = image_getpixel_fast(image, x, y); + + // if this is a completelly-transparent pixel... + if (_graya_geta(c) == 0) { + count = 0; + k = 0; + + for (v=y-1; v<=y+1; ++v) { + for (u=x-1; u<=x+1; ++u) { + if ((u >= 0) && (v >= 0) && (u < image->w) && (v < image->h)) { + c = image_getpixel_fast(image, u, v); + if (_graya_geta(c) > 0) { + k += _graya_getv(c); + ++count; + } + } + } + } + + if (count > 0) { + k /= count; + image_putpixel_fast(image, x, y, _graya(k, 0)); + } + } + } + } + break; + } + + } +} + +/** + * Resizes the source image @a src to the destination image @a dst. + * + * @warning If you are using the RESIZE_METHOD_BILINEAR, it is + * recommended to use @ref image_fixup_transparent_colors function + * over the source image @a src before using this routine. + */ void image_resize(const Image* src, Image* dst, ResizeMethod method, Palette* pal, RGB_MAP* rgb_map) { switch (method) { @@ -353,29 +444,47 @@ void image_resize(const Image* src, Image* dst, ResizeMethod method, Palette* pa break; } - // TODO optimize this + // TODO optimize this case RESIZE_METHOD_BILINEAR: { ase_uint32 color[4], dst_color; double u, v, du, dv; + int u_floor, u_floor2; + int v_floor, v_floor2; int x, y; u = v = 0.0; - du = src->w * 1.0 / dst->w; - dv = src->h * 1.0 / dst->h; + du = (src->w-1) * 1.0 / (dst->w-1); + dv = (src->h-1) * 1.0 / (dst->h-1); for (y=0; yh; ++y) { for (x=0; xw; ++x) { - int u_floor = floor(u); - int v_floor = floor(v); + u_floor = floor(u); + v_floor = floor(v); - color[0] = src->getpixel(MID(0, u_floor, src->w-1), - MID(0, v_floor, src->h-1)); - color[1] = src->getpixel(MID(0, u_floor+1, src->w-1), - MID(0, v_floor, src->h-1)); - color[2] = src->getpixel(MID(0, u_floor, src->w-1), - MID(0, v_floor+1, src->h-1)); - color[3] = src->getpixel(MID(0, u_floor+1, src->w-1), - MID(0, v_floor+1, src->h-1)); + if (u_floor > src->w-1) { + u_floor = src->w-1; + u_floor2 = src->w-1; + } + else if (u_floor == src->w-1) + u_floor2 = u_floor; + else + u_floor2 = u_floor+1; + if (v_floor > src->h-1) { + v_floor = src->h-1; + v_floor2 = src->h-1; + } + else if (v_floor == src->h-1) + v_floor2 = v_floor; + else + v_floor2 = v_floor+1; + + // get the four colors + color[0] = src->getpixel(u_floor, v_floor); + color[1] = src->getpixel(u_floor2, v_floor); + color[2] = src->getpixel(u_floor, v_floor2); + color[3] = src->getpixel(u_floor2, v_floor2); + + // calculate the interpolated color double u1 = u - u_floor; double v1 = v - v_floor; double u2 = 1 - u1; @@ -409,11 +518,17 @@ void image_resize(const Image* src, Image* dst, ResizeMethod method, Palette* pa (_rgba_getg(pal->color[color[2]])*u2 + _rgba_getg(pal->color[color[3]])*u1)*v1); int b = ((_rgba_getb(pal->color[color[0]])*u2 + _rgba_getb(pal->color[color[1]])*u1)*v2 + (_rgba_getb(pal->color[color[2]])*u2 + _rgba_getb(pal->color[color[3]])*u1)*v1); - int a = ((_rgba_geta(pal->color[color[0]])*u2 + _rgba_geta(pal->color[color[1]])*u1)*v2 + - (_rgba_geta(pal->color[color[2]])*u2 + _rgba_geta(pal->color[color[3]])*u1)*v1); + int a = (((color[0] == 0 ? 0: 255)*u2 + (color[1] == 0 ? 0: 255)*u1)*v2 + + ((color[2] == 0 ? 0: 255)*u2 + (color[3] == 0 ? 0: 255)*u1)*v1); dst_color = a > 127 ? rgb_map->data[r>>3][g>>3][b>>3]: 0; break; } + case IMAGE_BITMAP: { + int g = ((255*color[0]*u2 + 255*color[1]*u1)*v2 + + (255*color[2]*u2 + 255*color[3]*u1)*v1); + dst_color = g > 127 ? 1: 0; + break; + } } dst->putpixel(x, y, dst_color); diff --git a/src/raster/image.h b/src/raster/image.h index dc74ae81f..c701370a7 100644 --- a/src/raster/image.h +++ b/src/raster/image.h @@ -88,6 +88,7 @@ void image_ellipsefill(Image* image, int x1, int y1, int x2, int y2, int color); void image_to_allegro(const Image* image, BITMAP* bmp, int x, int y); +void image_fixup_transparent_colors(Image* image); void image_resize(const Image* src, Image* dst, ResizeMethod method, Palette* palette, RGB_MAP* rgb_map); int image_count_diff(const Image* i1, const Image* i2); bool image_shrink_rect(Image *image, int *x1, int *y1, int *x2, int *y2, int refpixel);