mirror of https://github.com/GNOME/gimp.git
476 lines
12 KiB
C
476 lines
12 KiB
C
/* GIMP - The GNU Image Manipulation Program
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
*
|
|
* gimpbrush-scale.c
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <glib-object.h>
|
|
|
|
#include "core-types.h"
|
|
|
|
#include "gimpbrush.h"
|
|
#include "gimpbrush-scale.h"
|
|
|
|
#include "base/pixel-region.h"
|
|
#include "base/temp-buf.h"
|
|
|
|
#include "paint-funcs/scale-region.h"
|
|
|
|
|
|
/* local function prototypes */
|
|
|
|
static TempBuf * gimp_brush_scale_buf_up (TempBuf *brush_buf,
|
|
gint dest_width,
|
|
gint dest_height);
|
|
static TempBuf * gimp_brush_scale_mask_down (TempBuf *brush_mask,
|
|
gint dest_width,
|
|
gint dest_height);
|
|
static TempBuf * gimp_brush_scale_pixmap_down (TempBuf *pixmap,
|
|
gint dest_width,
|
|
gint dest_height);
|
|
|
|
|
|
/* public functions */
|
|
|
|
void
|
|
gimp_brush_real_scale_size (GimpBrush *brush,
|
|
gdouble scale,
|
|
gint *width,
|
|
gint *height)
|
|
{
|
|
*width = (gint) (brush->mask->width * scale + 0.5);
|
|
*height = (gint) (brush->mask->height * scale + 0.5);
|
|
}
|
|
|
|
TempBuf *
|
|
gimp_brush_real_scale_mask (GimpBrush *brush,
|
|
gdouble scale)
|
|
{
|
|
gint dest_width;
|
|
gint dest_height;
|
|
|
|
gimp_brush_scale_size (brush, scale, &dest_width, &dest_height);
|
|
|
|
if (dest_width <= 0 || dest_height <= 0)
|
|
return NULL;
|
|
|
|
if (scale <= 1.0)
|
|
{
|
|
/* Downscaling with brush_scale_mask is much faster than with
|
|
* gimp_brush_scale_buf.
|
|
*/
|
|
return gimp_brush_scale_mask_down (brush->mask,
|
|
dest_width, dest_height);
|
|
}
|
|
|
|
return gimp_brush_scale_buf_up (brush->mask, dest_width, dest_height);
|
|
}
|
|
|
|
TempBuf *
|
|
gimp_brush_real_scale_pixmap (GimpBrush *brush,
|
|
gdouble scale)
|
|
{
|
|
gint dest_width;
|
|
gint dest_height;
|
|
|
|
gimp_brush_scale_size (brush, scale, &dest_width, &dest_height);
|
|
|
|
if (dest_width <= 0 || dest_height <= 0)
|
|
return NULL;
|
|
|
|
if (scale <= 1.0)
|
|
{
|
|
/* Downscaling with brush_scale_pixmap is much faster than with
|
|
* gimp_brush_scale_buf.
|
|
*/
|
|
return gimp_brush_scale_pixmap_down (brush->pixmap,
|
|
dest_width, dest_height);
|
|
}
|
|
|
|
return gimp_brush_scale_buf_up (brush->pixmap, dest_width, dest_height);
|
|
}
|
|
|
|
|
|
/* private functions */
|
|
|
|
static TempBuf *
|
|
gimp_brush_scale_buf_up (TempBuf *brush_buf,
|
|
gint dest_width,
|
|
gint dest_height)
|
|
{
|
|
PixelRegion source_region;
|
|
PixelRegion dest_region;
|
|
TempBuf *dest_brush_buf;
|
|
|
|
pixel_region_init_temp_buf (&source_region, brush_buf,
|
|
0, 0,
|
|
brush_buf->width,
|
|
brush_buf->height);
|
|
|
|
dest_brush_buf = temp_buf_new (dest_width, dest_height, brush_buf->bytes,
|
|
0, 0, NULL);
|
|
|
|
pixel_region_init_temp_buf (&dest_region, dest_brush_buf,
|
|
0, 0,
|
|
dest_width,
|
|
dest_height);
|
|
|
|
scale_region (&source_region, &dest_region, GIMP_INTERPOLATION_LINEAR,
|
|
NULL, NULL);
|
|
|
|
return dest_brush_buf;
|
|
}
|
|
|
|
static TempBuf *
|
|
gimp_brush_scale_mask_down (TempBuf *brush_mask,
|
|
gint dest_width,
|
|
gint dest_height)
|
|
{
|
|
TempBuf *scale_brush;
|
|
gint src_width;
|
|
gint src_height;
|
|
gint value;
|
|
gint area;
|
|
gint i, j;
|
|
gint x, x0, y, y0;
|
|
gint dx, dx0, dy, dy0;
|
|
gint fx, fx0, fy, fy0;
|
|
guchar *src, *dest;
|
|
|
|
g_return_val_if_fail (brush_mask != NULL &&
|
|
dest_width != 0 && dest_height != 0, NULL);
|
|
|
|
src_width = brush_mask->width;
|
|
src_height = brush_mask->height;
|
|
|
|
scale_brush = temp_buf_new (dest_width, dest_height, 1, 0, 0, NULL);
|
|
g_return_val_if_fail (scale_brush != NULL, NULL);
|
|
|
|
/* get the data */
|
|
dest = temp_buf_data (scale_brush);
|
|
src = temp_buf_data (brush_mask);
|
|
|
|
fx = fx0 = (src_width << 8) / dest_width;
|
|
fy = fy0 = (src_height << 8) / dest_height;
|
|
|
|
area = (fx0 * fy0) >> 8;
|
|
|
|
x = x0 = 0;
|
|
y = y0 = 0;
|
|
dx = dx0 = 0;
|
|
dy = dy0 = 0;
|
|
|
|
for (i=0; i<dest_height; i++)
|
|
{
|
|
for (j=0; j<dest_width; j++)
|
|
{
|
|
value = 0;
|
|
|
|
fy = fy0;
|
|
y = y0;
|
|
dy = dy0;
|
|
|
|
if (dy)
|
|
{
|
|
fx = fx0;
|
|
x = x0;
|
|
dx = dx0;
|
|
|
|
if (dx)
|
|
{
|
|
value += (dx * dy * src[x + src_width * y]) >> 8;
|
|
x++;
|
|
fx -= dx;
|
|
dx = 0;
|
|
}
|
|
while (fx >= 256)
|
|
{
|
|
value += dy * src[x + src_width * y];
|
|
x++;
|
|
fx -= 256;
|
|
}
|
|
if (fx)
|
|
{
|
|
value += fx * dy * src[x + src_width * y] >> 8;
|
|
dx = 256 - fx;
|
|
}
|
|
|
|
y++;
|
|
fy -= dy;
|
|
dy = 0;
|
|
}
|
|
|
|
while (fy >= 256)
|
|
{
|
|
fx = fx0;
|
|
x = x0;
|
|
dx = dx0;
|
|
|
|
if (dx)
|
|
{
|
|
value += dx * src[x + src_width * y];
|
|
x++;
|
|
fx -= dx;
|
|
dx = 0;
|
|
}
|
|
while (fx >= 256)
|
|
{
|
|
value += 256 * src[x + src_width * y];
|
|
x++;
|
|
fx -= 256;
|
|
}
|
|
if (fx)
|
|
{
|
|
value += fx * src[x + src_width * y];
|
|
dx = 256 - fx;
|
|
}
|
|
|
|
y++;
|
|
fy -= 256;
|
|
}
|
|
|
|
if (fy)
|
|
{
|
|
fx = fx0;
|
|
x = x0;
|
|
dx = dx0;
|
|
|
|
if (dx)
|
|
{
|
|
value += (dx * fy * src[x + src_width * y]) >> 8;
|
|
x++;
|
|
fx -= dx;
|
|
dx = 0;
|
|
}
|
|
while (fx >= 256)
|
|
{
|
|
value += fy * src[x + src_width * y];
|
|
x++;
|
|
fx -= 256;
|
|
}
|
|
if (fx)
|
|
{
|
|
value += (fx * fy * src[x + src_width * y]) >> 8;
|
|
dx = 256 - fx;
|
|
}
|
|
|
|
dy = 256 - fy;
|
|
}
|
|
|
|
value /= area;
|
|
*dest++ = MIN (value, 255);
|
|
|
|
x0 = x;
|
|
dx0 = dx;
|
|
}
|
|
|
|
x0 = 0;
|
|
dx0 = 0;
|
|
y0 = y;
|
|
dy0 = dy;
|
|
}
|
|
|
|
return scale_brush;
|
|
}
|
|
|
|
|
|
#define ADD_RGB(dest, factor, src) \
|
|
dest[0] += factor * src[0]; \
|
|
dest[1] += factor * src[1]; \
|
|
dest[2] += factor * src[2];
|
|
|
|
static TempBuf *
|
|
gimp_brush_scale_pixmap_down (TempBuf *pixmap,
|
|
gint dest_width,
|
|
gint dest_height)
|
|
{
|
|
TempBuf *scale_brush;
|
|
gint src_width;
|
|
gint src_height;
|
|
gint value[3];
|
|
gint factor;
|
|
gint area;
|
|
gint i, j;
|
|
gint x, x0, y, y0;
|
|
gint dx, dx0, dy, dy0;
|
|
gint fx, fx0, fy, fy0;
|
|
guchar *src, *src_ptr, *dest;
|
|
|
|
g_return_val_if_fail (pixmap != NULL && pixmap->bytes == 3 &&
|
|
dest_width != 0 && dest_height != 0, NULL);
|
|
|
|
src_width = pixmap->width;
|
|
src_height = pixmap->height;
|
|
|
|
scale_brush = temp_buf_new (dest_width, dest_height, 3, 0, 0, NULL);
|
|
g_return_val_if_fail (scale_brush != NULL, NULL);
|
|
|
|
/* get the data */
|
|
dest = temp_buf_data (scale_brush);
|
|
src = temp_buf_data (pixmap);
|
|
|
|
fx = fx0 = (src_width << 8) / dest_width;
|
|
fy = fy0 = (src_height << 8) / dest_height;
|
|
area = (fx0 * fy0) >> 8;
|
|
|
|
x = x0 = 0;
|
|
y = y0 = 0;
|
|
dx = dx0 = 0;
|
|
dy = dy0 = 0;
|
|
|
|
for (i=0; i<dest_height; i++)
|
|
{
|
|
for (j=0; j<dest_width; j++)
|
|
{
|
|
value[0] = 0;
|
|
value[1] = 0;
|
|
value[2] = 0;
|
|
|
|
fy = fy0;
|
|
y = y0;
|
|
dy = dy0;
|
|
|
|
if (dy)
|
|
{
|
|
fx = fx0;
|
|
x = x0;
|
|
dx = dx0;
|
|
|
|
if (dx)
|
|
{
|
|
factor = (dx * dy) >> 8;
|
|
src_ptr = src + 3 * (x + y * src_width);
|
|
ADD_RGB (value, factor, src_ptr);
|
|
x++;
|
|
fx -= dx;
|
|
dx = 0;
|
|
}
|
|
while (fx >= 256)
|
|
{
|
|
factor = dy;
|
|
src_ptr = src + 3 * (x + y * src_width);
|
|
ADD_RGB (value, factor, src_ptr);
|
|
x++;
|
|
fx -= 256;
|
|
}
|
|
if (fx)
|
|
{
|
|
factor = (fx * dy) >> 8;
|
|
src_ptr = src + 3 * (x + y * src_width);
|
|
ADD_RGB (value, factor, src_ptr);
|
|
dx = 256 - fx;
|
|
}
|
|
|
|
y++;
|
|
fy -= dy;
|
|
dy = 0;
|
|
}
|
|
|
|
while (fy >= 256)
|
|
{
|
|
fx = fx0;
|
|
x = x0;
|
|
dx = dx0;
|
|
|
|
if (dx)
|
|
{
|
|
factor = dx;
|
|
src_ptr = src + 3 * (x + y * src_width);
|
|
ADD_RGB (value, factor, src_ptr);
|
|
x++;
|
|
fx -= dx;
|
|
dx = 0;
|
|
}
|
|
while (fx >= 256)
|
|
{
|
|
factor = 256;
|
|
src_ptr = src + 3 * (x + y * src_width);
|
|
ADD_RGB (value, factor, src_ptr);
|
|
x++;
|
|
fx -= 256;
|
|
}
|
|
if (fx)
|
|
{
|
|
factor = fx;
|
|
src_ptr = src + 3 * (x + y * src_width);
|
|
ADD_RGB (value, factor, src_ptr);
|
|
dx = 256 - fx;
|
|
}
|
|
|
|
y++;
|
|
fy -= 256;
|
|
}
|
|
|
|
if (fy)
|
|
{
|
|
fx = fx0;
|
|
x = x0;
|
|
dx = dx0;
|
|
|
|
if (dx)
|
|
{
|
|
factor = (dx * fy) >> 8;
|
|
src_ptr = src + 3 * (x + y * src_width);
|
|
ADD_RGB (value, factor, src_ptr);
|
|
x++;
|
|
fx -= dx;
|
|
dx = 0;
|
|
}
|
|
while (fx >= 256)
|
|
{
|
|
factor = fy;
|
|
src_ptr = src + 3 * (x + y * src_width);
|
|
ADD_RGB (value, factor, src_ptr);
|
|
x++;
|
|
fx -= 256;
|
|
}
|
|
if (fx)
|
|
{
|
|
factor = (fx * fy) >> 8;
|
|
src_ptr = src + 3 * (x + y * src_width);
|
|
ADD_RGB (value, factor, src_ptr);
|
|
dx = 256 - fx;
|
|
}
|
|
|
|
dy = 256 - fy;
|
|
}
|
|
|
|
value[0] /= area;
|
|
value[1] /= area;
|
|
value[2] /= area;
|
|
|
|
*dest++ = MIN (value[0], 255);
|
|
*dest++ = MIN (value[1], 255);
|
|
*dest++ = MIN (value[2], 255);
|
|
|
|
x0 = x;
|
|
dx0 = dx;
|
|
}
|
|
|
|
x0 = 0;
|
|
dx0 = 0;
|
|
y0 = y;
|
|
dy0 = dy;
|
|
}
|
|
|
|
return scale_brush;
|
|
}
|
|
|
|
#undef ADD_RGB
|