mirror of https://github.com/GNOME/gimp.git
app/base/base-enums.[ch] app/core/gimpdrawable-transform.c
2005-01-11 Sven Neumann <neumann@jpk.com> * app/base/base-enums.[ch] * app/core/gimpdrawable-transform.c * app/core/gimpdrawable.c * app/paint-funcs/Makefile.am * app/paint-funcs/paint-funcs.[ch] * app/paint-funcs/scale-funcs.[ch]: applied patch by Geert Jordaens (after a good deal of reformatting for coding style compliance). This factors the scale routines into their own file and adds a sinc-based (Lanczos) interpolation routine (bug #162250).
This commit is contained in:
parent
86b4d00a0e
commit
f3166ba9f9
12
ChangeLog
12
ChangeLog
|
@ -1,3 +1,15 @@
|
|||
2005-01-11 Sven Neumann <neumann@jpk.com>
|
||||
|
||||
* app/base/base-enums.[ch]
|
||||
* app/core/gimpdrawable-transform.c
|
||||
* app/core/gimpdrawable.c
|
||||
* app/paint-funcs/Makefile.am
|
||||
* app/paint-funcs/paint-funcs.[ch]
|
||||
* app/paint-funcs/scale-funcs.[ch]: applied patch by Geert Jordaens
|
||||
(after a good deal of reformatting for coding style compliance).
|
||||
This factors the scale routines into their own file and adds a
|
||||
sinc-based (Lanczos) interpolation routine (bug #162250).
|
||||
|
||||
2005-01-11 Sven Neumann <sven@gimp.org>
|
||||
|
||||
* plug-ins/script-fu/siod/slib.c (help): removed wrong URL from
|
||||
|
|
|
@ -80,6 +80,7 @@ gimp_interpolation_type_get_type (void)
|
|||
{ GIMP_INTERPOLATION_NONE, "GIMP_INTERPOLATION_NONE", "none" },
|
||||
{ GIMP_INTERPOLATION_LINEAR, "GIMP_INTERPOLATION_LINEAR", "linear" },
|
||||
{ GIMP_INTERPOLATION_CUBIC, "GIMP_INTERPOLATION_CUBIC", "cubic" },
|
||||
{ GIMP_INTERPOLATION_LANCZOS, "GIMP_INTERPOLATION_LANCZOS", "lanczos" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
|
@ -87,7 +88,8 @@ gimp_interpolation_type_get_type (void)
|
|||
{
|
||||
{ GIMP_INTERPOLATION_NONE, N_("None (Fastest)"), NULL },
|
||||
{ GIMP_INTERPOLATION_LINEAR, N_("Linear"), NULL },
|
||||
{ GIMP_INTERPOLATION_CUBIC, N_("Cubic (Best)"), NULL },
|
||||
{ GIMP_INTERPOLATION_CUBIC, N_("Cubic"), NULL },
|
||||
{ GIMP_INTERPOLATION_LANCZOS, N_("Lanczos (Best)"), NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
|
|
|
@ -69,7 +69,8 @@ typedef enum
|
|||
{
|
||||
GIMP_INTERPOLATION_NONE, /*< desc="None (Fastest)" >*/
|
||||
GIMP_INTERPOLATION_LINEAR, /*< desc="Linear" >*/
|
||||
GIMP_INTERPOLATION_CUBIC /*< desc="Cubic (Best)" >*/
|
||||
GIMP_INTERPOLATION_CUBIC, /*< desc="Cubic" >*/
|
||||
GIMP_INTERPOLATION_LANCZOS /*< desc="Lanczos (Best)" >*/
|
||||
} GimpInterpolationType;
|
||||
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "base/tile.h"
|
||||
|
||||
#include "paint-funcs/paint-funcs.h"
|
||||
#include "paint-funcs/scale-funcs.h"
|
||||
|
||||
#include "gimp.h"
|
||||
#include "gimp-utils.h"
|
||||
|
@ -98,6 +99,16 @@ static void sample_linear (PixelSurround *surround,
|
|||
gint bytes,
|
||||
gint alpha);
|
||||
|
||||
static void sample_lanczos (const gdouble *kernel,
|
||||
gint su,
|
||||
gint sv,
|
||||
guchar *color,
|
||||
guchar *buffer,
|
||||
gint bytes,
|
||||
gint alpha);
|
||||
|
||||
static gdouble * kernel_lanczos (void);
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
|
@ -137,6 +148,11 @@ gimp_drawable_transform_tiles_affine (GimpDrawable *drawable,
|
|||
gdouble tu[5],tv[5],tw[5]; /* undivided source coordinates and
|
||||
divisor */
|
||||
|
||||
gdouble *kernel = NULL; /* Lanczos kernel */
|
||||
gint su, sv; /* Lanczos kernel position */
|
||||
guchar *buffer = NULL; /* Holds sliding window buffer */
|
||||
|
||||
|
||||
gint coords;
|
||||
gint width;
|
||||
gint alpha;
|
||||
|
@ -272,6 +288,14 @@ gimp_drawable_transform_tiles_affine (GimpDrawable *drawable,
|
|||
0, 0, x2 - x1, y2 - y1, TRUE);
|
||||
tile_manager_set_offsets (new_tiles, x1, y1);
|
||||
|
||||
width = tile_manager_width (new_tiles);
|
||||
bytes = tile_manager_bpp (new_tiles);
|
||||
|
||||
/* If the image is too small for lanczos, switch to cubic interpolation */
|
||||
if (interpolation_type == GIMP_INTERPOLATION_LANCZOS &&
|
||||
(x2 - x1 < LANCZOS_WIDTH2 || y2 - y1 < LANCZOS_WIDTH2))
|
||||
interpolation_type = GIMP_INTERPOLATION_CUBIC;
|
||||
|
||||
/* initialise the pixel_surround and pixel_cache accessors */
|
||||
switch (interpolation_type)
|
||||
{
|
||||
|
@ -283,11 +307,12 @@ gimp_drawable_transform_tiles_affine (GimpDrawable *drawable,
|
|||
case GIMP_INTERPOLATION_LINEAR:
|
||||
pixel_surround_init (&surround, orig_tiles, 2, 2, bg_color);
|
||||
break;
|
||||
case GIMP_INTERPOLATION_LANCZOS:
|
||||
kernel = kernel_lanczos ();
|
||||
buffer = g_new0 (guchar, LANCZOS_WIDTH2 * bytes);
|
||||
break;
|
||||
}
|
||||
|
||||
width = tile_manager_width (new_tiles);
|
||||
bytes = tile_manager_bpp (new_tiles);
|
||||
|
||||
dest = g_new (guchar, tile_manager_width (new_tiles) * bytes);
|
||||
|
||||
uinc = m.coeff[0][0];
|
||||
|
@ -386,6 +411,47 @@ gimp_drawable_transform_tiles_affine (GimpDrawable *drawable,
|
|||
*d++ = bg_color[b];
|
||||
}
|
||||
}
|
||||
else if (interpolation_type == GIMP_INTERPOLATION_LANCZOS)
|
||||
{
|
||||
guchar color[MAX_CHANNELS];
|
||||
gint iu = (gint) u [0];
|
||||
gint iv = (gint) v [0];
|
||||
gint fu,fv;
|
||||
gint b;
|
||||
|
||||
if (iu >= u1 && iu < u2 &&
|
||||
iv >= v1 && iv < v2)
|
||||
{
|
||||
/* u, v coordinates into source tiles */
|
||||
gint u = iu - u1;
|
||||
gint v = iv - v1;
|
||||
|
||||
read_pixel_data (orig_tiles,
|
||||
u-LANCZOS_WIDTH+1,
|
||||
v-LANCZOS_WIDTH+1,
|
||||
u+LANCZOS_WIDTH,
|
||||
v+LANCZOS_WIDTH,
|
||||
buffer,
|
||||
bytes*LANCZOS_WIDTH2);
|
||||
|
||||
fu = u-iu;
|
||||
su = (gint)( fu * LANCZOS_SPP );
|
||||
fv = v-iv;
|
||||
sv = (gint)( fv * LANCZOS_SPP );
|
||||
|
||||
sample_lanczos (kernel, su, sv, color, buffer, bytes, alpha);
|
||||
|
||||
for (b = 0; b < bytes; b++)
|
||||
*d++ = color[b];
|
||||
}
|
||||
else /* not in source range */
|
||||
{
|
||||
/* increment the destination pointers */
|
||||
|
||||
for (b = 0; b < bytes; b++)
|
||||
*d++ = bg_color[b];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint b;
|
||||
|
@ -451,8 +517,19 @@ gimp_drawable_transform_tiles_affine (GimpDrawable *drawable,
|
|||
pixel_region_set_row (&destPR, 0, (y - y1), width, dest);
|
||||
}
|
||||
|
||||
if (interpolation_type != GIMP_INTERPOLATION_NONE)
|
||||
pixel_surround_clear (&surround);
|
||||
switch (interpolation_type)
|
||||
{
|
||||
case GIMP_INTERPOLATION_NONE:
|
||||
break;
|
||||
case GIMP_INTERPOLATION_CUBIC:
|
||||
case GIMP_INTERPOLATION_LINEAR:
|
||||
pixel_surround_clear (&surround);
|
||||
break;
|
||||
case GIMP_INTERPOLATION_LANCZOS:
|
||||
g_free (kernel);
|
||||
g_free (buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
g_free (dest);
|
||||
|
||||
|
@ -1611,3 +1688,152 @@ sample_cubic (PixelSurround *surround,
|
|||
|
||||
pixel_surround_release (surround);
|
||||
}
|
||||
|
||||
|
||||
/* Lanczos */
|
||||
|
||||
static inline gdouble
|
||||
sinc (gdouble x)
|
||||
{
|
||||
gdouble y = x * G_PI;
|
||||
|
||||
if (ABS (x) < EPSILON)
|
||||
return 1.0;
|
||||
|
||||
return sin (y) / y;
|
||||
}
|
||||
|
||||
static inline gdouble
|
||||
lanczos_sum (const guchar *buffer,
|
||||
gdouble *l,
|
||||
gint row,
|
||||
gint bytes,
|
||||
gint byte)
|
||||
{
|
||||
gdouble sum = 0;
|
||||
gint j, k, p;
|
||||
|
||||
p = row * bytes * LANCZOS_WIDTH2;
|
||||
|
||||
for (k = 0, j = 0; j < LANCZOS_WIDTH2; j++, k++)
|
||||
sum += l[k] * (buffer + p)[j * bytes + byte];
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
static inline gdouble
|
||||
lanczos_sum_mul (guchar *buffer,
|
||||
gdouble *l,
|
||||
gint row,
|
||||
gint bytes,
|
||||
gint byte,
|
||||
gint alpha)
|
||||
{
|
||||
gdouble sum = 0;
|
||||
gint j, k, p;
|
||||
|
||||
p = row * bytes * LANCZOS_WIDTH2;
|
||||
for (k = 0, j = 0; j < LANCZOS_WIDTH2; j++, k++)
|
||||
sum += (l[k] *
|
||||
(buffer + p)[j * bytes + byte] *
|
||||
(buffer + p)[j * bytes + alpha]);
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
static gdouble *
|
||||
kernel_lanczos (void)
|
||||
{
|
||||
gdouble *kernel ;
|
||||
gdouble x = 0.0;
|
||||
gdouble dx = (gdouble) LANCZOS_WIDTH / (gdouble) (LANCZOS_SAMPLES - 1);
|
||||
gint i;
|
||||
|
||||
kernel = g_new (gdouble, LANCZOS_SAMPLES);
|
||||
|
||||
for (i = 0 ;i < LANCZOS_SAMPLES; i++)
|
||||
{
|
||||
kernel[i] = ((ABS (x) < LANCZOS_WIDTH) ?
|
||||
(sinc (x) * sinc (x / LANCZOS_WIDTH)) : 0.0);
|
||||
x += dx;
|
||||
}
|
||||
|
||||
return kernel;
|
||||
}
|
||||
|
||||
static void
|
||||
sample_lanczos (const gdouble *kernel,
|
||||
gint su,
|
||||
gint sv,
|
||||
guchar *color,
|
||||
guchar *buffer,
|
||||
gint bytes,
|
||||
gint alpha)
|
||||
{
|
||||
|
||||
gdouble lu[LANCZOS_WIDTH2]; /* Lanczos sample value */
|
||||
gdouble lv[LANCZOS_WIDTH2]; /* Lanczos sample value */
|
||||
gdouble lusum, lvsum, weight; /* Lanczos weighting vars */
|
||||
gint i,j,row, byte; /* loop vars to fill source window */
|
||||
|
||||
gdouble aval, arecip; /* Handle alpha values */
|
||||
gdouble newval; /* New interpolated RGB value */
|
||||
|
||||
|
||||
for (lusum = lvsum = i = 0, j = LANCZOS_WIDTH - 1;
|
||||
j >= - LANCZOS_WIDTH;
|
||||
j--, i++)
|
||||
{
|
||||
lusum += lu[i] = kernel[ABS (j * LANCZOS_SPP + su)];
|
||||
lvsum += lv[i] = kernel[ABS (j * LANCZOS_SPP + sv)];
|
||||
}
|
||||
|
||||
weight = lusum * lvsum;
|
||||
|
||||
if (alpha != 0)
|
||||
{
|
||||
for ( aval = 0, row = 0 ; row < LANCZOS_WIDTH2 ; row ++ )
|
||||
aval += lv[row] * lanczos_sum (buffer, lu, row, bytes, alpha);
|
||||
|
||||
/* calculate alpha of result */
|
||||
aval /= weight;
|
||||
|
||||
if ( aval <= 0.0 )
|
||||
{
|
||||
arecip = 0.0;
|
||||
color[alpha] = 0;
|
||||
}
|
||||
else if ( aval > 255.0 )
|
||||
{
|
||||
arecip = 1.0 / aval;
|
||||
color[alpha] = 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
arecip = 1.0 / aval;
|
||||
color[alpha] = RINT (aval);
|
||||
}
|
||||
|
||||
for (byte = 0; byte < alpha; byte++)
|
||||
{
|
||||
for (newval = 0, row = 0; row < LANCZOS_WIDTH2; row ++)
|
||||
newval += lv[row] * lanczos_sum_mul (buffer, lu,
|
||||
row, bytes, byte, alpha);
|
||||
newval *= arecip;
|
||||
color[byte] = CLAMP (newval, 0, 255);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (byte = 0; byte < bytes; byte++)
|
||||
{
|
||||
for (newval = 0, row = 0 ; row < LANCZOS_WIDTH2 ; row++ )
|
||||
newval += lv[row] * lanczos_sum (buffer, lu, row, bytes, byte);
|
||||
|
||||
newval /= weight;
|
||||
color[byte] = CLAMP ((gint) newval, 0, 255);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/* Lanczos */
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "base/tile.h"
|
||||
|
||||
#include "paint-funcs/paint-funcs.h"
|
||||
#include "paint-funcs/scale-funcs.h"
|
||||
|
||||
#include "gimp.h"
|
||||
#include "gimp-utils.h"
|
||||
|
@ -98,6 +99,16 @@ static void sample_linear (PixelSurround *surround,
|
|||
gint bytes,
|
||||
gint alpha);
|
||||
|
||||
static void sample_lanczos (const gdouble *kernel,
|
||||
gint su,
|
||||
gint sv,
|
||||
guchar *color,
|
||||
guchar *buffer,
|
||||
gint bytes,
|
||||
gint alpha);
|
||||
|
||||
static gdouble * kernel_lanczos (void);
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
|
@ -137,6 +148,11 @@ gimp_drawable_transform_tiles_affine (GimpDrawable *drawable,
|
|||
gdouble tu[5],tv[5],tw[5]; /* undivided source coordinates and
|
||||
divisor */
|
||||
|
||||
gdouble *kernel = NULL; /* Lanczos kernel */
|
||||
gint su, sv; /* Lanczos kernel position */
|
||||
guchar *buffer = NULL; /* Holds sliding window buffer */
|
||||
|
||||
|
||||
gint coords;
|
||||
gint width;
|
||||
gint alpha;
|
||||
|
@ -272,6 +288,14 @@ gimp_drawable_transform_tiles_affine (GimpDrawable *drawable,
|
|||
0, 0, x2 - x1, y2 - y1, TRUE);
|
||||
tile_manager_set_offsets (new_tiles, x1, y1);
|
||||
|
||||
width = tile_manager_width (new_tiles);
|
||||
bytes = tile_manager_bpp (new_tiles);
|
||||
|
||||
/* If the image is too small for lanczos, switch to cubic interpolation */
|
||||
if (interpolation_type == GIMP_INTERPOLATION_LANCZOS &&
|
||||
(x2 - x1 < LANCZOS_WIDTH2 || y2 - y1 < LANCZOS_WIDTH2))
|
||||
interpolation_type = GIMP_INTERPOLATION_CUBIC;
|
||||
|
||||
/* initialise the pixel_surround and pixel_cache accessors */
|
||||
switch (interpolation_type)
|
||||
{
|
||||
|
@ -283,11 +307,12 @@ gimp_drawable_transform_tiles_affine (GimpDrawable *drawable,
|
|||
case GIMP_INTERPOLATION_LINEAR:
|
||||
pixel_surround_init (&surround, orig_tiles, 2, 2, bg_color);
|
||||
break;
|
||||
case GIMP_INTERPOLATION_LANCZOS:
|
||||
kernel = kernel_lanczos ();
|
||||
buffer = g_new0 (guchar, LANCZOS_WIDTH2 * bytes);
|
||||
break;
|
||||
}
|
||||
|
||||
width = tile_manager_width (new_tiles);
|
||||
bytes = tile_manager_bpp (new_tiles);
|
||||
|
||||
dest = g_new (guchar, tile_manager_width (new_tiles) * bytes);
|
||||
|
||||
uinc = m.coeff[0][0];
|
||||
|
@ -386,6 +411,47 @@ gimp_drawable_transform_tiles_affine (GimpDrawable *drawable,
|
|||
*d++ = bg_color[b];
|
||||
}
|
||||
}
|
||||
else if (interpolation_type == GIMP_INTERPOLATION_LANCZOS)
|
||||
{
|
||||
guchar color[MAX_CHANNELS];
|
||||
gint iu = (gint) u [0];
|
||||
gint iv = (gint) v [0];
|
||||
gint fu,fv;
|
||||
gint b;
|
||||
|
||||
if (iu >= u1 && iu < u2 &&
|
||||
iv >= v1 && iv < v2)
|
||||
{
|
||||
/* u, v coordinates into source tiles */
|
||||
gint u = iu - u1;
|
||||
gint v = iv - v1;
|
||||
|
||||
read_pixel_data (orig_tiles,
|
||||
u-LANCZOS_WIDTH+1,
|
||||
v-LANCZOS_WIDTH+1,
|
||||
u+LANCZOS_WIDTH,
|
||||
v+LANCZOS_WIDTH,
|
||||
buffer,
|
||||
bytes*LANCZOS_WIDTH2);
|
||||
|
||||
fu = u-iu;
|
||||
su = (gint)( fu * LANCZOS_SPP );
|
||||
fv = v-iv;
|
||||
sv = (gint)( fv * LANCZOS_SPP );
|
||||
|
||||
sample_lanczos (kernel, su, sv, color, buffer, bytes, alpha);
|
||||
|
||||
for (b = 0; b < bytes; b++)
|
||||
*d++ = color[b];
|
||||
}
|
||||
else /* not in source range */
|
||||
{
|
||||
/* increment the destination pointers */
|
||||
|
||||
for (b = 0; b < bytes; b++)
|
||||
*d++ = bg_color[b];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint b;
|
||||
|
@ -451,8 +517,19 @@ gimp_drawable_transform_tiles_affine (GimpDrawable *drawable,
|
|||
pixel_region_set_row (&destPR, 0, (y - y1), width, dest);
|
||||
}
|
||||
|
||||
if (interpolation_type != GIMP_INTERPOLATION_NONE)
|
||||
pixel_surround_clear (&surround);
|
||||
switch (interpolation_type)
|
||||
{
|
||||
case GIMP_INTERPOLATION_NONE:
|
||||
break;
|
||||
case GIMP_INTERPOLATION_CUBIC:
|
||||
case GIMP_INTERPOLATION_LINEAR:
|
||||
pixel_surround_clear (&surround);
|
||||
break;
|
||||
case GIMP_INTERPOLATION_LANCZOS:
|
||||
g_free (kernel);
|
||||
g_free (buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
g_free (dest);
|
||||
|
||||
|
@ -1611,3 +1688,152 @@ sample_cubic (PixelSurround *surround,
|
|||
|
||||
pixel_surround_release (surround);
|
||||
}
|
||||
|
||||
|
||||
/* Lanczos */
|
||||
|
||||
static inline gdouble
|
||||
sinc (gdouble x)
|
||||
{
|
||||
gdouble y = x * G_PI;
|
||||
|
||||
if (ABS (x) < EPSILON)
|
||||
return 1.0;
|
||||
|
||||
return sin (y) / y;
|
||||
}
|
||||
|
||||
static inline gdouble
|
||||
lanczos_sum (const guchar *buffer,
|
||||
gdouble *l,
|
||||
gint row,
|
||||
gint bytes,
|
||||
gint byte)
|
||||
{
|
||||
gdouble sum = 0;
|
||||
gint j, k, p;
|
||||
|
||||
p = row * bytes * LANCZOS_WIDTH2;
|
||||
|
||||
for (k = 0, j = 0; j < LANCZOS_WIDTH2; j++, k++)
|
||||
sum += l[k] * (buffer + p)[j * bytes + byte];
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
static inline gdouble
|
||||
lanczos_sum_mul (guchar *buffer,
|
||||
gdouble *l,
|
||||
gint row,
|
||||
gint bytes,
|
||||
gint byte,
|
||||
gint alpha)
|
||||
{
|
||||
gdouble sum = 0;
|
||||
gint j, k, p;
|
||||
|
||||
p = row * bytes * LANCZOS_WIDTH2;
|
||||
for (k = 0, j = 0; j < LANCZOS_WIDTH2; j++, k++)
|
||||
sum += (l[k] *
|
||||
(buffer + p)[j * bytes + byte] *
|
||||
(buffer + p)[j * bytes + alpha]);
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
static gdouble *
|
||||
kernel_lanczos (void)
|
||||
{
|
||||
gdouble *kernel ;
|
||||
gdouble x = 0.0;
|
||||
gdouble dx = (gdouble) LANCZOS_WIDTH / (gdouble) (LANCZOS_SAMPLES - 1);
|
||||
gint i;
|
||||
|
||||
kernel = g_new (gdouble, LANCZOS_SAMPLES);
|
||||
|
||||
for (i = 0 ;i < LANCZOS_SAMPLES; i++)
|
||||
{
|
||||
kernel[i] = ((ABS (x) < LANCZOS_WIDTH) ?
|
||||
(sinc (x) * sinc (x / LANCZOS_WIDTH)) : 0.0);
|
||||
x += dx;
|
||||
}
|
||||
|
||||
return kernel;
|
||||
}
|
||||
|
||||
static void
|
||||
sample_lanczos (const gdouble *kernel,
|
||||
gint su,
|
||||
gint sv,
|
||||
guchar *color,
|
||||
guchar *buffer,
|
||||
gint bytes,
|
||||
gint alpha)
|
||||
{
|
||||
|
||||
gdouble lu[LANCZOS_WIDTH2]; /* Lanczos sample value */
|
||||
gdouble lv[LANCZOS_WIDTH2]; /* Lanczos sample value */
|
||||
gdouble lusum, lvsum, weight; /* Lanczos weighting vars */
|
||||
gint i,j,row, byte; /* loop vars to fill source window */
|
||||
|
||||
gdouble aval, arecip; /* Handle alpha values */
|
||||
gdouble newval; /* New interpolated RGB value */
|
||||
|
||||
|
||||
for (lusum = lvsum = i = 0, j = LANCZOS_WIDTH - 1;
|
||||
j >= - LANCZOS_WIDTH;
|
||||
j--, i++)
|
||||
{
|
||||
lusum += lu[i] = kernel[ABS (j * LANCZOS_SPP + su)];
|
||||
lvsum += lv[i] = kernel[ABS (j * LANCZOS_SPP + sv)];
|
||||
}
|
||||
|
||||
weight = lusum * lvsum;
|
||||
|
||||
if (alpha != 0)
|
||||
{
|
||||
for ( aval = 0, row = 0 ; row < LANCZOS_WIDTH2 ; row ++ )
|
||||
aval += lv[row] * lanczos_sum (buffer, lu, row, bytes, alpha);
|
||||
|
||||
/* calculate alpha of result */
|
||||
aval /= weight;
|
||||
|
||||
if ( aval <= 0.0 )
|
||||
{
|
||||
arecip = 0.0;
|
||||
color[alpha] = 0;
|
||||
}
|
||||
else if ( aval > 255.0 )
|
||||
{
|
||||
arecip = 1.0 / aval;
|
||||
color[alpha] = 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
arecip = 1.0 / aval;
|
||||
color[alpha] = RINT (aval);
|
||||
}
|
||||
|
||||
for (byte = 0; byte < alpha; byte++)
|
||||
{
|
||||
for (newval = 0, row = 0; row < LANCZOS_WIDTH2; row ++)
|
||||
newval += lv[row] * lanczos_sum_mul (buffer, lu,
|
||||
row, bytes, byte, alpha);
|
||||
newval *= arecip;
|
||||
color[byte] = CLAMP (newval, 0, 255);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (byte = 0; byte < bytes; byte++)
|
||||
{
|
||||
for (newval = 0, row = 0 ; row < LANCZOS_WIDTH2 ; row++ )
|
||||
newval += lv[row] * lanczos_sum (buffer, lu, row, bytes, byte);
|
||||
|
||||
newval /= weight;
|
||||
color[byte] = CLAMP ((gint) newval, 0, 255);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/* Lanczos */
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "base/tile-manager.h"
|
||||
|
||||
#include "paint-funcs/paint-funcs.h"
|
||||
#include "paint-funcs/scale-funcs.h"
|
||||
|
||||
#include "gimp.h"
|
||||
#include "gimp-utils.h"
|
||||
|
|
|
@ -6,7 +6,9 @@ libapppaint_funcs_a_SOURCES = \
|
|||
paint-funcs-types.h \
|
||||
paint-funcs.c \
|
||||
paint-funcs.h \
|
||||
paint-funcs-generic.h
|
||||
paint-funcs-generic.h \
|
||||
scale-funcs.c \
|
||||
scale-funcs.h
|
||||
|
||||
INCLUDES = \
|
||||
-I$(top_srcdir) \
|
||||
|
|
|
@ -43,15 +43,6 @@
|
|||
#define EPSILON 0.0001
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MinifyX_MinifyY,
|
||||
MinifyX_MagnifyY,
|
||||
MagnifyX_MinifyY,
|
||||
MagnifyX_MagnifyY
|
||||
} ScaleType;
|
||||
|
||||
|
||||
/* Layer modes information */
|
||||
typedef struct _LayerMode LayerMode;
|
||||
struct _LayerMode
|
||||
|
@ -154,8 +145,6 @@ static void apply_layer_mode_replace (guchar *src1,
|
|||
static inline void rotate_pointers (guchar **p,
|
||||
guint32 n);
|
||||
|
||||
|
||||
|
||||
static void
|
||||
update_tile_rowhints (Tile *tile,
|
||||
gint ymin,
|
||||
|
@ -432,6 +421,7 @@ cubic (gdouble dx,
|
|||
( - jm1 + jp1 ) ) * dx + (j + j) ) / 2.0;
|
||||
}
|
||||
|
||||
|
||||
/*********************/
|
||||
/* FUNCTIONS */
|
||||
/*********************/
|
||||
|
@ -2829,275 +2819,6 @@ gaussian_blur_region (PixelRegion *srcR,
|
|||
g_free (buf);
|
||||
}
|
||||
|
||||
|
||||
/* non-interpolating scale_region. [adam]
|
||||
*/
|
||||
static void
|
||||
scale_region_no_resample (PixelRegion *srcPR,
|
||||
PixelRegion *destPR)
|
||||
{
|
||||
gint *x_src_offsets;
|
||||
gint *y_src_offsets;
|
||||
guchar *src;
|
||||
guchar *dest;
|
||||
gint width, height, orig_width, orig_height;
|
||||
gint last_src_y;
|
||||
gint row_bytes;
|
||||
gint x, y, b;
|
||||
gchar bytes;
|
||||
|
||||
orig_width = srcPR->w;
|
||||
orig_height = srcPR->h;
|
||||
|
||||
width = destPR->w;
|
||||
height = destPR->h;
|
||||
|
||||
bytes = srcPR->bytes;
|
||||
|
||||
/* the data pointers... */
|
||||
x_src_offsets = g_new (gint, width * bytes);
|
||||
y_src_offsets = g_new (gint, height);
|
||||
src = g_new (guchar, orig_width * bytes);
|
||||
dest = g_new (guchar, width * bytes);
|
||||
|
||||
/* pre-calc the scale tables */
|
||||
for (b = 0; b < bytes; b++)
|
||||
for (x = 0; x < width; x++)
|
||||
x_src_offsets [b + x * bytes] =
|
||||
b + bytes * ((x * orig_width + orig_width / 2) / width);
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
y_src_offsets [y] = (y * orig_height + orig_height / 2) / height;
|
||||
|
||||
/* do the scaling */
|
||||
row_bytes = width * bytes;
|
||||
last_src_y = -1;
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
/* if the source of this line was the same as the source
|
||||
* of the last line, there's no point in re-rescaling.
|
||||
*/
|
||||
if (y_src_offsets[y] != last_src_y)
|
||||
{
|
||||
pixel_region_get_row (srcPR, 0, y_src_offsets[y], orig_width, src, 1);
|
||||
for (x = 0; x < row_bytes ; x++)
|
||||
{
|
||||
dest[x] = src[x_src_offsets[x]];
|
||||
}
|
||||
last_src_y = y_src_offsets[y];
|
||||
}
|
||||
|
||||
pixel_region_set_row (destPR, 0, y, width, dest);
|
||||
}
|
||||
|
||||
g_free (x_src_offsets);
|
||||
g_free (y_src_offsets);
|
||||
g_free (src);
|
||||
g_free (dest);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
get_premultiplied_double_row (PixelRegion *srcPR,
|
||||
gint x,
|
||||
gint y,
|
||||
gint w,
|
||||
gdouble *row,
|
||||
guchar *tmp_src,
|
||||
gint n)
|
||||
{
|
||||
gint b;
|
||||
gint bytes = srcPR->bytes;
|
||||
|
||||
pixel_region_get_row (srcPR, x, y, w, tmp_src, n);
|
||||
|
||||
if (pixel_region_has_alpha (srcPR))
|
||||
{
|
||||
/* premultiply the alpha into the double array */
|
||||
gdouble *irow = row;
|
||||
gint alpha = bytes - 1;
|
||||
gdouble mod_alpha;
|
||||
|
||||
for (x = 0; x < w; x++)
|
||||
{
|
||||
mod_alpha = tmp_src[alpha] / 255.0;
|
||||
for (b = 0; b < alpha; b++)
|
||||
irow[b] = mod_alpha * tmp_src[b];
|
||||
irow[b] = tmp_src[alpha];
|
||||
irow += bytes;
|
||||
tmp_src += bytes;
|
||||
}
|
||||
}
|
||||
else /* no alpha */
|
||||
{
|
||||
for (x = 0; x < w * bytes; x++)
|
||||
row[x] = tmp_src[x];
|
||||
}
|
||||
|
||||
/* set the off edge pixels to their nearest neighbor */
|
||||
for (b = 0; b < 2 * bytes; b++)
|
||||
row[b - 2 * bytes] = row[b % bytes];
|
||||
for (b = 0; b < bytes * 2; b++)
|
||||
row[b + w * bytes] = row[(w - 1) * bytes + b % bytes];
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
expand_line (gdouble *dest,
|
||||
gdouble *src,
|
||||
gint bytes,
|
||||
gint old_width,
|
||||
gint width,
|
||||
GimpInterpolationType interp)
|
||||
{
|
||||
gdouble ratio;
|
||||
gint x,b;
|
||||
gint src_col;
|
||||
gdouble frac;
|
||||
gdouble *s;
|
||||
|
||||
ratio = old_width / (gdouble) width;
|
||||
|
||||
/* we can overflow src's boundaries, so we expect our caller to have
|
||||
allocated extra space for us to do so safely (see scale_region ()) */
|
||||
|
||||
/* this could be optimized much more by precalculating the coefficients for
|
||||
each x */
|
||||
switch(interp)
|
||||
{
|
||||
case GIMP_INTERPOLATION_CUBIC:
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
src_col = ((int) (x * ratio + 2.0 - 0.5)) - 2;
|
||||
/* +2, -2 is there because (int) rounds towards 0 and we need
|
||||
to round down */
|
||||
frac = (x * ratio - 0.5) - src_col;
|
||||
s = &src[src_col * bytes];
|
||||
for (b = 0; b < bytes; b++)
|
||||
dest[b] = cubic (frac, s[b - bytes], s[b], s[b + bytes],
|
||||
s[b + bytes * 2]);
|
||||
dest += bytes;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case GIMP_INTERPOLATION_LINEAR:
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
src_col = ((int) (x * ratio + 2.0 - 0.5)) - 2;
|
||||
/* +2, -2 is there because (int) rounds towards 0 and we need
|
||||
to round down */
|
||||
frac = (x * ratio - 0.5) - src_col;
|
||||
s = &src[src_col * bytes];
|
||||
for (b = 0; b < bytes; b++)
|
||||
dest[b] = ((s[b + bytes] - s[b]) * frac + s[b]);
|
||||
dest += bytes;
|
||||
}
|
||||
break;
|
||||
|
||||
case GIMP_INTERPOLATION_NONE:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
shrink_line (gdouble *dest,
|
||||
gdouble *src,
|
||||
gint bytes,
|
||||
gint old_width,
|
||||
gint width,
|
||||
GimpInterpolationType interp)
|
||||
{
|
||||
gint x;
|
||||
gint b;
|
||||
gdouble *srcp;
|
||||
gdouble *destp;
|
||||
gdouble accum[4];
|
||||
gdouble slice;
|
||||
const gdouble avg_ratio = (gdouble) width / old_width;
|
||||
const gdouble inv_width = 1.0 / width;
|
||||
gint slicepos; /* slice position relative to width */
|
||||
|
||||
#if 0
|
||||
g_printerr ("shrink_line bytes=%d old_width=%d width=%d interp=%d "
|
||||
"avg_ratio=%f\n",
|
||||
bytes, old_width, width, interp, avg_ratio);
|
||||
#endif
|
||||
|
||||
g_return_if_fail (bytes <= 4);
|
||||
|
||||
/* This algorithm calculates the weighted average of pixel data that
|
||||
each output pixel must receive, taking into account that it always
|
||||
scales down, i.e. there's always more than one input pixel per each
|
||||
output pixel. */
|
||||
|
||||
srcp = src;
|
||||
destp = dest;
|
||||
|
||||
slicepos = 0;
|
||||
|
||||
/* Initialize accum to the first pixel slice. As there is no partial
|
||||
pixel at start, that value is 0. The source data is interleaved, so
|
||||
we maintain BYTES accumulators at the same time to deal with that
|
||||
many channels simultaneously. */
|
||||
for (b = 0; b < bytes; b++)
|
||||
accum[b] = 0.0;
|
||||
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
/* Accumulate whole pixels. */
|
||||
do
|
||||
{
|
||||
for (b = 0; b < bytes; b++)
|
||||
accum[b] += *srcp++;
|
||||
|
||||
slicepos += width;
|
||||
}
|
||||
while (slicepos < old_width);
|
||||
slicepos -= old_width;
|
||||
|
||||
if (! (slicepos < width))
|
||||
g_warning ("Assertion (slicepos < width) failed. Please report.");
|
||||
|
||||
if (slicepos == 0)
|
||||
{
|
||||
/* Simplest case: we have reached a whole pixel boundary. Store
|
||||
the average value per channel and reset the accumulators for
|
||||
the next round.
|
||||
|
||||
The main reason to treat this case separately is to avoid an
|
||||
access to out-of-bounds memory for the first pixel. */
|
||||
for (b = 0; b < bytes; b++)
|
||||
{
|
||||
*destp++ = accum[b] * avg_ratio;
|
||||
accum[b] = 0.0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (b = 0; b < bytes; b++)
|
||||
{
|
||||
/* We have accumulated a whole pixel per channel where just a
|
||||
slice of it was needed. Subtract now the previous pixel's
|
||||
extra slice. */
|
||||
slice = srcp[- bytes + b] * slicepos * inv_width;
|
||||
*destp++ = (accum[b] - slice) * avg_ratio;
|
||||
|
||||
/* That slice is the initial value for the next round. */
|
||||
accum[b] = slice;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Sanity check: srcp should point to the next-to-last position, and
|
||||
slicepos should be zero. */
|
||||
if (! (srcp - src == old_width * bytes && slicepos == 0))
|
||||
g_warning ("Assertion (srcp - src == old_width * bytes && slicepos == 0)"
|
||||
" failed. Please report.");
|
||||
}
|
||||
|
||||
static inline void
|
||||
rotate_pointers (guchar **p,
|
||||
guint32 n)
|
||||
|
@ -3113,421 +2834,6 @@ rotate_pointers (guchar **p,
|
|||
p[i] = tmp;
|
||||
}
|
||||
|
||||
static void
|
||||
get_scaled_row (gdouble **src,
|
||||
gint y,
|
||||
gint new_width,
|
||||
PixelRegion *srcPR,
|
||||
gdouble *row,
|
||||
guchar *src_tmp,
|
||||
GimpInterpolationType interpolation_type)
|
||||
{
|
||||
/* get the necesary lines from the source image, scale them,
|
||||
and put them into src[] */
|
||||
rotate_pointers ((gpointer) src, 4);
|
||||
if (y < 0)
|
||||
y = 0;
|
||||
if (y < srcPR->h)
|
||||
{
|
||||
get_premultiplied_double_row (srcPR, 0, y, srcPR->w,
|
||||
row, src_tmp, 1);
|
||||
if (new_width > srcPR->w)
|
||||
expand_line(src[3], row, srcPR->bytes,
|
||||
srcPR->w, new_width, interpolation_type);
|
||||
else if (srcPR->w > new_width)
|
||||
shrink_line(src[3], row, srcPR->bytes,
|
||||
srcPR->w, new_width, interpolation_type);
|
||||
else /* no scailing needed */
|
||||
memcpy(src[3], row, sizeof (gdouble) * new_width * srcPR->bytes);
|
||||
}
|
||||
else
|
||||
memcpy(src[3], src[2], sizeof (gdouble) * new_width * srcPR->bytes);
|
||||
}
|
||||
|
||||
void
|
||||
scale_region (PixelRegion *srcPR,
|
||||
PixelRegion *destPR,
|
||||
GimpInterpolationType interpolation,
|
||||
GimpProgressFunc progress_callback,
|
||||
gpointer progress_data)
|
||||
{
|
||||
gdouble *src[4];
|
||||
guchar *src_tmp;
|
||||
guchar *dest;
|
||||
gdouble *row, *accum;
|
||||
gint bytes, b;
|
||||
gint width, height;
|
||||
gint orig_width, orig_height;
|
||||
gdouble y_rat;
|
||||
gint i;
|
||||
gint old_y = -4;
|
||||
gint new_y;
|
||||
gint x, y;
|
||||
|
||||
if (interpolation == GIMP_INTERPOLATION_NONE)
|
||||
{
|
||||
scale_region_no_resample (srcPR, destPR);
|
||||
return;
|
||||
}
|
||||
|
||||
orig_width = srcPR->w;
|
||||
orig_height = srcPR->h;
|
||||
|
||||
width = destPR->w;
|
||||
height = destPR->h;
|
||||
|
||||
#if 0
|
||||
g_printerr ("scale_region: (%d x %d) -> (%d x %d)\n",
|
||||
orig_width, orig_height, width, height);
|
||||
#endif
|
||||
|
||||
/* find the ratios of old y to new y */
|
||||
y_rat = (gdouble) orig_height / (gdouble) height;
|
||||
|
||||
bytes = destPR->bytes;
|
||||
|
||||
/* the data pointers... */
|
||||
for (i = 0; i < 4; i++)
|
||||
src[i] = g_new (gdouble, width * bytes);
|
||||
|
||||
dest = g_new (guchar, width * bytes);
|
||||
|
||||
src_tmp = g_new (guchar, orig_width * bytes);
|
||||
|
||||
/* offset the row pointer by 2*bytes so the range of the array
|
||||
is [-2*bytes] to [(orig_width + 2)*bytes] */
|
||||
row = g_new (gdouble, (orig_width + 2 * 2) * bytes);
|
||||
row += bytes * 2;
|
||||
|
||||
accum = g_new (gdouble, width * bytes);
|
||||
|
||||
/* Scale the selected region */
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
if (progress_callback && !(y & 0xf))
|
||||
(* progress_callback) (0, height, y, progress_data);
|
||||
|
||||
if (height < orig_height)
|
||||
{
|
||||
gint max;
|
||||
gdouble frac;
|
||||
const gdouble inv_ratio = 1.0 / y_rat;
|
||||
|
||||
if (y == 0) /* load the first row if this is the first time through */
|
||||
get_scaled_row (&src[0], 0, width, srcPR, row,
|
||||
src_tmp,
|
||||
interpolation);
|
||||
new_y = (int) (y * y_rat);
|
||||
frac = 1.0 - (y * y_rat - new_y);
|
||||
for (x = 0; x < width * bytes; x++)
|
||||
accum[x] = src[3][x] * frac;
|
||||
|
||||
max = (int) ((y + 1) * y_rat) - new_y - 1;
|
||||
|
||||
get_scaled_row (&src[0], ++new_y, width, srcPR, row,
|
||||
src_tmp,
|
||||
interpolation);
|
||||
|
||||
while (max > 0)
|
||||
{
|
||||
for (x = 0; x < width * bytes; x++)
|
||||
accum[x] += src[3][x];
|
||||
get_scaled_row (&src[0], ++new_y, width, srcPR, row,
|
||||
src_tmp,
|
||||
interpolation);
|
||||
max--;
|
||||
}
|
||||
frac = (y + 1) * y_rat - ((int) ((y + 1) * y_rat));
|
||||
for (x = 0; x < width * bytes; x++)
|
||||
{
|
||||
accum[x] += frac * src[3][x];
|
||||
accum[x] *= inv_ratio;
|
||||
}
|
||||
}
|
||||
else if (height > orig_height)
|
||||
{
|
||||
new_y = floor (y * y_rat - 0.5);
|
||||
|
||||
while (old_y <= new_y)
|
||||
{
|
||||
/* get the necesary lines from the source image, scale them,
|
||||
and put them into src[] */
|
||||
get_scaled_row (&src[0], old_y + 2, width, srcPR, row,
|
||||
src_tmp,
|
||||
interpolation);
|
||||
old_y++;
|
||||
}
|
||||
|
||||
switch (interpolation)
|
||||
{
|
||||
case GIMP_INTERPOLATION_CUBIC:
|
||||
{
|
||||
gdouble p0, p1, p2, p3;
|
||||
gdouble dy = (y * y_rat - 0.5) - new_y;
|
||||
|
||||
p0 = cubic (dy, 1, 0, 0, 0);
|
||||
p1 = cubic (dy, 0, 1, 0, 0);
|
||||
p2 = cubic (dy, 0, 0, 1, 0);
|
||||
p3 = cubic (dy, 0, 0, 0, 1);
|
||||
for (x = 0; x < width * bytes; x++)
|
||||
accum[x] = (p0 * src[0][x] + p1 * src[1][x] +
|
||||
p2 * src[2][x] + p3 * src[3][x]);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case GIMP_INTERPOLATION_LINEAR:
|
||||
{
|
||||
gdouble idy = (y * y_rat - 0.5) - new_y;
|
||||
gdouble dy = 1.0 - idy;
|
||||
|
||||
for (x = 0; x < width * bytes; x++)
|
||||
accum[x] = dy * src[1][x] + idy * src[2][x];
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case GIMP_INTERPOLATION_NONE:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else /* height == orig_height */
|
||||
{
|
||||
get_scaled_row (&src[0], y, width, srcPR, row,
|
||||
src_tmp,
|
||||
interpolation);
|
||||
memcpy (accum, src[3], sizeof (gdouble) * width * bytes);
|
||||
}
|
||||
|
||||
if (pixel_region_has_alpha (srcPR))
|
||||
{
|
||||
/* unmultiply the alpha */
|
||||
gdouble inv_alpha;
|
||||
gdouble *p = accum;
|
||||
gint alpha = bytes - 1;
|
||||
gint result;
|
||||
guchar *d = dest;
|
||||
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
if (p[alpha] > 0.001)
|
||||
{
|
||||
inv_alpha = 255.0 / p[alpha];
|
||||
for (b = 0; b < alpha; b++)
|
||||
{
|
||||
result = RINT (inv_alpha * p[b]);
|
||||
if (result < 0)
|
||||
d[b] = 0;
|
||||
else if (result > 255)
|
||||
d[b] = 255;
|
||||
else
|
||||
d[b] = result;
|
||||
}
|
||||
result = RINT (p[alpha]);
|
||||
if (result > 255)
|
||||
d[alpha] = 255;
|
||||
else
|
||||
d[alpha] = result;
|
||||
}
|
||||
else /* alpha <= 0 */
|
||||
for (b = 0; b <= alpha; b++)
|
||||
d[b] = 0;
|
||||
|
||||
d += bytes;
|
||||
p += bytes;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint w = width * bytes;
|
||||
|
||||
for (x = 0; x < w; x++)
|
||||
{
|
||||
if (accum[x] < 0.0)
|
||||
dest[x] = 0;
|
||||
else if (accum[x] > 255.0)
|
||||
dest[x] = 255;
|
||||
else
|
||||
dest[x] = RINT (accum[x]);
|
||||
}
|
||||
}
|
||||
pixel_region_set_row (destPR, 0, y, width, dest);
|
||||
}
|
||||
|
||||
/* free up temporary arrays */
|
||||
g_free (accum);
|
||||
for (i = 0; i < 4; i++)
|
||||
g_free (src[i]);
|
||||
g_free (src_tmp);
|
||||
g_free (dest);
|
||||
|
||||
row -= 2 * bytes;
|
||||
g_free (row);
|
||||
}
|
||||
|
||||
void
|
||||
subsample_region (PixelRegion *srcPR,
|
||||
PixelRegion *destPR,
|
||||
gint subsample)
|
||||
{
|
||||
guchar *src, *s;
|
||||
guchar *dest, *d;
|
||||
gdouble *row, *r;
|
||||
gint destwidth;
|
||||
gint src_row, src_col;
|
||||
gint bytes, b;
|
||||
gint width, height;
|
||||
gint orig_width, orig_height;
|
||||
gdouble x_rat, y_rat;
|
||||
gdouble x_cum, y_cum;
|
||||
gdouble x_last, y_last;
|
||||
gdouble * x_frac, y_frac, tot_frac;
|
||||
gint i, j;
|
||||
gint frac;
|
||||
gint advance_dest;
|
||||
|
||||
orig_width = srcPR->w / subsample;
|
||||
orig_height = srcPR->h / subsample;
|
||||
width = destPR->w;
|
||||
height = destPR->h;
|
||||
|
||||
#if 0
|
||||
g_printerr ("subsample_region: (%d x %d) -> (%d x %d)\n",
|
||||
orig_width, orig_height, width, height);
|
||||
#endif
|
||||
|
||||
/* Some calculations... */
|
||||
bytes = destPR->bytes;
|
||||
destwidth = destPR->rowstride;
|
||||
|
||||
/* the data pointers... */
|
||||
src = g_new (guchar, orig_width * bytes);
|
||||
dest = destPR->data;
|
||||
|
||||
/* find the ratios of old x to new x and old y to new y */
|
||||
x_rat = (gdouble) orig_width / (gdouble) width;
|
||||
y_rat = (gdouble) orig_height / (gdouble) height;
|
||||
|
||||
/* allocate an array to help with the calculations */
|
||||
row = g_new (gdouble, width * bytes);
|
||||
x_frac = g_new (gdouble, width + orig_width);
|
||||
|
||||
/* initialize the pre-calculated pixel fraction array */
|
||||
src_col = 0;
|
||||
x_cum = (gdouble) src_col;
|
||||
x_last = x_cum;
|
||||
|
||||
for (i = 0; i < width + orig_width; i++)
|
||||
{
|
||||
if (x_cum + x_rat <= (src_col + 1 + EPSILON))
|
||||
{
|
||||
x_cum += x_rat;
|
||||
x_frac[i] = x_cum - x_last;
|
||||
}
|
||||
else
|
||||
{
|
||||
src_col ++;
|
||||
x_frac[i] = src_col - x_last;
|
||||
}
|
||||
x_last += x_frac[i];
|
||||
}
|
||||
|
||||
/* clear the "row" array */
|
||||
memset (row, 0, sizeof (gdouble) * width * bytes);
|
||||
|
||||
/* counters... */
|
||||
src_row = 0;
|
||||
y_cum = (gdouble) src_row;
|
||||
y_last = y_cum;
|
||||
|
||||
pixel_region_get_row (srcPR, 0, src_row * subsample, orig_width * subsample, src, subsample);
|
||||
|
||||
/* Scale the selected region */
|
||||
for (i = 0; i < height; )
|
||||
{
|
||||
src_col = 0;
|
||||
x_cum = (gdouble) src_col;
|
||||
|
||||
/* determine the fraction of the src pixel we are using for y */
|
||||
if (y_cum + y_rat <= (src_row + 1 + EPSILON))
|
||||
{
|
||||
y_cum += y_rat;
|
||||
y_frac = y_cum - y_last;
|
||||
advance_dest = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
src_row ++;
|
||||
y_frac = src_row - y_last;
|
||||
advance_dest = FALSE;
|
||||
}
|
||||
|
||||
y_last += y_frac;
|
||||
|
||||
s = src;
|
||||
r = row;
|
||||
|
||||
frac = 0;
|
||||
j = width;
|
||||
|
||||
while (j)
|
||||
{
|
||||
tot_frac = x_frac[frac++] * y_frac;
|
||||
|
||||
for (b = 0; b < bytes; b++)
|
||||
r[b] += s[b] * tot_frac;
|
||||
|
||||
/* increment the destination */
|
||||
if (x_cum + x_rat <= (src_col + 1 + EPSILON))
|
||||
{
|
||||
r += bytes;
|
||||
x_cum += x_rat;
|
||||
j--;
|
||||
}
|
||||
|
||||
/* increment the source */
|
||||
else
|
||||
{
|
||||
s += bytes;
|
||||
src_col++;
|
||||
}
|
||||
}
|
||||
|
||||
if (advance_dest)
|
||||
{
|
||||
tot_frac = 1.0 / (x_rat * y_rat);
|
||||
|
||||
/* copy "row" to "dest" */
|
||||
d = dest;
|
||||
r = row;
|
||||
|
||||
j = width;
|
||||
while (j--)
|
||||
{
|
||||
b = bytes;
|
||||
while (b--)
|
||||
*d++ = (guchar) (*r++ * tot_frac + 0.5);
|
||||
}
|
||||
|
||||
dest += destwidth;
|
||||
|
||||
/* clear the "row" array */
|
||||
memset (row, 0, sizeof (gdouble) * destwidth);
|
||||
|
||||
i++;
|
||||
}
|
||||
else
|
||||
pixel_region_get_row (srcPR, 0, src_row * subsample, orig_width * subsample, src, subsample);
|
||||
}
|
||||
|
||||
/* free up temporary arrays */
|
||||
g_free (row);
|
||||
g_free (x_frac);
|
||||
g_free (src);
|
||||
}
|
||||
|
||||
|
||||
gfloat
|
||||
shapeburst_region (PixelRegion *srcPR,
|
||||
|
|
|
@ -369,12 +369,6 @@ void border_region (PixelRegion *src,
|
|||
gint16 xradius,
|
||||
gint16 yradius);
|
||||
|
||||
void scale_region (PixelRegion *srcPR,
|
||||
PixelRegion *destPR,
|
||||
GimpInterpolationType interpolation,
|
||||
GimpProgressFunc progress_callback,
|
||||
gpointer progress_data);
|
||||
|
||||
void subsample_region (PixelRegion *srcPR,
|
||||
PixelRegion *destPR,
|
||||
gint subsample);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,37 @@
|
|||
/* The GIMP -- an image manipulation program
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __SCALE_FUNCS_H__
|
||||
#define __SCALE_FUNCS_H__
|
||||
|
||||
|
||||
#define EPSILON (0.0001)
|
||||
#define LANCZOS_SPP (1000)
|
||||
#define LANCZOS_WIDTH (2)
|
||||
#define LANCZOS_SAMPLES (1 + (LANCZOS_SPP * LANCZOS_WIDTH))
|
||||
#define LANCZOS_WIDTH2 (LANCZOS_WIDTH * 2)
|
||||
|
||||
|
||||
void scale_region (PixelRegion *srcPR,
|
||||
PixelRegion *destPR,
|
||||
GimpInterpolationType interpolation,
|
||||
GimpProgressFunc progress_callback,
|
||||
gpointer progress_data);
|
||||
|
||||
|
||||
#endif /* __SCALE_FUNCS_H__ */
|
Loading…
Reference in New Issue