1997-11-25 06:05:25 +08:00
|
|
|
/* 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
|
1998-04-13 13:44:11 +08:00
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
1997-11-25 06:05:25 +08:00
|
|
|
*/
|
1999-02-21 07:20:54 +08:00
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
#include <stdlib.h>
|
2001-02-04 12:51:17 +08:00
|
|
|
#include <string.h>
|
2001-02-11 20:15:42 +08:00
|
|
|
#include <stdio.h>
|
1998-07-12 00:25:52 +08:00
|
|
|
|
2001-01-24 23:36:55 +08:00
|
|
|
#include <glib.h>
|
2000-12-17 05:37:03 +08:00
|
|
|
|
2001-01-24 07:56:18 +08:00
|
|
|
#include "libgimpcolor/gimpcolor.h"
|
|
|
|
#include "libgimpmath/gimpmath.h"
|
|
|
|
|
2000-12-17 05:37:03 +08:00
|
|
|
#include "apptypes.h"
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
#include "gimprc.h"
|
|
|
|
#include "paint_funcs.h"
|
2000-12-29 23:22:01 +08:00
|
|
|
#include "pixel_processor.h"
|
|
|
|
#include "pixel_region.h"
|
1998-07-03 07:29:44 +08:00
|
|
|
#include "tile_manager.h"
|
2000-12-29 23:22:01 +08:00
|
|
|
#include "tile.h"
|
1998-07-08 14:41:58 +08:00
|
|
|
|
2000-12-29 23:22:01 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
#define STD_BUF_SIZE 1021
|
|
|
|
#define MAXDIFF 195076
|
|
|
|
#define HASH_TABLE_SIZE 1021
|
|
|
|
#define RANDOM_TABLE_SIZE 4096
|
|
|
|
#define RANDOM_SEED 314159265
|
|
|
|
#define EPSILON 0.0001
|
|
|
|
|
|
|
|
#define INT_MULT(a,b,t) ((t) = (a) * (b) + 0x80, ((((t) >> 8) + (t)) >> 8))
|
1999-03-12 14:04:09 +08:00
|
|
|
|
|
|
|
/* This version of INT_MULT3 is very fast, but suffers from some
|
1999-08-20 18:06:54 +08:00
|
|
|
slight roundoff errors. It returns the correct result 99.987
|
1999-03-12 14:04:09 +08:00
|
|
|
percent of the time */
|
|
|
|
#define INT_MULT3(a,b,c,t) ((t) = (a) * (b) * (c)+ 0x7F5B, \
|
|
|
|
((((t) >> 7) + (t)) >> 16))
|
|
|
|
/*
|
|
|
|
This version of INT_MULT3 always gives the correct result, but runs at
|
|
|
|
approximatly one third the speed. */
|
|
|
|
/* #define INT_MULT3(a,b,c,t) (((a) * (b) * (c)+ 32512) / 65025.0)
|
1999-07-29 18:40:42 +08:00
|
|
|
*/
|
1999-03-12 14:04:09 +08:00
|
|
|
|
1998-12-16 23:48:43 +08:00
|
|
|
#define INT_BLEND(a,b,alpha,tmp) (INT_MULT((a)-(b), alpha, tmp) + (b))
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
typedef enum
|
|
|
|
{
|
|
|
|
MinifyX_MinifyY,
|
|
|
|
MinifyX_MagnifyY,
|
|
|
|
MagnifyX_MinifyY,
|
|
|
|
MagnifyX_MagnifyY
|
|
|
|
} ScaleType;
|
|
|
|
|
2001-01-24 23:36:55 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
/* Layer modes information */
|
|
|
|
typedef struct _LayerMode LayerMode;
|
|
|
|
struct _LayerMode
|
|
|
|
{
|
2001-01-24 23:36:55 +08:00
|
|
|
gboolean affect_alpha; /* does the layer mode affect the alpha channel */
|
|
|
|
gboolean increase_opacity; /* layer mode can increase opacity */
|
|
|
|
gboolean decrease_opacity; /* layer mode can decrease opacity */
|
1997-11-25 06:05:25 +08:00
|
|
|
};
|
|
|
|
|
2001-01-24 23:36:55 +08:00
|
|
|
static const LayerMode layer_modes[] =
|
|
|
|
/* This must obviously be in the same
|
|
|
|
* order as the corresponding values
|
|
|
|
* in the LayerModeEffects enumeration.
|
|
|
|
*/
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2001-01-24 23:36:55 +08:00
|
|
|
{ TRUE, TRUE, FALSE, }, /* NORMAL_MODE */
|
|
|
|
{ TRUE, TRUE, FALSE, }, /* DISSOLVE_MODE */
|
|
|
|
{ TRUE, TRUE, FALSE, }, /* BEHIND_MODE */
|
|
|
|
{ FALSE, FALSE, FALSE, }, /* MULTIPLY_MODE */
|
|
|
|
{ FALSE, FALSE, FALSE, }, /* SCREEN_MODE */
|
|
|
|
{ FALSE, FALSE, FALSE, }, /* OVERLAY_MODE */
|
|
|
|
{ FALSE, FALSE, FALSE, }, /* DIFFERENCE_MODE */
|
|
|
|
{ FALSE, FALSE, FALSE, }, /* ADDITION_MODE */
|
|
|
|
{ FALSE, FALSE, FALSE, }, /* SUBTRACT_MODE */
|
|
|
|
{ FALSE, FALSE, FALSE, }, /* DARKEN_ONLY_MODE */
|
|
|
|
{ FALSE, FALSE, FALSE, }, /* LIGHTEN_ONLY_MODE */
|
|
|
|
{ FALSE, FALSE, FALSE, }, /* HUE_MODE */
|
|
|
|
{ FALSE, FALSE, FALSE, }, /* SATURATION_MODE */
|
|
|
|
{ FALSE, FALSE, FALSE, }, /* COLOR_MODE */
|
|
|
|
{ FALSE, FALSE, FALSE, }, /* VALUE_MODE */
|
|
|
|
{ FALSE, FALSE, FALSE, }, /* DIVIDE_MODE */
|
|
|
|
{ FALSE, FALSE, FALSE, }, /* DODGE_MODE */
|
|
|
|
{ FALSE, FALSE, FALSE, }, /* BURN_MODE */
|
|
|
|
{ FALSE, FALSE, FALSE, }, /* HARDLIGHT_MODE */
|
|
|
|
{ TRUE, FALSE, TRUE, }, /* ERASE_MODE */
|
|
|
|
{ TRUE, TRUE, TRUE, }, /* REPLACE_MODE */
|
|
|
|
{ TRUE, FALSE, TRUE, } /* ANTI_ERASE_MODE */
|
1997-11-25 06:05:25 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/* ColorHash structure */
|
|
|
|
typedef struct _ColorHash ColorHash;
|
|
|
|
|
|
|
|
struct _ColorHash
|
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
gint pixel; /* R << 16 | G << 8 | B */
|
|
|
|
gint index; /* colormap index */
|
|
|
|
GimpImage *gimage;
|
1997-11-25 06:05:25 +08:00
|
|
|
};
|
|
|
|
|
2000-12-29 00:19:55 +08:00
|
|
|
static ColorHash color_hash_table[HASH_TABLE_SIZE];
|
|
|
|
static gint random_table[RANDOM_TABLE_SIZE];
|
|
|
|
static gint color_hash_misses;
|
|
|
|
static gint color_hash_hits;
|
|
|
|
static guchar *tmp_buffer; /* temporary buffer available upon request */
|
|
|
|
static gint tmp_buffer_size;
|
|
|
|
static guchar no_mask = OPAQUE_OPACITY;
|
|
|
|
static gint add_lut[256][256];
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* Local function prototypes */
|
2000-12-29 00:19:55 +08:00
|
|
|
|
2001-01-24 23:36:55 +08:00
|
|
|
static gint * make_curve (gdouble sigma,
|
|
|
|
gint *length);
|
|
|
|
static void run_length_encode (guchar *src,
|
|
|
|
gint *dest,
|
|
|
|
gint w,
|
|
|
|
gint bytes);
|
|
|
|
static gdouble cubic (gdouble dx,
|
|
|
|
gint jm1,
|
|
|
|
gint j,
|
|
|
|
gint jp1,
|
|
|
|
gint jp2);
|
|
|
|
static void apply_layer_mode_replace (guchar *src1,
|
|
|
|
guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
guchar *mask,
|
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint opacity,
|
|
|
|
gint length,
|
|
|
|
gint bytes1,
|
|
|
|
gint bytes2,
|
|
|
|
gboolean *affect);
|
|
|
|
static void rotate_pointers (gpointer *p,
|
|
|
|
guint32 n);
|
2001-02-11 05:14:54 +08:00
|
|
|
/* MMX stuff */
|
|
|
|
extern gboolean use_mmx;
|
|
|
|
|
2001-02-11 20:15:42 +08:00
|
|
|
#ifdef HAVE_ASM_MMX
|
2001-02-11 05:14:54 +08:00
|
|
|
extern int use_mmx;
|
|
|
|
|
|
|
|
#define MMX_PIXEL_OP(x) \
|
|
|
|
void \
|
|
|
|
x( \
|
|
|
|
const unsigned char *src1, \
|
|
|
|
const unsigned char *src2, \
|
|
|
|
unsigned count, \
|
|
|
|
unsigned char *dst) __attribute((regparm(3)));
|
|
|
|
|
|
|
|
#define MMX_PIXEL_OP_3A_1A(op) \
|
|
|
|
MMX_PIXEL_OP(op##_pixels_3a_3a) \
|
|
|
|
MMX_PIXEL_OP(op##_pixels_1a_1a)
|
|
|
|
|
|
|
|
#define USE_MMX_PIXEL_OP_3A_1A(op) \
|
|
|
|
if (use_mmx && has_alpha1 && has_alpha2) \
|
|
|
|
{ \
|
|
|
|
if (bytes1==2 && bytes2==2) \
|
|
|
|
return op##_pixels_1a_1a(src1, src2, length, dest); \
|
|
|
|
if (bytes1==4 && bytes2==4) \
|
|
|
|
return op##_pixels_3a_3a(src1, src2, length, dest); \
|
|
|
|
} \
|
|
|
|
/*fprintf(stderr, "non-MMX: %s(%d, %d, %d, %d)\n", #op, \
|
|
|
|
bytes1, bytes2, has_alpha1, has_alpha2);*/
|
|
|
|
#else
|
2001-01-24 23:36:55 +08:00
|
|
|
|
2001-02-11 05:14:54 +08:00
|
|
|
#define MMX_PIXEL_OP_3A_1A(op)
|
|
|
|
#define USE_MMX_PIXEL_OP_3A_1A(op)
|
|
|
|
#endif
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
|
1999-05-09 23:45:37 +08:00
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
update_tile_rowhints (Tile *tile,
|
|
|
|
gint ymin,
|
|
|
|
gint ymax)
|
1999-05-09 23:45:37 +08:00
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
gint bpp, ewidth;
|
|
|
|
gint x, y;
|
|
|
|
guchar *ptr;
|
|
|
|
guchar alpha;
|
|
|
|
TileRowHint thishint;
|
1999-05-09 23:45:37 +08:00
|
|
|
|
|
|
|
#ifdef HINTS_SANITY
|
2000-12-29 00:19:55 +08:00
|
|
|
g_assert (tile != NULL);
|
1999-05-09 23:45:37 +08:00
|
|
|
#endif
|
|
|
|
|
1999-12-14 03:48:24 +08:00
|
|
|
tile_sanitize_rowhints (tile);
|
|
|
|
|
1999-05-09 23:45:37 +08:00
|
|
|
bpp = tile_bpp (tile);
|
2001-01-23 22:21:37 +08:00
|
|
|
ewidth = tile_ewidth (tile);
|
1999-05-09 23:45:37 +08:00
|
|
|
|
|
|
|
if (bpp == 1 || bpp == 3)
|
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
for (y = ymin; y <= ymax; y++)
|
1999-05-09 23:45:37 +08:00
|
|
|
tile_set_rowhint (tile, y, TILEROWHINT_OPAQUE);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bpp == 4)
|
|
|
|
{
|
|
|
|
#ifdef HINTS_SANITY
|
2000-12-29 00:19:55 +08:00
|
|
|
g_assert (tile != NULL);
|
1999-05-09 23:45:37 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
ptr = tile_data_pointer (tile, 0, ymin);
|
|
|
|
|
|
|
|
#ifdef HINTS_SANITY
|
2000-12-29 00:19:55 +08:00
|
|
|
g_assert (ptr != NULL);
|
1999-05-09 23:45:37 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
for (y = ymin; y <= ymax; y++)
|
|
|
|
{
|
|
|
|
thishint = tile_get_rowhint (tile, y);
|
|
|
|
|
|
|
|
#ifdef HINTS_SANITY
|
2000-12-29 00:19:55 +08:00
|
|
|
if (thishint == TILEROWHINT_BROKEN)
|
|
|
|
g_error ("BROKEN y=%d",y);
|
|
|
|
if (thishint == TILEROWHINT_OUTOFRANGE)
|
|
|
|
g_error ("OOR y=%d",y);
|
|
|
|
if (thishint == TILEROWHINT_UNDEFINED)
|
|
|
|
g_error ("UNDEFINED y=%d - bpp=%d ew=%d eh=%d",
|
|
|
|
y, bpp, ewidth, eheight);
|
1999-05-09 23:45:37 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HINTS_SANITY
|
|
|
|
if (thishint == TILEROWHINT_TRANSPARENT ||
|
|
|
|
thishint == TILEROWHINT_MIXED ||
|
|
|
|
thishint == TILEROWHINT_OPAQUE)
|
|
|
|
{
|
|
|
|
goto next_row4;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (thishint != TILEROWHINT_UNKNOWN)
|
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
g_error ("MEGABOGUS y=%d - bpp=%d ew=%d eh=%d",
|
|
|
|
y, bpp, ewidth, eheight);
|
1999-05-09 23:45:37 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (thishint == TILEROWHINT_UNKNOWN)
|
|
|
|
{
|
|
|
|
alpha = ptr[3];
|
|
|
|
|
|
|
|
/* row is all-opaque or all-transparent? */
|
|
|
|
if (alpha == 0 || alpha == 255)
|
|
|
|
{
|
|
|
|
if (ewidth > 1)
|
|
|
|
{
|
|
|
|
for (x = 1; x < ewidth; x++)
|
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
if (ptr[x * 4 + 3] != alpha)
|
1999-05-09 23:45:37 +08:00
|
|
|
{
|
|
|
|
tile_set_rowhint (tile, y, TILEROWHINT_MIXED);
|
|
|
|
goto next_row4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tile_set_rowhint (tile, y,
|
|
|
|
(alpha == 0) ?
|
|
|
|
TILEROWHINT_TRANSPARENT :
|
|
|
|
TILEROWHINT_OPAQUE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tile_set_rowhint (tile, y, TILEROWHINT_MIXED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
next_row4:
|
|
|
|
ptr += 4 * ewidth;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bpp == 2)
|
|
|
|
{
|
|
|
|
#ifdef HINTS_SANITY
|
2000-12-31 22:58:08 +08:00
|
|
|
g_assert (tile != NULL);
|
1999-05-09 23:45:37 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
ptr = tile_data_pointer (tile, 0, ymin);
|
|
|
|
|
|
|
|
#ifdef HINTS_SANITY
|
2000-12-31 22:58:08 +08:00
|
|
|
g_assert (ptr != NULL);
|
1999-05-09 23:45:37 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
for (y = ymin; y <= ymax; y++)
|
|
|
|
{
|
|
|
|
thishint = tile_get_rowhint (tile, y);
|
|
|
|
|
|
|
|
#ifdef HINTS_SANITY
|
2000-12-29 00:19:55 +08:00
|
|
|
if (thishint == TILEROWHINT_BROKEN)
|
|
|
|
g_error ("BROKEN y=%d",y);
|
|
|
|
if (thishint == TILEROWHINT_OUTOFRANGE)
|
|
|
|
g_error ("OOR y=%d",y);
|
|
|
|
if (thishint == TILEROWHINT_UNDEFINED)
|
|
|
|
g_error ("UNDEFINED y=%d - bpp=%d ew=%d eh=%d",
|
|
|
|
y, bpp, ewidth, eheight);
|
1999-05-09 23:45:37 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HINTS_SANITY
|
|
|
|
if (thishint == TILEROWHINT_TRANSPARENT ||
|
|
|
|
thishint == TILEROWHINT_MIXED ||
|
|
|
|
thishint == TILEROWHINT_OPAQUE)
|
|
|
|
{
|
|
|
|
goto next_row2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (thishint != TILEROWHINT_UNKNOWN)
|
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
g_error ("MEGABOGUS y=%d - bpp=%d ew=%d eh=%d",
|
|
|
|
y, bpp, ewidth, eheight);
|
1999-05-09 23:45:37 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (thishint == TILEROWHINT_UNKNOWN)
|
|
|
|
{
|
|
|
|
alpha = ptr[1];
|
|
|
|
|
|
|
|
/* row is all-opaque or all-transparent? */
|
|
|
|
if (alpha == 0 || alpha == 255)
|
|
|
|
{
|
|
|
|
if (ewidth > 1)
|
|
|
|
{
|
|
|
|
for (x = 1; x < ewidth; x++)
|
|
|
|
{
|
|
|
|
if (ptr[x*2 + 1] != alpha)
|
|
|
|
{
|
|
|
|
tile_set_rowhint (tile, y, TILEROWHINT_MIXED);
|
|
|
|
goto next_row2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tile_set_rowhint (tile, y,
|
|
|
|
(alpha == 0) ?
|
|
|
|
TILEROWHINT_TRANSPARENT :
|
|
|
|
TILEROWHINT_OPAQUE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tile_set_rowhint (tile, y, TILEROWHINT_MIXED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
next_row2:
|
|
|
|
ptr += 2 * ewidth;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_warning ("update_tile_rowhints: Don't know about tiles with bpp==%d", bpp);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-12-29 00:19:55 +08:00
|
|
|
static guchar *
|
|
|
|
paint_funcs_get_buffer (gint size)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
if (size > tmp_buffer_size)
|
|
|
|
{
|
|
|
|
tmp_buffer_size = size;
|
2000-12-29 00:19:55 +08:00
|
|
|
tmp_buffer = (guchar *) g_realloc (tmp_buffer, size);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return tmp_buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The equations: g(r) = exp (- r^2 / (2 * sigma^2))
|
|
|
|
* r = sqrt (x^2 + y ^2)
|
|
|
|
*/
|
|
|
|
|
2000-12-29 00:19:55 +08:00
|
|
|
static gint *
|
|
|
|
make_curve (gdouble sigma,
|
|
|
|
gint *length)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
gint *curve;
|
|
|
|
gdouble sigma2;
|
|
|
|
gdouble l;
|
|
|
|
gint temp;
|
|
|
|
gint i, n;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
sigma2 = 2 * sigma * sigma;
|
|
|
|
l = sqrt (-sigma2 * log (1.0 / 255.0));
|
|
|
|
|
|
|
|
n = ceil (l) * 2;
|
|
|
|
if ((n % 2) == 0)
|
|
|
|
n += 1;
|
|
|
|
|
2000-12-29 00:19:55 +08:00
|
|
|
curve = g_new (gint, n);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
*length = n / 2;
|
|
|
|
curve += *length;
|
|
|
|
curve[0] = 255;
|
|
|
|
|
|
|
|
for (i = 1; i <= *length; i++)
|
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
temp = (gint) (exp (- (i * i) / sigma2) * 255);
|
1997-11-25 06:05:25 +08:00
|
|
|
curve[-i] = temp;
|
|
|
|
curve[i] = temp;
|
|
|
|
}
|
|
|
|
|
|
|
|
return curve;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2000-12-29 00:19:55 +08:00
|
|
|
run_length_encode (guchar *src,
|
|
|
|
gint *dest,
|
|
|
|
gint w,
|
|
|
|
gint bytes)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
gint start;
|
|
|
|
gint i;
|
|
|
|
gint j;
|
|
|
|
guchar last;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
last = *src;
|
|
|
|
src += bytes;
|
|
|
|
start = 0;
|
|
|
|
|
|
|
|
for (i = 1; i < w; i++)
|
|
|
|
{
|
|
|
|
if (*src != last)
|
|
|
|
{
|
|
|
|
for (j = start; j < i; j++)
|
|
|
|
{
|
|
|
|
*dest++ = (i - j);
|
|
|
|
*dest++ = last;
|
|
|
|
}
|
|
|
|
start = i;
|
|
|
|
last = *src;
|
|
|
|
}
|
|
|
|
src += bytes;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (j = start; j < i; j++)
|
|
|
|
{
|
|
|
|
*dest++ = (i - j);
|
|
|
|
*dest++ = last;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-08-20 18:06:54 +08:00
|
|
|
/* Note: cubic function no longer clips result */
|
2000-12-29 00:19:55 +08:00
|
|
|
static inline gdouble
|
|
|
|
cubic (gdouble dx,
|
|
|
|
gint jm1,
|
|
|
|
gint j,
|
|
|
|
gint jp1,
|
|
|
|
gint jp2)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1999-08-20 18:06:54 +08:00
|
|
|
/* Catmull-Rom - not bad */
|
2000-12-29 00:19:55 +08:00
|
|
|
return (gdouble) ((( ( - jm1 + 3 * j - 3 * jp1 + jp2 ) * dx +
|
|
|
|
( 2 * jm1 - 5 * j + 4 * jp1 - jp2 ) ) * dx +
|
|
|
|
( - jm1 + jp1 ) ) * dx + (j + j) ) / 2.0;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*********************/
|
|
|
|
/* FUNCTIONS */
|
|
|
|
/*********************/
|
|
|
|
|
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
paint_funcs_setup (void)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
gint i;
|
|
|
|
gint j, k;
|
|
|
|
gint tmp_sum;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* allocate the temporary buffer */
|
2000-12-29 00:19:55 +08:00
|
|
|
tmp_buffer = g_new (guchar, STD_BUF_SIZE);
|
1997-11-25 06:05:25 +08:00
|
|
|
tmp_buffer_size = STD_BUF_SIZE;
|
|
|
|
|
|
|
|
/* initialize the color hash table--invalidate all entries */
|
|
|
|
for (i = 0; i < HASH_TABLE_SIZE; i++)
|
1998-06-29 08:24:44 +08:00
|
|
|
color_hash_table[i].gimage = NULL;
|
1997-11-25 06:05:25 +08:00
|
|
|
color_hash_misses = 0;
|
|
|
|
color_hash_hits = 0;
|
|
|
|
|
|
|
|
/* generate a table of random seeds */
|
|
|
|
srand (RANDOM_SEED);
|
2000-06-18 01:37:36 +08:00
|
|
|
|
2000-11-05 21:58:17 +08:00
|
|
|
/* FIXME: Why creating an array of random values and shuffle it randomly
|
2000-06-18 01:37:36 +08:00
|
|
|
* afterwards???
|
|
|
|
*/
|
2000-12-29 00:19:55 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
for (i = 0; i < RANDOM_TABLE_SIZE; i++)
|
|
|
|
random_table[i] = rand ();
|
1998-05-02 15:44:58 +08:00
|
|
|
|
|
|
|
for (i = 0; i < RANDOM_TABLE_SIZE; i++)
|
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
gint tmp;
|
|
|
|
gint swap = i + rand () % (RANDOM_TABLE_SIZE - i);
|
|
|
|
|
1998-05-02 15:44:58 +08:00
|
|
|
tmp = random_table[i];
|
|
|
|
random_table[i] = random_table[swap];
|
|
|
|
random_table[swap] = tmp;
|
|
|
|
}
|
Lots of ii8n stuff here and some additions to the de.po. Applied
Wed Oct 14 17:46:15 EDT 1998 Adrian Likins <adrian@gimp.org>
* app/*, po/de.po, de/POTFILES.in, libgimp/gimpintl.h:
Lots of ii8n stuff here and some additions to the de.po.
Applied gimp-egger-981005-1 ,gimp-egger-981006-1,
gimp-egger-981007-1, gimp-egger-981008-1,
gimp-egger-981009-1.patch, gimp-egger-981010-1.patch
* plug-in/guillotine/guillotine.c: added the coordinates
of the split images from the original image to the title.
ie foo.jpg (0,0) for the image in the topleft.
* plug-in/script-fu/scripts/neon-logo.scm,
perspective-shadow.scm, predator.scm,rendermap.scm,
ripply-anim.scm, select_to_image.scm,swirltile.scm,
xach-effect.scm: updated scripts to use new script-fu stuff
wooo boy! a big un!
in testing this, it looks like some of the po files are busted.
but the code stuff seems okay.
-adrian
1998-10-15 07:23:52 +08:00
|
|
|
|
|
|
|
for (j = 0; j < 256; j++)
|
1998-10-22 17:49:46 +08:00
|
|
|
{ /* rows */
|
Lots of ii8n stuff here and some additions to the de.po. Applied
Wed Oct 14 17:46:15 EDT 1998 Adrian Likins <adrian@gimp.org>
* app/*, po/de.po, de/POTFILES.in, libgimp/gimpintl.h:
Lots of ii8n stuff here and some additions to the de.po.
Applied gimp-egger-981005-1 ,gimp-egger-981006-1,
gimp-egger-981007-1, gimp-egger-981008-1,
gimp-egger-981009-1.patch, gimp-egger-981010-1.patch
* plug-in/guillotine/guillotine.c: added the coordinates
of the split images from the original image to the title.
ie foo.jpg (0,0) for the image in the topleft.
* plug-in/script-fu/scripts/neon-logo.scm,
perspective-shadow.scm, predator.scm,rendermap.scm,
ripply-anim.scm, select_to_image.scm,swirltile.scm,
xach-effect.scm: updated scripts to use new script-fu stuff
wooo boy! a big un!
in testing this, it looks like some of the po files are busted.
but the code stuff seems okay.
-adrian
1998-10-15 07:23:52 +08:00
|
|
|
for (k = 0; k < 256; k++)
|
1998-10-22 17:49:46 +08:00
|
|
|
{ /* column */
|
Lots of ii8n stuff here and some additions to the de.po. Applied
Wed Oct 14 17:46:15 EDT 1998 Adrian Likins <adrian@gimp.org>
* app/*, po/de.po, de/POTFILES.in, libgimp/gimpintl.h:
Lots of ii8n stuff here and some additions to the de.po.
Applied gimp-egger-981005-1 ,gimp-egger-981006-1,
gimp-egger-981007-1, gimp-egger-981008-1,
gimp-egger-981009-1.patch, gimp-egger-981010-1.patch
* plug-in/guillotine/guillotine.c: added the coordinates
of the split images from the original image to the title.
ie foo.jpg (0,0) for the image in the topleft.
* plug-in/script-fu/scripts/neon-logo.scm,
perspective-shadow.scm, predator.scm,rendermap.scm,
ripply-anim.scm, select_to_image.scm,swirltile.scm,
xach-effect.scm: updated scripts to use new script-fu stuff
wooo boy! a big un!
in testing this, it looks like some of the po files are busted.
but the code stuff seems okay.
-adrian
1998-10-15 07:23:52 +08:00
|
|
|
tmp_sum = j + k;
|
2000-12-29 00:19:55 +08:00
|
|
|
|
|
|
|
if (tmp_sum > 255)
|
Lots of ii8n stuff here and some additions to the de.po. Applied
Wed Oct 14 17:46:15 EDT 1998 Adrian Likins <adrian@gimp.org>
* app/*, po/de.po, de/POTFILES.in, libgimp/gimpintl.h:
Lots of ii8n stuff here and some additions to the de.po.
Applied gimp-egger-981005-1 ,gimp-egger-981006-1,
gimp-egger-981007-1, gimp-egger-981008-1,
gimp-egger-981009-1.patch, gimp-egger-981010-1.patch
* plug-in/guillotine/guillotine.c: added the coordinates
of the split images from the original image to the title.
ie foo.jpg (0,0) for the image in the topleft.
* plug-in/script-fu/scripts/neon-logo.scm,
perspective-shadow.scm, predator.scm,rendermap.scm,
ripply-anim.scm, select_to_image.scm,swirltile.scm,
xach-effect.scm: updated scripts to use new script-fu stuff
wooo boy! a big un!
in testing this, it looks like some of the po files are busted.
but the code stuff seems okay.
-adrian
1998-10-15 07:23:52 +08:00
|
|
|
tmp_sum = 255;
|
2000-12-29 00:19:55 +08:00
|
|
|
|
Lots of ii8n stuff here and some additions to the de.po. Applied
Wed Oct 14 17:46:15 EDT 1998 Adrian Likins <adrian@gimp.org>
* app/*, po/de.po, de/POTFILES.in, libgimp/gimpintl.h:
Lots of ii8n stuff here and some additions to the de.po.
Applied gimp-egger-981005-1 ,gimp-egger-981006-1,
gimp-egger-981007-1, gimp-egger-981008-1,
gimp-egger-981009-1.patch, gimp-egger-981010-1.patch
* plug-in/guillotine/guillotine.c: added the coordinates
of the split images from the original image to the title.
ie foo.jpg (0,0) for the image in the topleft.
* plug-in/script-fu/scripts/neon-logo.scm,
perspective-shadow.scm, predator.scm,rendermap.scm,
ripply-anim.scm, select_to_image.scm,swirltile.scm,
xach-effect.scm: updated scripts to use new script-fu stuff
wooo boy! a big un!
in testing this, it looks like some of the po files are busted.
but the code stuff seems okay.
-adrian
1998-10-15 07:23:52 +08:00
|
|
|
add_lut[j][k] = tmp_sum;
|
|
|
|
}
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
paint_funcs_free (void)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
/* free the temporary buffer */
|
|
|
|
g_free (tmp_buffer);
|
|
|
|
|
|
|
|
/* print out the hash table statistics
|
|
|
|
printf ("RGB->indexed hash table lookups: %d\n", color_hash_hits + color_hash_misses);
|
|
|
|
printf ("RGB->indexed hash table hits: %d\n", color_hash_hits);
|
|
|
|
printf ("RGB->indexed hash table misses: %d\n", color_hash_misses);
|
|
|
|
printf ("RGB->indexed hash table hit rate: %f\n",
|
|
|
|
100.0 * color_hash_hits / (color_hash_hits + color_hash_misses));
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
2000-02-11 05:38:43 +08:00
|
|
|
void
|
|
|
|
paint_funcs_invalidate_color_hash_table (GimpImage* gimage,
|
|
|
|
gint index)
|
|
|
|
{
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
g_return_if_fail (gimage != NULL);
|
|
|
|
|
|
|
|
if (index == -1) /* invalidate all entries */
|
|
|
|
{
|
|
|
|
for (i = 0; i < HASH_TABLE_SIZE; i++)
|
|
|
|
if (color_hash_table[i].gimage == gimage)
|
|
|
|
color_hash_table[i].gimage = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (i = 0; i < HASH_TABLE_SIZE; i++)
|
|
|
|
if (color_hash_table[i].gimage == gimage &&
|
|
|
|
color_hash_table[i].index == index)
|
|
|
|
color_hash_table[i].gimage = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
color_pixels (guchar *dest,
|
|
|
|
const guchar *color,
|
|
|
|
gint w,
|
|
|
|
gint bytes)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1998-07-20 01:37:14 +08:00
|
|
|
/* dest % bytes and color % bytes must be 0 or we will crash
|
|
|
|
when bytes = 2 or 4.
|
|
|
|
Is this safe to assume? Lets find out.
|
|
|
|
This is 4-7X as fast as the simple version.
|
|
|
|
*/
|
2000-09-28 01:36:52 +08:00
|
|
|
|
2000-10-18 02:32:43 +08:00
|
|
|
#if defined(sparc) || defined(__sparc__)
|
2000-12-29 00:19:55 +08:00
|
|
|
register guchar c0, c1, c2, c3;
|
2000-10-18 02:32:43 +08:00
|
|
|
#else
|
2000-12-29 00:19:55 +08:00
|
|
|
register guchar c0, c1, c2;
|
1998-07-20 01:37:14 +08:00
|
|
|
register guint32 *longd, longc;
|
|
|
|
register guint16 *shortd, shortc;
|
2000-10-18 02:32:43 +08:00
|
|
|
#endif
|
|
|
|
|
1998-07-20 01:37:14 +08:00
|
|
|
switch (bytes)
|
2000-12-29 00:19:55 +08:00
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
memset (dest, *color, w);
|
|
|
|
break;
|
2000-09-28 01:36:52 +08:00
|
|
|
|
2000-12-29 00:19:55 +08:00
|
|
|
case 2:
|
2000-09-28 01:36:52 +08:00
|
|
|
#if defined(sparc) || defined(__sparc__)
|
2000-12-29 00:19:55 +08:00
|
|
|
c0 = color[0];
|
|
|
|
c1 = color[1];
|
|
|
|
while (w--)
|
|
|
|
{
|
|
|
|
dest[0] = c0;
|
|
|
|
dest[1] = c1;
|
|
|
|
dest += 2;
|
|
|
|
}
|
2000-09-28 01:36:52 +08:00
|
|
|
#else
|
2000-12-29 00:19:55 +08:00
|
|
|
shortc = ((guint16 *) color)[0];
|
|
|
|
shortd = (guint16 *) dest;
|
|
|
|
while (w--)
|
|
|
|
{
|
|
|
|
*shortd = shortc;
|
|
|
|
shortd++;
|
|
|
|
}
|
2000-09-28 01:36:52 +08:00
|
|
|
#endif /* sparc || __sparc__ */
|
2000-12-29 00:19:55 +08:00
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
c0 = color[0];
|
|
|
|
c1 = color[1];
|
|
|
|
c2 = color[2];
|
|
|
|
while (w--)
|
|
|
|
{
|
|
|
|
dest[0] = c0;
|
|
|
|
dest[1] = c1;
|
|
|
|
dest[2] = c2;
|
|
|
|
dest += 3;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 4:
|
2000-09-28 01:36:52 +08:00
|
|
|
#if defined(sparc) || defined(__sparc__)
|
2000-12-29 00:19:55 +08:00
|
|
|
c0 = color[0];
|
|
|
|
c1 = color[1];
|
|
|
|
c2 = color[2];
|
|
|
|
c3 = color[3];
|
|
|
|
while (w--)
|
|
|
|
{
|
|
|
|
dest[0] = c0;
|
|
|
|
dest[1] = c1;
|
|
|
|
dest[2] = c2;
|
|
|
|
dest[3] = c3;
|
|
|
|
dest += 4;
|
|
|
|
}
|
2000-09-28 01:36:52 +08:00
|
|
|
#else
|
2000-12-29 00:19:55 +08:00
|
|
|
longc = ((guint32 *) color)[0];
|
|
|
|
longd = (guint32 *) dest;
|
|
|
|
while (w--)
|
|
|
|
{
|
|
|
|
*longd = longc;
|
|
|
|
longd++;
|
|
|
|
}
|
2000-09-28 01:36:52 +08:00
|
|
|
#endif /* sparc || __sparc__ */
|
2000-12-29 00:19:55 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
while (w--)
|
|
|
|
{
|
|
|
|
memcpy (dest, color, bytes);
|
|
|
|
dest += bytes;
|
|
|
|
}
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
blend_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
gint blend,
|
|
|
|
gint w,
|
|
|
|
gint bytes,
|
|
|
|
gint has_alpha)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
gint b;
|
|
|
|
guchar blend2 = (255 - blend);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
while (w --)
|
|
|
|
{
|
1999-07-02 00:52:50 +08:00
|
|
|
for (b = 0; b < bytes; b++)
|
1997-11-25 06:05:25 +08:00
|
|
|
dest[b] = (src1[b] * blend2 + src2[b] * blend) / 255;
|
|
|
|
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += bytes;
|
|
|
|
dest += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
shade_pixels (const guchar *src,
|
|
|
|
guchar *dest,
|
|
|
|
const guchar *col,
|
|
|
|
gint blend,
|
|
|
|
gint w,
|
|
|
|
gint bytes,
|
|
|
|
gint has_alpha)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
gint alpha, b;
|
|
|
|
guchar blend2 = (255 - blend);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
alpha = (has_alpha) ? bytes - 1 : bytes;
|
|
|
|
while (w --)
|
|
|
|
{
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
dest[b] = (src[b] * blend2 + col[b] * blend) / 255;
|
|
|
|
|
|
|
|
if (has_alpha)
|
|
|
|
dest[alpha] = src[alpha]; /* alpha channel */
|
|
|
|
|
|
|
|
src += bytes;
|
|
|
|
dest += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
extract_alpha_pixels (const guchar *src,
|
|
|
|
const guchar *mask,
|
|
|
|
guchar *dest,
|
|
|
|
gint w,
|
|
|
|
gint bytes)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
const guchar *m;
|
|
|
|
gint tmp;
|
1998-07-12 00:25:52 +08:00
|
|
|
|
2000-12-29 00:19:55 +08:00
|
|
|
const gint alpha = bytes - 1;
|
2000-06-18 01:37:36 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
if (mask)
|
|
|
|
{
|
2000-06-18 01:37:36 +08:00
|
|
|
m = mask;
|
|
|
|
while (w --)
|
|
|
|
{
|
|
|
|
*dest++ = INT_MULT(src[alpha], *m, tmp);
|
|
|
|
m++;
|
|
|
|
src += bytes;
|
|
|
|
}
|
2000-12-29 00:19:55 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m = &no_mask;
|
|
|
|
while (w --)
|
2000-06-18 01:37:36 +08:00
|
|
|
{
|
|
|
|
*dest++ = INT_MULT(src[alpha], *m, tmp);
|
|
|
|
src += bytes;
|
|
|
|
}
|
2000-12-29 00:19:55 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
2001-02-11 05:14:54 +08:00
|
|
|
MMX_PIXEL_OP_3A_1A(darken)
|
1997-11-25 06:05:25 +08:00
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
darken_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
gint length,
|
|
|
|
gint bytes1,
|
|
|
|
gint bytes2,
|
|
|
|
gint has_alpha1,
|
|
|
|
gint has_alpha2)
|
|
|
|
{
|
|
|
|
gint b, alpha;
|
|
|
|
guchar s1, s2;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2001-02-11 05:14:54 +08:00
|
|
|
USE_MMX_PIXEL_OP_3A_1A(darken)
|
|
|
|
|
2000-01-26 07:06:12 +08:00
|
|
|
alpha = (has_alpha1 || has_alpha2) ? MAX (bytes1, bytes2) - 1 : bytes1;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
while (length--)
|
|
|
|
{
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
{
|
|
|
|
s1 = src1[b];
|
|
|
|
s2 = src2[b];
|
|
|
|
dest[b] = (s1 < s2) ? s1 : s2;
|
|
|
|
}
|
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
if (has_alpha1 && has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
dest[alpha] = MIN (src1[alpha], src2[alpha]);
|
1998-09-15 09:53:40 +08:00
|
|
|
else if (has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
dest[alpha] = src2[alpha];
|
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
src1 += bytes1;
|
|
|
|
src2 += bytes2;
|
|
|
|
dest += bytes2;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-02-11 05:14:54 +08:00
|
|
|
MMX_PIXEL_OP_3A_1A(lighten)
|
1997-11-25 06:05:25 +08:00
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
lighten_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
gint length,
|
|
|
|
gint bytes1,
|
|
|
|
gint bytes2,
|
|
|
|
gint has_alpha1,
|
|
|
|
gint has_alpha2)
|
|
|
|
{
|
|
|
|
gint b, alpha;
|
|
|
|
guchar s1, s2;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2001-02-11 05:14:54 +08:00
|
|
|
USE_MMX_PIXEL_OP_3A_1A(lighten)
|
|
|
|
|
2000-01-26 07:06:12 +08:00
|
|
|
alpha = (has_alpha1 || has_alpha2) ? MAX (bytes1, bytes2) - 1 : bytes1;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
while (length--)
|
|
|
|
{
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
{
|
|
|
|
s1 = src1[b];
|
|
|
|
s2 = src2[b];
|
|
|
|
dest[b] = (s1 < s2) ? s2 : s1;
|
|
|
|
}
|
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
if (has_alpha1 && has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
dest[alpha] = MIN (src1[alpha], src2[alpha]);
|
1998-09-15 09:53:40 +08:00
|
|
|
else if (has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
dest[alpha] = src2[alpha];
|
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
src1 += bytes1;
|
|
|
|
src2 += bytes2;
|
|
|
|
dest += bytes2;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
hsv_only_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
gint mode,
|
|
|
|
gint length,
|
|
|
|
gint bytes1,
|
|
|
|
gint bytes2,
|
|
|
|
gint has_alpha1,
|
|
|
|
gint has_alpha2)
|
|
|
|
{
|
|
|
|
gint r1, g1, b1;
|
|
|
|
gint r2, g2, b2;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* assumes inputs are only 4 byte RGBA pixels */
|
|
|
|
while (length--)
|
|
|
|
{
|
|
|
|
r1 = src1[0]; g1 = src1[1]; b1 = src1[2];
|
|
|
|
r2 = src2[0]; g2 = src2[1]; b2 = src2[2];
|
2000-12-31 22:58:08 +08:00
|
|
|
gimp_rgb_to_hsv_int (&r1, &g1, &b1);
|
|
|
|
gimp_rgb_to_hsv_int (&r2, &g2, &b2);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
switch (mode)
|
|
|
|
{
|
|
|
|
case HUE_MODE:
|
|
|
|
r1 = r2;
|
|
|
|
break;
|
|
|
|
case SATURATION_MODE:
|
|
|
|
g1 = g2;
|
|
|
|
break;
|
|
|
|
case VALUE_MODE:
|
|
|
|
b1 = b2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set the destination */
|
2000-12-31 22:58:08 +08:00
|
|
|
gimp_hsv_to_rgb_int (&r1, &g1, &b1);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
dest[0] = r1; dest[1] = g1; dest[2] = b1;
|
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
if (has_alpha1 && has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
dest[3] = MIN (src1[3], src2[3]);
|
1998-09-15 09:53:40 +08:00
|
|
|
else if (has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
dest[3] = src2[3];
|
|
|
|
|
|
|
|
src1 += bytes1;
|
|
|
|
src2 += bytes2;
|
|
|
|
dest += bytes2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
color_only_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
gint mode,
|
|
|
|
gint length,
|
|
|
|
gint bytes1,
|
|
|
|
gint bytes2,
|
|
|
|
gint has_alpha1,
|
|
|
|
gint has_alpha2)
|
|
|
|
{
|
|
|
|
gint r1, g1, b1;
|
|
|
|
gint r2, g2, b2;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* assumes inputs are only 4 byte RGBA pixels */
|
|
|
|
while (length--)
|
|
|
|
{
|
|
|
|
r1 = src1[0]; g1 = src1[1]; b1 = src1[2];
|
|
|
|
r2 = src2[0]; g2 = src2[1]; b2 = src2[2];
|
2000-12-31 22:58:08 +08:00
|
|
|
gimp_rgb_to_hls_int (&r1, &g1, &b1);
|
|
|
|
gimp_rgb_to_hls_int (&r2, &g2, &b2);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* transfer hue and saturation to the source pixel */
|
|
|
|
r1 = r2;
|
|
|
|
b1 = b2;
|
|
|
|
|
|
|
|
/* set the destination */
|
2000-12-31 22:58:08 +08:00
|
|
|
gimp_hls_to_rgb_int (&r1, &g1, &b1);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
dest[0] = r1; dest[1] = g1; dest[2] = b1;
|
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
if (has_alpha1 && has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
dest[3] = MIN (src1[3], src2[3]);
|
1998-09-15 09:53:40 +08:00
|
|
|
else if (has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
dest[3] = src2[3];
|
|
|
|
|
|
|
|
src1 += bytes1;
|
|
|
|
src2 += bytes2;
|
|
|
|
dest += bytes2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-02-11 05:14:54 +08:00
|
|
|
MMX_PIXEL_OP_3A_1A(multiply)
|
1997-11-25 06:05:25 +08:00
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
multiply_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
gint length,
|
|
|
|
gint bytes1,
|
|
|
|
gint bytes2,
|
|
|
|
gint has_alpha1,
|
|
|
|
gint has_alpha2)
|
|
|
|
{
|
|
|
|
gint alpha, b;
|
|
|
|
gint tmp;
|
|
|
|
|
2001-02-11 05:14:54 +08:00
|
|
|
USE_MMX_PIXEL_OP_3A_1A(multiply)
|
|
|
|
|
2000-01-26 07:06:12 +08:00
|
|
|
alpha = (has_alpha1 || has_alpha2) ? MAX (bytes1, bytes2) - 1 : bytes1;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-12-16 19:23:30 +08:00
|
|
|
if (has_alpha1 && has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
dest[b] = INT_MULT(src1[b], src2[b], tmp);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-12-29 00:19:55 +08:00
|
|
|
dest[alpha] = MIN (src1[alpha], src2[alpha]);
|
1998-12-16 19:23:30 +08:00
|
|
|
|
2000-12-29 00:19:55 +08:00
|
|
|
src1 += bytes1;
|
|
|
|
src2 += bytes2;
|
|
|
|
dest += bytes2;
|
|
|
|
}
|
1998-12-16 19:23:30 +08:00
|
|
|
}
|
|
|
|
else if (has_alpha2)
|
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
dest[b] = INT_MULT(src1[b], src2[b], tmp);
|
1998-12-16 19:23:30 +08:00
|
|
|
|
2000-12-29 00:19:55 +08:00
|
|
|
dest[alpha] = src2[alpha];
|
1998-12-16 19:23:30 +08:00
|
|
|
|
2000-12-29 00:19:55 +08:00
|
|
|
src1 += bytes1;
|
|
|
|
src2 += bytes2;
|
|
|
|
dest += bytes2;
|
|
|
|
}
|
1998-12-16 19:23:30 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
dest[b] = INT_MULT(src1[b], src2[b], tmp);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-12-29 00:19:55 +08:00
|
|
|
src1 += bytes1;
|
|
|
|
src2 += bytes2;
|
|
|
|
dest += bytes2;
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-06-09 12:04:43 +08:00
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
divide_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
gint length,
|
|
|
|
gint bytes1,
|
|
|
|
gint bytes2,
|
|
|
|
gint has_alpha1,
|
|
|
|
gint has_alpha2)
|
1998-06-09 12:04:43 +08:00
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
gint alpha, b, result;
|
1998-06-09 12:04:43 +08:00
|
|
|
|
2000-01-26 07:06:12 +08:00
|
|
|
alpha = (has_alpha1 || has_alpha2) ? MAX (bytes1, bytes2) - 1 : bytes1;
|
1998-06-09 12:04:43 +08:00
|
|
|
|
|
|
|
while (length --)
|
|
|
|
{
|
2000-01-26 07:06:12 +08:00
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
{
|
|
|
|
result = ((src1[b] * 256) / (1+src2[b]));
|
|
|
|
dest[b] = MIN (result, 255);
|
|
|
|
}
|
1998-06-09 12:04:43 +08:00
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
if (has_alpha1 && has_alpha2)
|
1998-06-09 12:04:43 +08:00
|
|
|
dest[alpha] = MIN (src1[alpha], src2[alpha]);
|
1998-09-15 09:53:40 +08:00
|
|
|
else if (has_alpha2)
|
1998-06-09 12:04:43 +08:00
|
|
|
dest[alpha] = src2[alpha];
|
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
src1 += bytes1;
|
|
|
|
src2 += bytes2;
|
|
|
|
dest += bytes2;
|
1998-06-09 12:04:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-02-11 05:14:54 +08:00
|
|
|
MMX_PIXEL_OP_3A_1A(screen)
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
screen_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
gint length,
|
|
|
|
gint bytes1,
|
|
|
|
gint bytes2,
|
|
|
|
gint has_alpha1,
|
|
|
|
gint has_alpha2)
|
|
|
|
{
|
|
|
|
gint alpha, b;
|
|
|
|
gint tmp;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2001-02-11 05:14:54 +08:00
|
|
|
USE_MMX_PIXEL_OP_3A_1A(screen)
|
|
|
|
|
2000-01-26 07:06:12 +08:00
|
|
|
alpha = (has_alpha1 || has_alpha2) ? MAX (bytes1, bytes2) - 1 : bytes1;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
for (b = 0; b < alpha; b++)
|
1998-12-16 19:23:30 +08:00
|
|
|
dest[b] = 255 - INT_MULT((255 - src1[b]), (255 - src2[b]), tmp);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
if (has_alpha1 && has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
dest[alpha] = MIN (src1[alpha], src2[alpha]);
|
1998-09-15 09:53:40 +08:00
|
|
|
else if (has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
dest[alpha] = src2[alpha];
|
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
src1 += bytes1;
|
|
|
|
src2 += bytes2;
|
|
|
|
dest += bytes2;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-02-11 05:14:54 +08:00
|
|
|
MMX_PIXEL_OP_3A_1A(overlay)
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
overlay_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
gint length,
|
|
|
|
gint bytes1,
|
|
|
|
gint bytes2,
|
|
|
|
gint has_alpha1,
|
|
|
|
gint has_alpha2)
|
|
|
|
{
|
|
|
|
gint alpha, b;
|
|
|
|
gint tmp;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-01-26 07:06:12 +08:00
|
|
|
alpha = (has_alpha1 || has_alpha2) ? MAX (bytes1, bytes2) - 1 : bytes1;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
while (length --)
|
|
|
|
{
|
1999-07-29 18:40:42 +08:00
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
{
|
|
|
|
dest[b] = INT_MULT(src1[b], src1[b] + INT_MULT(2 * src2[b],
|
|
|
|
255 - src1[b],
|
|
|
|
tmp), tmp);
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
if (has_alpha1 && has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
dest[alpha] = MIN (src1[alpha], src2[alpha]);
|
1998-09-15 09:53:40 +08:00
|
|
|
else if (has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
dest[alpha] = src2[alpha];
|
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
src1 += bytes1;
|
|
|
|
src2 += bytes2;
|
|
|
|
dest += bytes2;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-01-09 10:45:27 +08:00
|
|
|
|
|
|
|
void
|
|
|
|
dodge_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
gint length,
|
|
|
|
gint b1,
|
|
|
|
gint b2,
|
|
|
|
gint ha1,
|
|
|
|
gint ha2)
|
|
|
|
{
|
|
|
|
gint alpha, b;
|
|
|
|
int tmp1;
|
|
|
|
|
|
|
|
alpha = (ha1 || ha2) ? MAX (b1, b2) - 1 : b1;
|
|
|
|
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
{
|
|
|
|
tmp1 = src1[b] << 8;
|
|
|
|
tmp1 /= 256 - src2[b];
|
|
|
|
dest[b] = (guchar) CLAMP (tmp1, 0, 255);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ha1 && ha2)
|
|
|
|
dest[alpha] = MIN (src1[alpha], src2[alpha]);
|
|
|
|
else if (ha2)
|
|
|
|
dest[alpha] = src2[alpha];
|
|
|
|
|
|
|
|
src1 += b1;
|
|
|
|
src2 += b2;
|
|
|
|
dest += b2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
burn_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
gint length,
|
|
|
|
gint b1,
|
|
|
|
gint b2,
|
|
|
|
gint ha1,
|
|
|
|
gint ha2)
|
|
|
|
{
|
|
|
|
gint alpha, b;
|
|
|
|
gint tmp1;
|
|
|
|
|
|
|
|
alpha = (ha1 || ha2) ? MAX (b1, b2) - 1 : b1;
|
|
|
|
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
{
|
|
|
|
tmp1 = (255 - src1[b]) << 8;
|
|
|
|
tmp1 /= src2[b] + 1;
|
|
|
|
dest[b] = (guchar) CLAMP (255 - tmp1, 0, 255);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ha1 && ha2)
|
|
|
|
dest[alpha] = MIN (src1[alpha], src2[alpha]);
|
|
|
|
else if (ha2)
|
|
|
|
dest[alpha] = src2[alpha];
|
|
|
|
|
|
|
|
src1 += b1;
|
|
|
|
src2 += b2;
|
|
|
|
dest += b2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
hardlight_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
gint length,
|
|
|
|
gint b1,
|
|
|
|
gint b2,
|
|
|
|
gint ha1,
|
|
|
|
gint ha2)
|
|
|
|
{
|
|
|
|
gint alpha, b;
|
|
|
|
gint tmp1;
|
|
|
|
|
|
|
|
alpha = (ha1 || ha2) ? MAX (b1, b2) - 1 : b1;
|
|
|
|
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
{
|
|
|
|
if (src2[b] > 128) {
|
|
|
|
tmp1 = ((gint)255 - src1[b]) * ((gint)255 - ((src2[b] - 128) << 1));
|
|
|
|
dest[b] = (guchar)CLAMP(255 - (tmp1 >> 8), 0, 255);
|
|
|
|
} else {
|
|
|
|
tmp1 = (gint)src1[b] * ((gint)src2[b] << 1);
|
|
|
|
dest[b] = (guchar)CLAMP(tmp1 >> 8, 0, 255);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ha1 && ha2)
|
|
|
|
dest[alpha] = MIN (src1[alpha], src2[alpha]);
|
|
|
|
else if (ha2)
|
|
|
|
dest[alpha] = src2[alpha];
|
|
|
|
|
|
|
|
src1 += b1;
|
|
|
|
src2 += b2;
|
|
|
|
dest += b2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-02-11 05:14:54 +08:00
|
|
|
MMX_PIXEL_OP_3A_1A(add)
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
add_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
gint length,
|
|
|
|
gint bytes1,
|
|
|
|
gint bytes2,
|
|
|
|
gint has_alpha1,
|
|
|
|
gint has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
gint alpha, b;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2001-02-11 05:14:54 +08:00
|
|
|
USE_MMX_PIXEL_OP_3A_1A(add)
|
|
|
|
|
2000-01-26 07:06:12 +08:00
|
|
|
alpha = (has_alpha1 || has_alpha2) ? MAX (bytes1, bytes2) - 1 : bytes1;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
{
|
2000-11-05 21:58:17 +08:00
|
|
|
/* TODO: wouldn't it be better use a 1 dimensional lut ie. add_lut[src1+src2]; */
|
|
|
|
dest[b] = add_lut[(src1[b])] [(src2[b])];
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
if (has_alpha1 && has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
dest[alpha] = MIN (src1[alpha], src2[alpha]);
|
1998-09-15 09:53:40 +08:00
|
|
|
else if (has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
dest[alpha] = src2[alpha];
|
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
src1 += bytes1;
|
|
|
|
src2 += bytes2;
|
|
|
|
dest += bytes2;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-02-11 05:14:54 +08:00
|
|
|
MMX_PIXEL_OP_3A_1A(substract)
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
subtract_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
gint length,
|
|
|
|
gint bytes1,
|
|
|
|
gint bytes2,
|
|
|
|
gint has_alpha1,
|
|
|
|
gint has_alpha2)
|
|
|
|
{
|
|
|
|
gint alpha, b;
|
|
|
|
gint diff;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2001-02-11 05:14:54 +08:00
|
|
|
USE_MMX_PIXEL_OP_3A_1A(substract)
|
|
|
|
|
2000-01-26 07:06:12 +08:00
|
|
|
alpha = (has_alpha1 || has_alpha2) ? MAX (bytes1, bytes2) - 1 : bytes1;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
{
|
|
|
|
diff = src1[b] - src2[b];
|
|
|
|
dest[b] = (diff < 0) ? 0 : diff;
|
|
|
|
}
|
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
if (has_alpha1 && has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
dest[alpha] = MIN (src1[alpha], src2[alpha]);
|
1998-09-15 09:53:40 +08:00
|
|
|
else if (has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
dest[alpha] = src2[alpha];
|
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
src1 += bytes1;
|
|
|
|
src2 += bytes2;
|
|
|
|
dest += bytes2;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-02-11 05:14:54 +08:00
|
|
|
MMX_PIXEL_OP_3A_1A(difference)
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
difference_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
gint length,
|
|
|
|
gint bytes1,
|
|
|
|
gint bytes2,
|
|
|
|
gint has_alpha1,
|
|
|
|
gint has_alpha2)
|
|
|
|
{
|
|
|
|
gint alpha, b;
|
|
|
|
gint diff;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2001-02-11 05:14:54 +08:00
|
|
|
USE_MMX_PIXEL_OP_3A_1A(difference)
|
|
|
|
|
2000-01-26 07:06:12 +08:00
|
|
|
alpha = (has_alpha1 || has_alpha2) ? MAX (bytes1, bytes2) - 1 : bytes1;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
{
|
|
|
|
diff = src1[b] - src2[b];
|
|
|
|
dest[b] = (diff < 0) ? -diff : diff;
|
|
|
|
}
|
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
if (has_alpha1 && has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
dest[alpha] = MIN (src1[alpha], src2[alpha]);
|
1998-09-15 09:53:40 +08:00
|
|
|
else if (has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
dest[alpha] = src2[alpha];
|
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
src1 += bytes1;
|
|
|
|
src2 += bytes2;
|
|
|
|
dest += bytes2;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
dissolve_pixels (const guchar *src,
|
|
|
|
guchar *dest,
|
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint opacity,
|
|
|
|
gint length,
|
|
|
|
gint sb,
|
|
|
|
gint db,
|
|
|
|
gint has_alpha)
|
|
|
|
{
|
|
|
|
gint alpha, b;
|
|
|
|
gint rand_val;
|
1999-03-19 11:19:18 +08:00
|
|
|
|
1999-05-01 05:11:27 +08:00
|
|
|
#if defined(ENABLE_MP) && defined(__GLIBC__)
|
|
|
|
/* The glibc 2.1 documentation recommends using the SVID random functions
|
|
|
|
* instead of rand_r
|
|
|
|
*/
|
|
|
|
struct drand48_data seed;
|
2000-12-29 00:19:55 +08:00
|
|
|
glong temp_val;
|
1999-05-01 05:11:27 +08:00
|
|
|
|
|
|
|
srand48_r (random_table[y % RANDOM_TABLE_SIZE], &seed);
|
|
|
|
for (b = 0; b < x; b++)
|
|
|
|
lrand48_r (&seed, &temp_val);
|
|
|
|
#elif defined(ENABLE_MP) && !defined(__GLIBC__)
|
|
|
|
/* If we are running with multiple threads rand_r give _much_ better
|
|
|
|
* performance than rand
|
|
|
|
*/
|
2000-12-29 00:19:55 +08:00
|
|
|
guint seed;
|
1999-05-01 05:11:27 +08:00
|
|
|
seed = random_table[y % RANDOM_TABLE_SIZE];
|
1999-02-01 16:22:18 +08:00
|
|
|
for (b = 0; b < x; b++)
|
1999-05-01 05:11:27 +08:00
|
|
|
rand_r (&seed);
|
1999-02-01 16:22:18 +08:00
|
|
|
#else
|
1999-05-01 05:11:27 +08:00
|
|
|
/* Set up the random number generator */
|
|
|
|
srand (random_table[y % RANDOM_TABLE_SIZE]);
|
1997-11-25 06:05:25 +08:00
|
|
|
for (b = 0; b < x; b++)
|
|
|
|
rand ();
|
1999-02-01 16:22:18 +08:00
|
|
|
#endif
|
1999-05-01 05:11:27 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
alpha = db - 1;
|
|
|
|
|
1999-05-01 05:11:27 +08:00
|
|
|
while (length--)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
/* preserve the intensity values */
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
dest[b] = src[b];
|
|
|
|
|
|
|
|
/* dissolve if random value is > opacity */
|
1999-05-01 05:11:27 +08:00
|
|
|
#if defined(ENABLE_MP) && defined(__GLIBC__)
|
|
|
|
lrand48_r (&seed, &temp_val);
|
|
|
|
rand_val = temp_val & 0xff;
|
|
|
|
#elif defined(ENABLE_MP) && !defined(__GLIBC__)
|
|
|
|
rand_val = (rand_r (&seed) & 0xff);
|
1999-02-01 16:22:18 +08:00
|
|
|
#else
|
1999-05-01 05:11:27 +08:00
|
|
|
rand_val = (rand () & 0xff);
|
1999-02-01 16:22:18 +08:00
|
|
|
#endif
|
1997-11-25 06:05:25 +08:00
|
|
|
if (has_alpha)
|
1999-01-23 07:46:44 +08:00
|
|
|
dest[alpha] = (rand_val > src[alpha]) ? 0 : src[alpha];
|
1997-11-25 06:05:25 +08:00
|
|
|
else
|
1998-01-25 09:24:46 +08:00
|
|
|
dest[alpha] = (rand_val > opacity) ? 0 : OPAQUE_OPACITY;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
dest += db;
|
1999-05-01 05:11:27 +08:00
|
|
|
src += sb;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1997-12-08 09:13:10 +08:00
|
|
|
void
|
2001-01-24 23:36:55 +08:00
|
|
|
replace_pixels (guchar *src1,
|
|
|
|
guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
guchar *mask,
|
|
|
|
gint length,
|
|
|
|
gint opacity,
|
|
|
|
gboolean *affect,
|
|
|
|
gint bytes1,
|
|
|
|
gint bytes2)
|
2000-12-29 00:19:55 +08:00
|
|
|
{
|
|
|
|
gint alpha;
|
|
|
|
gint b;
|
|
|
|
gdouble a_val, a_recip, mask_val;
|
|
|
|
gdouble norm_opacity;
|
|
|
|
gint s1_a, s2_a;
|
|
|
|
gint new_val;
|
1997-12-08 09:13:10 +08:00
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
if (bytes1 != bytes2)
|
1997-12-08 09:13:10 +08:00
|
|
|
{
|
1999-06-06 07:41:45 +08:00
|
|
|
g_warning ("replace_pixels only works on commensurate pixel regions");
|
1997-12-08 09:13:10 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
alpha = bytes1 - 1;
|
2000-02-17 06:36:46 +08:00
|
|
|
norm_opacity = opacity * (1.0 / 65536.0);
|
1997-12-08 09:13:10 +08:00
|
|
|
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
mask_val = mask[0] * norm_opacity;
|
|
|
|
/* calculate new alpha first. */
|
|
|
|
s1_a = src1[alpha];
|
|
|
|
s2_a = src2[alpha];
|
|
|
|
a_val = s1_a + mask_val * (s2_a - s1_a);
|
2001-01-24 23:36:55 +08:00
|
|
|
|
2000-02-17 06:36:46 +08:00
|
|
|
if (a_val == 0) /* In any case, write out versions of the blending function */
|
|
|
|
/* that result when combinations of s1_a, s2_a, and */
|
|
|
|
/* mask_val --> 0 (or mask_val -->1) */
|
|
|
|
{
|
|
|
|
/* Case 1: s1_a, s2_a, AND mask_val all approach 0+: */
|
|
|
|
/* Case 2: s1_a AND s2_a both approach 0+, regardless of mask_val: */
|
|
|
|
|
2001-01-24 23:36:55 +08:00
|
|
|
if (s1_a + s2_a == 0.0)
|
2000-02-17 06:36:46 +08:00
|
|
|
{
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
{
|
2001-01-24 23:36:55 +08:00
|
|
|
new_val = 0.5 + (gdouble) src1[b] +
|
|
|
|
mask_val * ((gdouble) src2[b] - (gdouble) src1[b]);
|
|
|
|
|
2000-02-17 06:36:46 +08:00
|
|
|
dest[b] = affect[b] ? MIN (new_val, 255) : src1[b];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Case 3: mask_val AND s1_a both approach 0+, regardless of s2_a */
|
2001-01-24 23:36:55 +08:00
|
|
|
else if (s1_a + mask_val == 0.0)
|
2000-02-17 06:36:46 +08:00
|
|
|
{
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
{
|
|
|
|
dest[b] = src1[b];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Case 4: mask_val -->1 AND s2_a -->0, regardless of s1_a */
|
2001-01-24 23:36:55 +08:00
|
|
|
else if (1.0 - mask_val + s2_a == 0.0)
|
2000-02-17 06:36:46 +08:00
|
|
|
{
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
{
|
|
|
|
dest[b] = affect[b] ? src2[b] : src1[b];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1997-12-08 09:13:10 +08:00
|
|
|
else
|
|
|
|
{
|
2000-02-17 06:36:46 +08:00
|
|
|
a_recip = 1.0 / a_val;
|
|
|
|
/* possible optimization: fold a_recip into s1_a and s2_a */
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
{
|
|
|
|
new_val = 0.5 + a_recip * (src1[b] * s1_a + mask_val *
|
|
|
|
(src2[b] * s2_a - src1[b] * s1_a));
|
|
|
|
dest[b] = affect[b] ? MIN (new_val, 255) : src1[b];
|
|
|
|
}
|
|
|
|
}
|
2001-01-24 23:36:55 +08:00
|
|
|
|
1997-12-08 09:13:10 +08:00
|
|
|
dest[alpha] = affect[alpha] ? a_val + 0.5: s1_a;
|
1998-09-15 09:53:40 +08:00
|
|
|
src1 += bytes1;
|
|
|
|
src2 += bytes2;
|
|
|
|
dest += bytes2;
|
1997-12-08 09:13:10 +08:00
|
|
|
mask++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
swap_pixels (guchar *src,
|
|
|
|
guchar *dest,
|
|
|
|
gint length)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
while (length--)
|
|
|
|
{
|
|
|
|
*src = *src ^ *dest;
|
|
|
|
*dest = *dest ^ *src;
|
|
|
|
*src = *src ^ *dest;
|
|
|
|
src++;
|
|
|
|
dest++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
scale_pixels (const guchar *src,
|
|
|
|
guchar *dest,
|
|
|
|
gint length,
|
|
|
|
gint scale)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
gint tmp;
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
while (length --)
|
2000-12-29 00:19:55 +08:00
|
|
|
{
|
|
|
|
*dest++ = (guchar) INT_MULT (*src, scale, tmp);
|
|
|
|
src++;
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
add_alpha_pixels (const guchar *src,
|
|
|
|
guchar *dest,
|
|
|
|
gint length,
|
|
|
|
gint bytes)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
gint alpha, b;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
alpha = bytes + 1;
|
2001-01-24 23:36:55 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
for (b = 0; b < bytes; b++)
|
|
|
|
dest[b] = src[b];
|
|
|
|
|
1998-01-25 09:24:46 +08:00
|
|
|
dest[b] = OPAQUE_OPACITY;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
src += bytes;
|
|
|
|
dest += alpha;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
flatten_pixels (const guchar *src,
|
|
|
|
guchar *dest,
|
|
|
|
const guchar *bg,
|
|
|
|
gint length,
|
|
|
|
gint bytes)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
gint alpha, b;
|
|
|
|
gint t1, t2;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
alpha = bytes - 1;
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
for (b = 0; b < alpha; b++)
|
2001-01-24 23:36:55 +08:00
|
|
|
dest[b] = INT_MULT (src[b], src[alpha], t1) +
|
|
|
|
INT_MULT (bg[b], (255 - src[alpha]), t2);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
src += bytes;
|
|
|
|
dest += alpha;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
gray_to_rgb_pixels (const guchar *src,
|
|
|
|
guchar *dest,
|
|
|
|
gint length,
|
|
|
|
gint bytes)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2001-01-24 23:36:55 +08:00
|
|
|
gint b;
|
|
|
|
gint dest_bytes;
|
|
|
|
gboolean has_alpha;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2001-01-24 23:36:55 +08:00
|
|
|
has_alpha = (bytes == 2) ? TRUE : FALSE;
|
1997-11-25 06:05:25 +08:00
|
|
|
dest_bytes = (has_alpha) ? 4 : 3;
|
|
|
|
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
for (b = 0; b < bytes; b++)
|
|
|
|
dest[b] = src[0];
|
|
|
|
|
|
|
|
if (has_alpha)
|
|
|
|
dest[3] = src[1];
|
|
|
|
|
|
|
|
src += bytes;
|
|
|
|
dest += dest_bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
apply_mask_to_alpha_channel (guchar *src,
|
|
|
|
const guchar *mask,
|
|
|
|
gint opacity,
|
|
|
|
gint length,
|
|
|
|
gint bytes)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
glong tmp;
|
|
|
|
|
1998-12-16 19:23:30 +08:00
|
|
|
src += bytes - 1;
|
2001-01-24 23:36:55 +08:00
|
|
|
|
1998-12-16 19:23:30 +08:00
|
|
|
if (opacity == 255)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
*src = INT_MULT(*src, *mask, tmp);
|
|
|
|
mask++;
|
|
|
|
src += bytes;
|
|
|
|
}
|
1998-12-16 19:23:30 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
*src = INT_MULT3(*src, *mask, opacity, tmp);
|
|
|
|
mask++;
|
|
|
|
src += bytes;
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
combine_mask_and_alpha_channel (guchar *src,
|
|
|
|
const guchar *mask,
|
|
|
|
gint opacity,
|
|
|
|
gint length,
|
|
|
|
gint bytes)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
gint mask_val;
|
|
|
|
gint alpha;
|
|
|
|
gint tmp;
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
alpha = bytes - 1;
|
1998-12-16 19:23:30 +08:00
|
|
|
src += alpha;
|
|
|
|
|
|
|
|
if (opacity != 255)
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
mask_val = INT_MULT(*mask, opacity, tmp);
|
|
|
|
mask++;
|
|
|
|
*src = *src + INT_MULT((255 - *src) , mask_val, tmp);
|
|
|
|
src += bytes;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
while (length --)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1998-12-16 19:23:30 +08:00
|
|
|
*src = *src + INT_MULT((255 - *src) , *mask, tmp);
|
1997-11-25 06:05:25 +08:00
|
|
|
src += bytes;
|
1998-12-16 19:23:30 +08:00
|
|
|
mask++;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
copy_gray_to_inten_a_pixels (const guchar *src,
|
|
|
|
guchar *dest,
|
|
|
|
gint length,
|
|
|
|
gint bytes)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
gint b;
|
|
|
|
gint alpha;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
alpha = bytes - 1;
|
2001-01-24 23:36:55 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
dest[b] = *src;
|
1998-01-25 09:24:46 +08:00
|
|
|
dest[b] = OPAQUE_OPACITY;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
src ++;
|
|
|
|
dest += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2000-12-31 22:58:08 +08:00
|
|
|
initial_channel_pixels (const guchar *src,
|
|
|
|
guchar *dest,
|
|
|
|
gint length,
|
|
|
|
gint bytes)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint alpha, b;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
alpha = bytes - 1;
|
2001-01-24 23:36:55 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
dest[b] = src[0];
|
|
|
|
|
1998-01-25 09:24:46 +08:00
|
|
|
dest[alpha] = OPAQUE_OPACITY;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
dest += bytes;
|
|
|
|
src ++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2000-12-31 22:58:08 +08:00
|
|
|
initial_indexed_pixels (const guchar *src,
|
|
|
|
guchar *dest,
|
|
|
|
const guchar *cmap,
|
|
|
|
gint length)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint col_index;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* This function assumes always that we're mapping from
|
|
|
|
* an RGB colormap to an RGBA image...
|
|
|
|
*/
|
|
|
|
while (length--)
|
|
|
|
{
|
|
|
|
col_index = *src++ * 3;
|
|
|
|
*dest++ = cmap[col_index++];
|
|
|
|
*dest++ = cmap[col_index++];
|
|
|
|
*dest++ = cmap[col_index++];
|
1998-01-25 09:24:46 +08:00
|
|
|
*dest++ = OPAQUE_OPACITY;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2000-12-31 22:58:08 +08:00
|
|
|
initial_indexed_a_pixels (const guchar *src,
|
|
|
|
guchar *dest,
|
|
|
|
const guchar *mask,
|
|
|
|
const guchar *cmap,
|
|
|
|
gint opacity,
|
|
|
|
gint length)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint col_index;
|
|
|
|
guchar new_alpha;
|
|
|
|
const guchar *m;
|
|
|
|
glong tmp;
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
if (mask)
|
|
|
|
m = mask;
|
|
|
|
else
|
|
|
|
m = &no_mask;
|
|
|
|
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
col_index = *src++ * 3;
|
1998-12-16 23:48:43 +08:00
|
|
|
new_alpha = INT_MULT3(*src, *m, opacity, tmp);
|
|
|
|
src++;
|
1997-11-25 06:05:25 +08:00
|
|
|
*dest++ = cmap[col_index++];
|
|
|
|
*dest++ = cmap[col_index++];
|
|
|
|
*dest++ = cmap[col_index++];
|
|
|
|
/* Set the alpha channel */
|
1998-01-25 09:24:46 +08:00
|
|
|
*dest++ = (new_alpha > 127) ? OPAQUE_OPACITY : TRANSPARENT_OPACITY;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
if (mask)
|
|
|
|
m++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2000-12-31 22:58:08 +08:00
|
|
|
initial_inten_pixels (const guchar *src,
|
|
|
|
guchar *dest,
|
|
|
|
const guchar *mask,
|
|
|
|
gint opacity,
|
|
|
|
const gint *affect,
|
|
|
|
gint length,
|
|
|
|
gint bytes)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2001-01-24 23:36:55 +08:00
|
|
|
gint b;
|
|
|
|
gint tmp;
|
|
|
|
gint l;
|
|
|
|
const guchar *m;
|
|
|
|
guchar *destp;
|
2000-12-31 22:58:08 +08:00
|
|
|
const guchar *srcp;
|
2001-01-24 23:36:55 +08:00
|
|
|
const gint dest_bytes = bytes + 1;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
if (mask)
|
2000-06-18 01:37:36 +08:00
|
|
|
{
|
1997-11-25 06:05:25 +08:00
|
|
|
m = mask;
|
2000-06-18 01:37:36 +08:00
|
|
|
|
|
|
|
/* This function assumes the source has no alpha channel and
|
|
|
|
* the destination has an alpha channel. So dest_bytes = bytes + 1
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (bytes == 3 && affect[0] && affect[1] && affect[2])
|
1998-12-16 19:23:30 +08:00
|
|
|
{
|
2000-06-18 01:37:36 +08:00
|
|
|
if (!affect[bytes])
|
|
|
|
opacity = 0;
|
2001-01-24 23:36:55 +08:00
|
|
|
|
2000-06-18 01:37:36 +08:00
|
|
|
destp = dest + bytes;
|
2001-01-24 23:36:55 +08:00
|
|
|
|
|
|
|
if (opacity != 0)
|
|
|
|
while(length--)
|
|
|
|
{
|
|
|
|
dest[0] = src[0];
|
|
|
|
dest[1] = src[1];
|
|
|
|
dest[2] = src[2];
|
|
|
|
dest[3] = INT_MULT(opacity, *m, tmp);
|
|
|
|
src += bytes;
|
|
|
|
dest += dest_bytes;
|
|
|
|
m++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
while(length--)
|
|
|
|
{
|
|
|
|
dest[0] = src[0];
|
|
|
|
dest[1] = src[1];
|
|
|
|
dest[2] = src[2];
|
|
|
|
dest[3] = opacity;
|
|
|
|
src += bytes;
|
|
|
|
dest += dest_bytes;
|
|
|
|
}
|
2000-06-18 01:37:36 +08:00
|
|
|
return;
|
1998-12-16 19:23:30 +08:00
|
|
|
}
|
2001-01-24 23:36:55 +08:00
|
|
|
|
2000-06-18 01:37:36 +08:00
|
|
|
for (b =0; b < bytes; b++)
|
|
|
|
{
|
|
|
|
destp = dest + b;
|
|
|
|
srcp = src + b;
|
|
|
|
l = length;
|
2001-01-24 23:36:55 +08:00
|
|
|
|
2000-06-18 01:37:36 +08:00
|
|
|
if (affect[b])
|
|
|
|
while(l--)
|
|
|
|
{
|
|
|
|
*destp = *srcp;
|
|
|
|
srcp += bytes;
|
|
|
|
destp += dest_bytes;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
while(l--)
|
|
|
|
{
|
|
|
|
*destp = 0;
|
|
|
|
destp += dest_bytes;
|
|
|
|
}
|
|
|
|
}
|
2001-01-24 23:36:55 +08:00
|
|
|
|
2000-06-18 01:37:36 +08:00
|
|
|
/* fill the alpha channel */
|
|
|
|
if (!affect[bytes])
|
|
|
|
opacity = 0;
|
2001-01-24 23:36:55 +08:00
|
|
|
|
2000-06-18 01:37:36 +08:00
|
|
|
destp = dest + bytes;
|
2001-01-24 23:36:55 +08:00
|
|
|
|
|
|
|
if (opacity != 0)
|
|
|
|
while (length--)
|
|
|
|
{
|
|
|
|
*destp = INT_MULT(opacity , *m, tmp);
|
|
|
|
destp += dest_bytes;
|
|
|
|
m++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
while (length--)
|
|
|
|
{
|
|
|
|
*destp = opacity;
|
|
|
|
destp += dest_bytes;
|
|
|
|
}
|
1998-12-16 19:23:30 +08:00
|
|
|
}
|
2001-01-24 23:36:55 +08:00
|
|
|
|
|
|
|
/* If no mask */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m = &no_mask;
|
|
|
|
|
|
|
|
/* This function assumes the source has no alpha channel and
|
|
|
|
* the destination has an alpha channel. So dest_bytes = bytes + 1
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (bytes == 3 && affect[0] && affect[1] && affect[2])
|
|
|
|
{
|
|
|
|
if (!affect[bytes])
|
|
|
|
opacity = 0;
|
|
|
|
|
|
|
|
destp = dest + bytes;
|
|
|
|
|
|
|
|
while(length--)
|
|
|
|
{
|
|
|
|
dest[0] = src[0];
|
|
|
|
dest[1] = src[1];
|
|
|
|
dest[2] = src[2];
|
|
|
|
dest[3] = opacity;
|
|
|
|
src += bytes;
|
|
|
|
dest += dest_bytes;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (b =0; b < bytes; b++)
|
|
|
|
{
|
|
|
|
destp = dest + b;
|
|
|
|
srcp = src + b;
|
|
|
|
l = length;
|
|
|
|
|
|
|
|
if (affect[b])
|
|
|
|
while(l--)
|
|
|
|
{
|
|
|
|
*destp = *srcp;
|
|
|
|
srcp += bytes;
|
|
|
|
destp += dest_bytes;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
while(l--)
|
|
|
|
{
|
|
|
|
*destp = 0;
|
|
|
|
destp += dest_bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* fill the alpha channel */
|
|
|
|
if (!affect[bytes])
|
|
|
|
opacity = 0;
|
|
|
|
|
|
|
|
destp = dest + bytes;
|
|
|
|
|
|
|
|
while (length--)
|
|
|
|
{
|
|
|
|
*destp = opacity;
|
|
|
|
destp += dest_bytes;
|
|
|
|
}
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2001-01-24 23:36:55 +08:00
|
|
|
initial_inten_a_pixels (const guchar *src,
|
|
|
|
guchar *dest,
|
|
|
|
const guchar *mask,
|
|
|
|
gint opacity,
|
|
|
|
const gboolean *affect,
|
|
|
|
gint length,
|
|
|
|
gint bytes)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint alpha, b;
|
|
|
|
const guchar *m;
|
|
|
|
glong tmp;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
alpha = bytes - 1;
|
|
|
|
if (mask)
|
|
|
|
{
|
|
|
|
m = mask;
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
dest[b] = src[b] * affect[b];
|
|
|
|
|
|
|
|
/* Set the alpha channel */
|
1998-12-16 23:48:43 +08:00
|
|
|
dest[alpha] = affect [alpha] ? INT_MULT3(opacity, src[alpha], *m, tmp)
|
|
|
|
: 0;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
m++;
|
|
|
|
|
|
|
|
dest += bytes;
|
|
|
|
src += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
dest[b] = src[b] * affect[b];
|
|
|
|
|
|
|
|
/* Set the alpha channel */
|
1998-12-16 19:23:30 +08:00
|
|
|
dest[alpha] = affect [alpha] ? INT_MULT(opacity , src[alpha], tmp) : 0;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
dest += bytes;
|
|
|
|
src += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2001-01-24 23:36:55 +08:00
|
|
|
combine_indexed_and_indexed_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
const guchar *mask,
|
|
|
|
gint opacity,
|
|
|
|
const gboolean *affect,
|
|
|
|
gint length,
|
|
|
|
gint bytes)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint b;
|
|
|
|
guchar new_alpha;
|
|
|
|
const guchar *m;
|
|
|
|
gint tmp;
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
if (mask)
|
|
|
|
{
|
|
|
|
m = mask;
|
|
|
|
while (length --)
|
|
|
|
{
|
1998-12-16 19:23:30 +08:00
|
|
|
new_alpha = INT_MULT(*m , opacity, tmp);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
for (b = 0; b < bytes; b++)
|
|
|
|
dest[b] = (affect[b] && new_alpha > 127) ? src2[b] : src1[b];
|
|
|
|
|
|
|
|
m++;
|
|
|
|
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += bytes;
|
|
|
|
dest += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
new_alpha = opacity;
|
|
|
|
|
|
|
|
for (b = 0; b < bytes; b++)
|
|
|
|
dest[b] = (affect[b] && new_alpha > 127) ? src2[b] : src1[b];
|
|
|
|
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += bytes;
|
|
|
|
dest += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2001-01-24 23:36:55 +08:00
|
|
|
combine_indexed_and_indexed_a_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
const guchar *mask,
|
|
|
|
gint opacity,
|
|
|
|
const gboolean *affect,
|
|
|
|
gint length,
|
|
|
|
gint bytes)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2001-01-24 23:36:55 +08:00
|
|
|
gint b, alpha;
|
2000-12-31 22:58:08 +08:00
|
|
|
guchar new_alpha;
|
2001-01-24 23:36:55 +08:00
|
|
|
gint src2_bytes;
|
|
|
|
glong tmp;
|
|
|
|
const guchar *m;
|
2000-12-31 22:58:08 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
alpha = 1;
|
|
|
|
src2_bytes = 2;
|
|
|
|
|
|
|
|
if (mask)
|
|
|
|
{
|
|
|
|
m = mask;
|
|
|
|
while (length --)
|
|
|
|
{
|
1998-12-16 19:23:30 +08:00
|
|
|
new_alpha = INT_MULT3(src2[alpha], *m, opacity, tmp);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
for (b = 0; b < bytes; b++)
|
|
|
|
dest[b] = (affect[b] && new_alpha > 127) ? src2[b] : src1[b];
|
|
|
|
|
|
|
|
m++;
|
|
|
|
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += src2_bytes;
|
|
|
|
dest += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while (length --)
|
|
|
|
{
|
1998-12-16 19:23:30 +08:00
|
|
|
new_alpha = INT_MULT(src2[alpha], opacity, tmp);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
for (b = 0; b < bytes; b++)
|
|
|
|
dest[b] = (affect[b] && new_alpha > 127) ? src2[b] : src1[b];
|
|
|
|
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += src2_bytes;
|
|
|
|
dest += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2001-01-24 23:36:55 +08:00
|
|
|
combine_indexed_a_and_indexed_a_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
const guchar *mask,
|
|
|
|
gint opacity,
|
|
|
|
const gboolean *affect,
|
|
|
|
gint length,
|
|
|
|
gint bytes)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
const guchar * m;
|
2001-01-24 23:36:55 +08:00
|
|
|
gint b, alpha;
|
|
|
|
guchar new_alpha;
|
|
|
|
glong tmp;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
alpha = 1;
|
|
|
|
|
|
|
|
if (mask)
|
|
|
|
{
|
|
|
|
m = mask;
|
2001-01-24 23:36:55 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
while (length --)
|
|
|
|
{
|
1998-12-16 19:23:30 +08:00
|
|
|
new_alpha = INT_MULT3(src2[alpha], *m, opacity, tmp);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
dest[b] = (affect[b] && new_alpha > 127) ? src2[b] : src1[b];
|
|
|
|
|
2001-01-24 23:36:55 +08:00
|
|
|
dest[alpha] = (affect[alpha] && new_alpha > 127) ?
|
|
|
|
OPAQUE_OPACITY : src1[alpha];
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
m++;
|
|
|
|
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += bytes;
|
|
|
|
dest += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while (length --)
|
|
|
|
{
|
1998-12-16 19:23:30 +08:00
|
|
|
new_alpha = INT_MULT(src2[alpha], opacity, tmp);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
dest[b] = (affect[b] && new_alpha > 127) ? src2[b] : src1[b];
|
|
|
|
|
2001-01-24 23:36:55 +08:00
|
|
|
dest[alpha] = (affect[alpha] && new_alpha > 127) ?
|
|
|
|
OPAQUE_OPACITY : src1[alpha];
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += bytes;
|
|
|
|
dest += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2000-12-31 22:58:08 +08:00
|
|
|
combine_inten_a_and_indexed_a_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
const guchar *mask,
|
|
|
|
const guchar *cmap,
|
|
|
|
gint opacity,
|
|
|
|
gint length,
|
|
|
|
gint bytes)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2001-01-24 23:36:55 +08:00
|
|
|
gint b, alpha;
|
2000-12-31 22:58:08 +08:00
|
|
|
guchar new_alpha;
|
2001-01-24 23:36:55 +08:00
|
|
|
gint src2_bytes;
|
|
|
|
gint index;
|
|
|
|
glong tmp;
|
|
|
|
const guchar *m;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
alpha = 1;
|
|
|
|
src2_bytes = 2;
|
|
|
|
|
|
|
|
if (mask)
|
|
|
|
{
|
2001-01-24 23:36:55 +08:00
|
|
|
m = mask;
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
while (length --)
|
|
|
|
{
|
1998-12-16 19:23:30 +08:00
|
|
|
new_alpha = INT_MULT3(src2[alpha], *m, opacity, tmp);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
index = src2[0] * 3;
|
|
|
|
|
|
|
|
for (b = 0; b < bytes-1; b++)
|
|
|
|
dest[b] = (new_alpha > 127) ? cmap[index + b] : src1[b];
|
|
|
|
|
2001-01-24 23:36:55 +08:00
|
|
|
dest[b] = (new_alpha > 127) ? OPAQUE_OPACITY : src1[b];
|
|
|
|
/* alpha channel is opaque */
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
m++;
|
|
|
|
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += src2_bytes;
|
|
|
|
dest += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while (length --)
|
|
|
|
{
|
1998-12-16 19:23:30 +08:00
|
|
|
new_alpha = INT_MULT(src2[alpha], opacity, tmp);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
index = src2[0] * 3;
|
|
|
|
|
|
|
|
for (b = 0; b < bytes-1; b++)
|
|
|
|
dest[b] = (new_alpha > 127) ? cmap[index + b] : src1[b];
|
|
|
|
|
2001-01-24 23:36:55 +08:00
|
|
|
dest[b] = (new_alpha > 127) ? OPAQUE_OPACITY : src1[b];
|
|
|
|
/* alpha channel is opaque */
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* m++; /Per */
|
|
|
|
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += src2_bytes;
|
|
|
|
dest += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2001-01-24 23:36:55 +08:00
|
|
|
combine_inten_and_inten_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
const guchar *mask,
|
|
|
|
gint opacity,
|
|
|
|
const gboolean *affect,
|
|
|
|
gint length,
|
|
|
|
gint bytes)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
const guchar * m;
|
2001-01-24 23:36:55 +08:00
|
|
|
gint b;
|
|
|
|
guchar new_alpha;
|
|
|
|
gint tmp;
|
2000-12-31 22:58:08 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
if (mask)
|
|
|
|
{
|
|
|
|
m = mask;
|
|
|
|
while (length --)
|
|
|
|
{
|
1998-12-16 19:23:30 +08:00
|
|
|
new_alpha = INT_MULT(*m, opacity, tmp);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
for (b = 0; b < bytes; b++)
|
|
|
|
dest[b] = (affect[b]) ?
|
1998-12-16 19:23:30 +08:00
|
|
|
INT_BLEND(src2[b], src1[b], new_alpha, tmp) :
|
1997-11-25 06:05:25 +08:00
|
|
|
src1[b];
|
|
|
|
|
|
|
|
m++;
|
|
|
|
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += bytes;
|
|
|
|
dest += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
|
|
|
|
for (b = 0; b < bytes; b++)
|
|
|
|
dest[b] = (affect[b]) ?
|
1998-12-16 19:23:30 +08:00
|
|
|
INT_BLEND(src2[b], src1[b], opacity, tmp) :
|
1997-11-25 06:05:25 +08:00
|
|
|
src1[b];
|
|
|
|
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += bytes;
|
|
|
|
dest += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2001-01-24 23:36:55 +08:00
|
|
|
combine_inten_and_inten_a_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
const guchar *mask,
|
|
|
|
gint opacity,
|
|
|
|
const gboolean *affect,
|
|
|
|
gint length,
|
|
|
|
gint bytes)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2001-01-24 23:36:55 +08:00
|
|
|
gint alpha, b;
|
|
|
|
gint src2_bytes;
|
2000-12-31 22:58:08 +08:00
|
|
|
guchar new_alpha;
|
2001-01-24 23:36:55 +08:00
|
|
|
const guchar *m;
|
|
|
|
register glong t1;
|
2000-12-31 22:58:08 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
alpha = bytes;
|
|
|
|
src2_bytes = bytes + 1;
|
|
|
|
|
|
|
|
if (mask)
|
|
|
|
{
|
|
|
|
m = mask;
|
|
|
|
while (length --)
|
|
|
|
{
|
1998-12-16 23:48:43 +08:00
|
|
|
new_alpha = INT_MULT3(src2[alpha], *m, opacity, t1);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
for (b = 0; b < bytes; b++)
|
|
|
|
dest[b] = (affect[b]) ?
|
1998-12-16 19:23:30 +08:00
|
|
|
INT_BLEND(src2[b], src1[b], new_alpha, t1) :
|
|
|
|
src1[b];
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
m++;
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += src2_bytes;
|
|
|
|
dest += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1998-12-16 19:23:30 +08:00
|
|
|
if (bytes == 3 && affect[0] && affect[1] && affect[2])
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
new_alpha = INT_MULT(src2[alpha],opacity,t1);
|
|
|
|
dest[0] = INT_BLEND(src2[0] , src1[0] , new_alpha, t1);
|
|
|
|
dest[1] = INT_BLEND(src2[1] , src1[1] , new_alpha, t1);
|
|
|
|
dest[2] = INT_BLEND(src2[2] , src1[2] , new_alpha, t1);
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += src2_bytes;
|
|
|
|
dest += bytes;
|
|
|
|
}
|
1998-12-16 23:48:43 +08:00
|
|
|
else
|
|
|
|
while (length --)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1998-12-16 19:23:30 +08:00
|
|
|
new_alpha = INT_MULT(src2[alpha],opacity,t1);
|
1997-11-25 06:05:25 +08:00
|
|
|
for (b = 0; b < bytes; b++)
|
|
|
|
dest[b] = (affect[b]) ?
|
1998-12-16 19:23:30 +08:00
|
|
|
INT_BLEND(src2[b] , src1[b] , new_alpha, t1) :
|
1997-11-25 06:05:25 +08:00
|
|
|
src1[b];
|
|
|
|
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += src2_bytes;
|
|
|
|
dest += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-07-12 00:25:52 +08:00
|
|
|
/*orig #define alphify(src2_alpha,new_alpha) \
|
1997-11-25 06:05:25 +08:00
|
|
|
if (new_alpha == 0 || src2_alpha == 0) \
|
|
|
|
{ \
|
|
|
|
for (b = 0; b < alpha; b++) \
|
|
|
|
dest[b] = src1 [b]; \
|
|
|
|
} \
|
|
|
|
else if (src2_alpha == new_alpha){ \
|
|
|
|
for (b = 0; b < alpha; b++) \
|
|
|
|
dest [b] = affect [b] ? src2 [b] : src1 [b]; \
|
|
|
|
} else { \
|
|
|
|
ratio = (float) src2_alpha / new_alpha; \
|
|
|
|
compl_ratio = 1.0 - ratio; \
|
|
|
|
\
|
|
|
|
for (b = 0; b < alpha; b++) \
|
|
|
|
dest[b] = affect[b] ? \
|
2000-12-31 22:58:08 +08:00
|
|
|
(guchar) (src2[b] * ratio + src1[b] * compl_ratio + EPSILON) : src1[b]; \
|
1998-07-12 00:25:52 +08:00
|
|
|
}*/
|
|
|
|
|
|
|
|
/*shortened #define alphify(src2_alpha,new_alpha) \
|
|
|
|
if (src2_alpha != 0 && new_alpha != 0) \
|
|
|
|
{ \
|
|
|
|
if (src2_alpha == new_alpha){ \
|
|
|
|
for (b = 0; b < alpha; b++) \
|
|
|
|
dest [b] = affect [b] ? src2 [b] : src1 [b]; \
|
|
|
|
} else { \
|
|
|
|
ratio = (float) src2_alpha / new_alpha; \
|
|
|
|
compl_ratio = 1.0 - ratio; \
|
|
|
|
\
|
|
|
|
for (b = 0; b < alpha; b++) \
|
|
|
|
dest[b] = affect[b] ? \
|
2000-12-31 22:58:08 +08:00
|
|
|
(guchar) (src2[b] * ratio + src1[b] * compl_ratio + EPSILON) : src1[b];\
|
1998-07-12 00:25:52 +08:00
|
|
|
} \
|
|
|
|
}*/
|
|
|
|
|
|
|
|
#define alphify(src2_alpha,new_alpha) \
|
|
|
|
if (src2_alpha != 0 && new_alpha != 0) \
|
|
|
|
{ \
|
|
|
|
b = alpha; \
|
|
|
|
if (src2_alpha == new_alpha){ \
|
|
|
|
do { \
|
|
|
|
b--; dest [b] = affect [b] ? src2 [b] : src1 [b];} while (b); \
|
|
|
|
} else { \
|
|
|
|
ratio = (float) src2_alpha / new_alpha; \
|
|
|
|
compl_ratio = 1.0 - ratio; \
|
|
|
|
\
|
|
|
|
do { b--; \
|
|
|
|
dest[b] = affect[b] ? \
|
2000-12-31 22:58:08 +08:00
|
|
|
(guchar) (src2[b] * ratio + src1[b] * compl_ratio + EPSILON) : src1[b];\
|
1998-07-12 00:25:52 +08:00
|
|
|
} while (b); \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
/*special #define alphify4(src2_alpha,new_alpha) \
|
|
|
|
if (src2_alpha != 0 && new_alpha != 0) \
|
|
|
|
{ \
|
|
|
|
if (src2_alpha == new_alpha){ \
|
|
|
|
dest [0] = affect [0] ? src2 [0] : src1 [0]; \
|
|
|
|
dest [1] = affect [1] ? src2 [1] : src1 [1]; \
|
|
|
|
dest [2] = affect [2] ? src2 [2] : src1 [2]; \
|
|
|
|
} else { \
|
|
|
|
ratio = (float) src2_alpha / new_alpha; \
|
|
|
|
compl_ratio = 1.0 - ratio; \
|
|
|
|
\
|
|
|
|
dest[0] = affect[0] ? \
|
2000-12-31 22:58:08 +08:00
|
|
|
(guchar) (src2[0] * ratio + src1[0] * compl_ratio + EPSILON) : src1[0]; \
|
1998-07-12 00:25:52 +08:00
|
|
|
dest[1] = affect[1] ? \
|
2000-12-31 22:58:08 +08:00
|
|
|
(guchar) (src2[1] * ratio + src1[1] * compl_ratio + EPSILON) : src1[1]; \
|
1998-07-12 00:25:52 +08:00
|
|
|
dest[2] = affect[2] ? \
|
2000-12-31 22:58:08 +08:00
|
|
|
(guchar) (src2[2] * ratio + src1[2] * compl_ratio + EPSILON) : src1[2]; \
|
1998-07-12 00:25:52 +08:00
|
|
|
} \
|
|
|
|
}*/
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
void
|
2001-01-24 23:36:55 +08:00
|
|
|
combine_inten_a_and_inten_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
const guchar *mask,
|
|
|
|
gint opacity,
|
|
|
|
const gboolean *affect,
|
|
|
|
gint mode_affect, /* how does the combination mode affect alpha? */
|
|
|
|
gint length,
|
|
|
|
gint bytes) /* 4 or 2 depending on RGBA or GRAYA */
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint alpha, b;
|
|
|
|
gint src2_bytes;
|
|
|
|
guchar src2_alpha;
|
|
|
|
guchar new_alpha;
|
|
|
|
const guchar *m;
|
|
|
|
gfloat ratio, compl_ratio;
|
|
|
|
glong tmp;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
src2_bytes = bytes - 1;
|
|
|
|
alpha = bytes - 1;
|
|
|
|
|
|
|
|
if (mask)
|
|
|
|
{
|
|
|
|
m = mask;
|
1998-07-12 00:25:52 +08:00
|
|
|
if (opacity == OPAQUE_OPACITY) /* HAS MASK, FULL OPACITY */
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1998-07-12 00:25:52 +08:00
|
|
|
while (length--)
|
|
|
|
{
|
|
|
|
src2_alpha = *m;
|
1998-12-16 23:48:43 +08:00
|
|
|
new_alpha = src1[alpha] +
|
|
|
|
INT_MULT((255 - src1[alpha]), src2_alpha, tmp);
|
1998-07-12 00:25:52 +08:00
|
|
|
alphify (src2_alpha, new_alpha);
|
|
|
|
|
|
|
|
if (mode_affect)
|
|
|
|
{
|
|
|
|
dest[alpha] = (affect[alpha]) ? new_alpha : src1[alpha];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dest[alpha] = (src1[alpha]) ? src1[alpha] :
|
|
|
|
(affect[alpha] ? new_alpha : src1[alpha]);
|
|
|
|
}
|
|
|
|
|
|
|
|
m++;
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += src2_bytes;
|
|
|
|
dest += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else /* HAS MASK, SEMI-OPACITY */
|
|
|
|
{
|
|
|
|
while (length--)
|
|
|
|
{
|
1998-12-16 23:48:43 +08:00
|
|
|
src2_alpha = INT_MULT(*m, opacity, tmp);
|
|
|
|
new_alpha = src1[alpha] +
|
|
|
|
INT_MULT((255 - src1[alpha]), src2_alpha, tmp);
|
1998-07-12 00:25:52 +08:00
|
|
|
alphify (src2_alpha, new_alpha);
|
|
|
|
|
|
|
|
if (mode_affect)
|
|
|
|
{
|
|
|
|
dest[alpha] = (affect[alpha]) ? new_alpha : src1[alpha];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dest[alpha] = (src1[alpha]) ? src1[alpha] :
|
|
|
|
(affect[alpha] ? new_alpha : src1[alpha]);
|
|
|
|
}
|
|
|
|
|
|
|
|
m++;
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += src2_bytes;
|
|
|
|
dest += bytes;
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
1998-07-12 00:25:52 +08:00
|
|
|
else /* NO MASK */
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
src2_alpha = opacity;
|
1998-12-16 23:48:43 +08:00
|
|
|
new_alpha = src1[alpha] +
|
|
|
|
INT_MULT((255 - src1[alpha]), src2_alpha, tmp);
|
1997-11-25 06:05:25 +08:00
|
|
|
alphify (src2_alpha, new_alpha);
|
|
|
|
|
|
|
|
if (mode_affect)
|
|
|
|
dest[alpha] = (affect[alpha]) ? new_alpha : src1[alpha];
|
|
|
|
else
|
|
|
|
dest[alpha] = (src1[alpha]) ? src1[alpha] : (affect[alpha] ? new_alpha : src1[alpha]);
|
|
|
|
|
1998-07-12 00:25:52 +08:00
|
|
|
src1 += bytes;
|
|
|
|
src2 += src2_bytes;
|
|
|
|
dest += bytes;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2001-01-24 23:36:55 +08:00
|
|
|
combine_inten_a_and_inten_a_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
const guchar *mask,
|
|
|
|
gint opacity,
|
|
|
|
const gboolean *affect,
|
|
|
|
const gint mode_affect, /* how does the combination mode affect alpha? */
|
|
|
|
gint length,
|
|
|
|
gint bytes) /* 4 or 2 depending on RGBA or GRAYA */
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint b;
|
|
|
|
guchar src2_alpha;
|
|
|
|
guchar new_alpha;
|
|
|
|
const guchar * m;
|
2001-01-24 23:36:55 +08:00
|
|
|
gfloat ratio, compl_ratio;
|
|
|
|
glong tmp;
|
2000-12-31 22:58:08 +08:00
|
|
|
const gint alpha = bytes - 1;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-07-12 00:25:52 +08:00
|
|
|
if (mask)
|
|
|
|
{
|
|
|
|
m = mask;
|
1999-01-12 06:08:07 +08:00
|
|
|
|
1998-07-12 00:25:52 +08:00
|
|
|
if (opacity == OPAQUE_OPACITY) /* HAS MASK, FULL OPACITY */
|
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
const gint* mask_ip;
|
|
|
|
gint i,j;
|
1999-01-12 06:08:07 +08:00
|
|
|
|
1999-02-01 01:58:16 +08:00
|
|
|
if (length >= sizeof(int))
|
1999-01-12 06:08:07 +08:00
|
|
|
{
|
1999-02-01 01:58:16 +08:00
|
|
|
/* HEAD */
|
|
|
|
i = (((int)m) & (sizeof(int)-1));
|
|
|
|
if (i != 0)
|
1999-01-12 06:08:07 +08:00
|
|
|
{
|
1999-02-01 01:58:16 +08:00
|
|
|
i = sizeof(int) - i;
|
|
|
|
length -= i;
|
|
|
|
while (i--)
|
1999-01-12 06:08:07 +08:00
|
|
|
{
|
|
|
|
/* GUTS */
|
|
|
|
src2_alpha = INT_MULT(src2[alpha], *m, tmp);
|
|
|
|
new_alpha = src1[alpha] +
|
|
|
|
INT_MULT((255 - src1[alpha]), src2_alpha, tmp);
|
|
|
|
|
|
|
|
alphify (src2_alpha, new_alpha);
|
|
|
|
|
|
|
|
if (mode_affect)
|
|
|
|
{
|
|
|
|
dest[alpha] = (affect[alpha]) ? new_alpha : src1[alpha];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dest[alpha] = (src1[alpha]) ? src1[alpha] :
|
|
|
|
(affect[alpha] ? new_alpha : src1[alpha]);
|
|
|
|
}
|
|
|
|
|
|
|
|
m++;
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += bytes;
|
|
|
|
dest += bytes;
|
|
|
|
/* GUTS END */
|
|
|
|
}
|
|
|
|
}
|
1999-02-01 01:58:16 +08:00
|
|
|
|
|
|
|
/* BODY */
|
|
|
|
mask_ip = (int*)m;
|
|
|
|
i = length / sizeof(int);
|
|
|
|
length %= sizeof(int);
|
|
|
|
while (i--)
|
1999-01-12 06:08:07 +08:00
|
|
|
{
|
1999-02-01 01:58:16 +08:00
|
|
|
if (*mask_ip)
|
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
m = (const guchar*)mask_ip;
|
1999-02-01 01:58:16 +08:00
|
|
|
j = sizeof(int);
|
|
|
|
while (j--)
|
|
|
|
{
|
|
|
|
/* GUTS */
|
|
|
|
src2_alpha = INT_MULT(src2[alpha], *m, tmp);
|
|
|
|
new_alpha = src1[alpha] +
|
|
|
|
INT_MULT((255 - src1[alpha]), src2_alpha, tmp);
|
|
|
|
|
|
|
|
alphify (src2_alpha, new_alpha);
|
|
|
|
|
|
|
|
if (mode_affect)
|
|
|
|
{
|
|
|
|
dest[alpha] = (affect[alpha]) ? new_alpha : src1[alpha];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dest[alpha] = (src1[alpha]) ? src1[alpha] :
|
|
|
|
(affect[alpha] ? new_alpha : src1[alpha]);
|
|
|
|
}
|
2000-12-31 22:58:08 +08:00
|
|
|
|
1999-02-01 01:58:16 +08:00
|
|
|
m++;
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += bytes;
|
2000-12-31 22:58:08 +08:00
|
|
|
dest += bytes;
|
1999-02-01 01:58:16 +08:00
|
|
|
/* GUTS END */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
1999-01-12 06:08:07 +08:00
|
|
|
{
|
1999-02-01 01:58:16 +08:00
|
|
|
j = bytes * sizeof(int);
|
|
|
|
src2 += j;
|
|
|
|
while (j--)
|
|
|
|
{
|
|
|
|
*(dest++) = *(src1++);
|
|
|
|
}
|
1999-01-12 06:08:07 +08:00
|
|
|
}
|
1999-02-01 01:58:16 +08:00
|
|
|
mask_ip++;
|
1999-01-12 06:08:07 +08:00
|
|
|
}
|
1999-02-01 01:58:16 +08:00
|
|
|
|
2000-12-31 22:58:08 +08:00
|
|
|
m = (const guchar*)mask_ip;
|
1999-01-12 06:08:07 +08:00
|
|
|
}
|
1999-01-18 02:32:59 +08:00
|
|
|
|
1999-01-12 06:08:07 +08:00
|
|
|
/* TAIL */
|
|
|
|
while (length--)
|
1998-07-12 00:25:52 +08:00
|
|
|
{
|
1999-01-12 06:08:07 +08:00
|
|
|
/* GUTS */
|
1998-12-16 23:48:43 +08:00
|
|
|
src2_alpha = INT_MULT(src2[alpha], *m, tmp);
|
|
|
|
new_alpha = src1[alpha] +
|
|
|
|
INT_MULT((255 - src1[alpha]), src2_alpha, tmp);
|
1998-07-12 00:25:52 +08:00
|
|
|
|
|
|
|
alphify (src2_alpha, new_alpha);
|
|
|
|
|
|
|
|
if (mode_affect)
|
|
|
|
{
|
|
|
|
dest[alpha] = (affect[alpha]) ? new_alpha : src1[alpha];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dest[alpha] = (src1[alpha]) ? src1[alpha] :
|
|
|
|
(affect[alpha] ? new_alpha : src1[alpha]);
|
|
|
|
}
|
|
|
|
|
|
|
|
m++;
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += bytes;
|
1999-01-12 06:08:07 +08:00
|
|
|
dest += bytes;
|
|
|
|
/* GUTS END */
|
1998-07-12 00:25:52 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else /* HAS MASK, SEMI-OPACITY */
|
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
const gint* mask_ip;
|
|
|
|
gint i,j;
|
1999-01-12 06:08:07 +08:00
|
|
|
|
1999-02-01 01:58:16 +08:00
|
|
|
if (length >= sizeof(int))
|
1998-07-12 00:25:52 +08:00
|
|
|
{
|
1999-02-01 01:58:16 +08:00
|
|
|
/* HEAD */
|
|
|
|
i = (((int)m) & (sizeof(int)-1));
|
|
|
|
if (i != 0)
|
1998-07-12 00:25:52 +08:00
|
|
|
{
|
1999-02-01 01:58:16 +08:00
|
|
|
i = sizeof(int) - i;
|
|
|
|
length -= i;
|
|
|
|
while (i--)
|
1999-01-12 06:08:07 +08:00
|
|
|
{
|
|
|
|
/* GUTS */
|
|
|
|
src2_alpha = INT_MULT3(src2[alpha], *m, opacity, tmp);
|
|
|
|
new_alpha = src1[alpha] +
|
|
|
|
INT_MULT((255 - src1[alpha]), src2_alpha, tmp);
|
1999-02-01 01:58:16 +08:00
|
|
|
|
1999-01-12 06:08:07 +08:00
|
|
|
alphify (src2_alpha, new_alpha);
|
1999-02-01 01:58:16 +08:00
|
|
|
|
1999-01-12 06:08:07 +08:00
|
|
|
if (mode_affect)
|
|
|
|
{
|
|
|
|
dest[alpha] = (affect[alpha]) ? new_alpha : src1[alpha];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dest[alpha] = (src1[alpha]) ? src1[alpha] :
|
|
|
|
(affect[alpha] ? new_alpha : src1[alpha]);
|
|
|
|
}
|
1999-02-01 01:58:16 +08:00
|
|
|
|
1999-01-12 06:08:07 +08:00
|
|
|
m++;
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += bytes;
|
|
|
|
dest += bytes;
|
|
|
|
/* GUTS END */
|
|
|
|
}
|
|
|
|
}
|
1999-02-01 01:58:16 +08:00
|
|
|
|
|
|
|
/* BODY */
|
|
|
|
mask_ip = (int*)m;
|
|
|
|
i = length / sizeof(int);
|
|
|
|
length %= sizeof(int);
|
|
|
|
while (i--)
|
1999-01-12 06:08:07 +08:00
|
|
|
{
|
1999-02-01 01:58:16 +08:00
|
|
|
if (*mask_ip)
|
1999-01-12 06:08:07 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
m = (const guchar*)mask_ip;
|
1999-02-01 01:58:16 +08:00
|
|
|
j = sizeof(int);
|
|
|
|
while (j--)
|
|
|
|
{
|
|
|
|
/* GUTS */
|
|
|
|
src2_alpha = INT_MULT3(src2[alpha], *m, opacity, tmp);
|
|
|
|
new_alpha = src1[alpha] +
|
|
|
|
INT_MULT((255 - src1[alpha]), src2_alpha, tmp);
|
|
|
|
|
|
|
|
alphify (src2_alpha, new_alpha);
|
|
|
|
|
|
|
|
if (mode_affect)
|
|
|
|
{
|
|
|
|
dest[alpha] = (affect[alpha]) ? new_alpha : src1[alpha];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dest[alpha] = (src1[alpha]) ? src1[alpha] :
|
|
|
|
(affect[alpha] ? new_alpha : src1[alpha]);
|
|
|
|
}
|
|
|
|
|
|
|
|
m++;
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += bytes;
|
|
|
|
dest += bytes;
|
|
|
|
/* GUTS END */
|
|
|
|
}
|
1999-01-12 06:08:07 +08:00
|
|
|
}
|
1999-02-01 01:58:16 +08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
j = bytes * sizeof(int);
|
|
|
|
src2 += j;
|
|
|
|
while (j--)
|
|
|
|
{
|
|
|
|
*(dest++) = *(src1++);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mask_ip++;
|
1999-01-12 06:08:07 +08:00
|
|
|
}
|
1999-01-18 02:32:59 +08:00
|
|
|
|
2000-12-31 22:58:08 +08:00
|
|
|
m = (const guchar*)mask_ip;
|
1999-02-01 01:58:16 +08:00
|
|
|
}
|
1999-01-12 06:08:07 +08:00
|
|
|
|
|
|
|
/* TAIL */
|
|
|
|
while (length--)
|
|
|
|
{
|
|
|
|
/* GUTS */
|
|
|
|
src2_alpha = INT_MULT3(src2[alpha], *m, opacity, tmp);
|
|
|
|
new_alpha = src1[alpha] +
|
|
|
|
INT_MULT((255 - src1[alpha]), src2_alpha, tmp);
|
|
|
|
|
|
|
|
alphify (src2_alpha, new_alpha);
|
|
|
|
|
|
|
|
if (mode_affect)
|
|
|
|
{
|
|
|
|
dest[alpha] = (affect[alpha]) ? new_alpha : src1[alpha];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dest[alpha] = (src1[alpha]) ? src1[alpha] :
|
|
|
|
(affect[alpha] ? new_alpha : src1[alpha]);
|
|
|
|
}
|
|
|
|
|
1998-07-12 00:25:52 +08:00
|
|
|
m++;
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += bytes;
|
|
|
|
dest += bytes;
|
1999-01-12 06:08:07 +08:00
|
|
|
/* GUTS END */
|
1998-07-12 00:25:52 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (opacity == OPAQUE_OPACITY) /* NO MASK, FULL OPACITY */
|
|
|
|
{
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
src2_alpha = src2[alpha];
|
1998-12-16 23:48:43 +08:00
|
|
|
new_alpha = src1[alpha] +
|
|
|
|
INT_MULT((255 - src1[alpha]), src2_alpha, tmp);
|
1998-07-12 00:25:52 +08:00
|
|
|
|
|
|
|
alphify (src2_alpha, new_alpha);
|
|
|
|
|
|
|
|
if (mode_affect)
|
|
|
|
{
|
|
|
|
dest[alpha] = (affect[alpha]) ? new_alpha : src1[alpha];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dest[alpha] = (src1[alpha]) ? src1[alpha] :
|
|
|
|
(affect[alpha] ? new_alpha : src1[alpha]);
|
|
|
|
}
|
|
|
|
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += bytes;
|
|
|
|
dest += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else /* NO MASK, SEMI OPACITY */
|
|
|
|
{
|
|
|
|
while (length --)
|
|
|
|
{
|
1998-12-16 23:48:43 +08:00
|
|
|
src2_alpha = INT_MULT(src2[alpha], opacity, tmp);
|
|
|
|
new_alpha = src1[alpha] +
|
|
|
|
INT_MULT((255 - src1[alpha]), src2_alpha, tmp);
|
1998-07-12 00:25:52 +08:00
|
|
|
|
|
|
|
alphify (src2_alpha, new_alpha);
|
|
|
|
|
|
|
|
if (mode_affect)
|
|
|
|
{
|
|
|
|
dest[alpha] = (affect[alpha]) ? new_alpha : src1[alpha];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dest[alpha] = (src1[alpha]) ? src1[alpha] :
|
|
|
|
(affect[alpha] ? new_alpha : src1[alpha]);
|
|
|
|
}
|
|
|
|
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += bytes;
|
|
|
|
dest += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
#undef alphify
|
|
|
|
|
|
|
|
void
|
2000-12-31 22:58:08 +08:00
|
|
|
combine_inten_a_and_channel_mask_pixels (const guchar *src,
|
|
|
|
const guchar *channel,
|
|
|
|
guchar *dest,
|
|
|
|
const guchar *col,
|
|
|
|
gint opacity,
|
|
|
|
gint length,
|
|
|
|
gint bytes)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint alpha, b;
|
|
|
|
guchar channel_alpha;
|
|
|
|
guchar new_alpha;
|
|
|
|
guchar compl_alpha;
|
|
|
|
gint t, s;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
alpha = bytes - 1;
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
channel_alpha = INT_MULT (255 - *channel, opacity, t);
|
|
|
|
if (channel_alpha)
|
|
|
|
{
|
|
|
|
new_alpha = src[alpha] + INT_MULT ((255 - src[alpha]), channel_alpha, t);
|
|
|
|
|
|
|
|
if (new_alpha != 255)
|
|
|
|
channel_alpha = (channel_alpha * 255) / new_alpha;
|
|
|
|
compl_alpha = 255 - channel_alpha;
|
|
|
|
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
dest[b] = INT_MULT (col[b], channel_alpha, t) +
|
|
|
|
INT_MULT (src[b], compl_alpha, s);
|
|
|
|
dest[b] = new_alpha;
|
|
|
|
}
|
|
|
|
else
|
1998-01-20 12:51:56 +08:00
|
|
|
memcpy(dest, src, bytes);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* advance pointers */
|
|
|
|
src+=bytes;
|
|
|
|
dest+=bytes;
|
|
|
|
channel++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2000-12-31 22:58:08 +08:00
|
|
|
combine_inten_a_and_channel_selection_pixels (const guchar *src,
|
|
|
|
const guchar *channel,
|
|
|
|
guchar *dest,
|
|
|
|
const guchar *col,
|
|
|
|
gint opacity,
|
|
|
|
gint length,
|
|
|
|
gint bytes)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint alpha, b;
|
|
|
|
guchar channel_alpha;
|
|
|
|
guchar new_alpha;
|
|
|
|
guchar compl_alpha;
|
|
|
|
gint t, s;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
alpha = bytes - 1;
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
channel_alpha = INT_MULT (*channel, opacity, t);
|
|
|
|
if (channel_alpha)
|
|
|
|
{
|
|
|
|
new_alpha = src[alpha] + INT_MULT ((255 - src[alpha]), channel_alpha, t);
|
|
|
|
|
|
|
|
if (new_alpha != 255)
|
|
|
|
channel_alpha = (channel_alpha * 255) / new_alpha;
|
|
|
|
compl_alpha = 255 - channel_alpha;
|
|
|
|
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
dest[b] = INT_MULT (col[b], channel_alpha, t) +
|
|
|
|
INT_MULT (src[b], compl_alpha, s);
|
|
|
|
dest[b] = new_alpha;
|
|
|
|
}
|
|
|
|
else
|
1998-01-20 12:51:56 +08:00
|
|
|
memcpy(dest, src, bytes);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* advance pointers */
|
|
|
|
src+=bytes;
|
|
|
|
dest+=bytes;
|
|
|
|
channel++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2001-01-24 23:36:55 +08:00
|
|
|
behind_inten_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
const guchar *mask,
|
|
|
|
gint opacity,
|
|
|
|
const gboolean *affect,
|
|
|
|
gint length,
|
|
|
|
gint bytes1,
|
|
|
|
gint bytes2,
|
|
|
|
gint has_alpha1,
|
|
|
|
gint has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint alpha, b;
|
|
|
|
guchar src1_alpha;
|
|
|
|
guchar src2_alpha;
|
|
|
|
guchar new_alpha;
|
|
|
|
const guchar *m;
|
|
|
|
gfloat ratio, compl_ratio;
|
|
|
|
glong tmp;
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
if (mask)
|
|
|
|
m = mask;
|
|
|
|
else
|
|
|
|
m = &no_mask;
|
|
|
|
|
|
|
|
/* the alpha channel */
|
1998-09-15 09:53:40 +08:00
|
|
|
alpha = bytes1 - 1;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
src1_alpha = src1[alpha];
|
1998-12-16 23:48:43 +08:00
|
|
|
src2_alpha = INT_MULT3(src2[alpha], *m, opacity, tmp);
|
|
|
|
new_alpha = src2_alpha +
|
|
|
|
INT_MULT((255 - src2_alpha), src1_alpha, tmp);
|
1997-11-25 06:05:25 +08:00
|
|
|
if (new_alpha)
|
|
|
|
ratio = (float) src1_alpha / new_alpha;
|
|
|
|
else
|
|
|
|
ratio = 0.0;
|
|
|
|
compl_ratio = 1.0 - ratio;
|
|
|
|
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
dest[b] = (affect[b]) ?
|
2000-12-31 22:58:08 +08:00
|
|
|
(guchar) (src1[b] * ratio + src2[b] * compl_ratio + EPSILON) :
|
1997-11-25 06:05:25 +08:00
|
|
|
src1[b];
|
|
|
|
|
|
|
|
dest[alpha] = (affect[alpha]) ? new_alpha : src1[alpha];
|
|
|
|
|
|
|
|
if (mask)
|
|
|
|
m++;
|
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
src1 += bytes1;
|
|
|
|
src2 += bytes2;
|
|
|
|
dest += bytes1;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2001-01-24 23:36:55 +08:00
|
|
|
behind_indexed_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
const guchar *mask,
|
|
|
|
gint opacity,
|
|
|
|
const gboolean *affect,
|
|
|
|
gint length,
|
|
|
|
gint bytes1,
|
|
|
|
gint bytes2,
|
|
|
|
gint has_alpha1,
|
|
|
|
gint has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint alpha, b;
|
|
|
|
guchar src1_alpha;
|
|
|
|
guchar src2_alpha;
|
|
|
|
guchar new_alpha;
|
|
|
|
const guchar *m;
|
|
|
|
glong tmp;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
if (mask)
|
|
|
|
m = mask;
|
|
|
|
else
|
|
|
|
m = &no_mask;
|
|
|
|
|
|
|
|
/* the alpha channel */
|
1998-09-15 09:53:40 +08:00
|
|
|
alpha = bytes1 - 1;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
src1_alpha = src1[alpha];
|
1998-12-16 23:48:43 +08:00
|
|
|
src2_alpha = INT_MULT3(src2[alpha], *m, opacity, tmp);
|
1998-01-25 09:24:46 +08:00
|
|
|
new_alpha = (src2_alpha > 127) ? OPAQUE_OPACITY : TRANSPARENT_OPACITY;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
for (b = 0; b < bytes1; b++)
|
1998-01-25 09:24:46 +08:00
|
|
|
dest[b] = (affect[b] && new_alpha == OPAQUE_OPACITY && (src1_alpha > 127)) ?
|
1997-11-25 06:05:25 +08:00
|
|
|
src2[b] : src1[b];
|
|
|
|
|
|
|
|
if (mask)
|
|
|
|
m++;
|
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
src1 += bytes1;
|
|
|
|
src2 += bytes2;
|
|
|
|
dest += bytes1;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2001-01-24 23:36:55 +08:00
|
|
|
replace_inten_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
const guchar *mask,
|
|
|
|
gint opacity,
|
|
|
|
const gboolean *affect,
|
|
|
|
gint length,
|
|
|
|
gint bytes1,
|
|
|
|
gint bytes2,
|
|
|
|
gint has_alpha1,
|
|
|
|
gint has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint b;
|
|
|
|
gint tmp;
|
|
|
|
const gint bytes = MIN (bytes1, bytes2);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-06-18 01:37:36 +08:00
|
|
|
if (mask)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
guchar mask_alpha;
|
|
|
|
const guchar *m = mask;
|
|
|
|
|
2000-06-18 01:37:36 +08:00
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
mask_alpha = INT_MULT(*m, opacity, tmp);
|
|
|
|
|
|
|
|
for (b = 0; b < bytes; b++)
|
|
|
|
dest[b] = (affect[b]) ?
|
|
|
|
INT_BLEND(src2[b], src1[b], mask_alpha, tmp) :
|
|
|
|
src1[b];
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-06-18 01:37:36 +08:00
|
|
|
if (has_alpha1 && !has_alpha2)
|
|
|
|
dest[b] = src1[b];
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-06-18 01:37:36 +08:00
|
|
|
m++;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-06-18 01:37:36 +08:00
|
|
|
src1 += bytes1;
|
|
|
|
src2 += bytes2;
|
|
|
|
dest += bytes1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
static const guchar mask_alpha = OPAQUE_OPACITY ;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-06-18 01:37:36 +08:00
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
for (b = 0; b < bytes; b++)
|
|
|
|
dest[b] = (affect[b]) ?
|
|
|
|
INT_BLEND(src2[b], src1[b], mask_alpha, tmp) :
|
|
|
|
src1[b];
|
|
|
|
|
|
|
|
if (has_alpha1 && !has_alpha2)
|
|
|
|
dest[b] = src1[b];
|
|
|
|
|
|
|
|
src1 += bytes1;
|
|
|
|
src2 += bytes2;
|
|
|
|
dest += bytes1;
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2001-01-24 23:36:55 +08:00
|
|
|
replace_indexed_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
const guchar *mask,
|
|
|
|
gint opacity,
|
|
|
|
const gboolean *affect,
|
|
|
|
gint length,
|
|
|
|
gint bytes1,
|
|
|
|
gint bytes2,
|
|
|
|
gint has_alpha1,
|
|
|
|
gint has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint bytes, b;
|
|
|
|
guchar mask_alpha;
|
|
|
|
const guchar *m;
|
|
|
|
gint tmp;
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
if (mask)
|
|
|
|
m = mask;
|
|
|
|
else
|
|
|
|
m = &no_mask;
|
|
|
|
|
2000-01-26 07:06:12 +08:00
|
|
|
bytes = MIN (bytes1, bytes2);
|
1997-11-25 06:05:25 +08:00
|
|
|
while (length --)
|
|
|
|
{
|
1998-12-16 23:48:43 +08:00
|
|
|
mask_alpha = INT_MULT(*m, opacity, tmp);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
for (b = 0; b < bytes; b++)
|
2000-12-31 22:58:08 +08:00
|
|
|
dest[b] = (affect[b] && mask_alpha) ? src2[b] : src1[b];
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
if (has_alpha1 && !has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
dest[b] = src1[b];
|
|
|
|
|
|
|
|
if (mask)
|
|
|
|
m++;
|
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
src1 += bytes1;
|
|
|
|
src2 += bytes2;
|
|
|
|
dest += bytes1;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2001-01-24 23:36:55 +08:00
|
|
|
erase_inten_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
const guchar *mask,
|
|
|
|
gint opacity,
|
|
|
|
const gboolean *affect,
|
|
|
|
gint length,
|
|
|
|
gint bytes)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint b;
|
|
|
|
guchar src2_alpha;
|
2001-01-24 23:36:55 +08:00
|
|
|
glong tmp;
|
2000-12-31 22:58:08 +08:00
|
|
|
const gint alpha = bytes - 1;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
if (mask)
|
2000-06-18 01:37:36 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
const guchar *m = mask;
|
2000-06-18 01:37:36 +08:00
|
|
|
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
dest[b] = src1[b];
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-06-18 01:37:36 +08:00
|
|
|
src2_alpha = INT_MULT3(src2[alpha], *m, opacity, tmp);
|
|
|
|
dest[alpha] = src1[alpha] - INT_MULT(src1[alpha], src2_alpha, tmp);
|
|
|
|
|
|
|
|
m++;
|
|
|
|
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += bytes;
|
|
|
|
dest += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
guchar *m = &no_mask;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-06-18 01:37:36 +08:00
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
dest[b] = src1[b];
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-06-18 01:37:36 +08:00
|
|
|
src2_alpha = INT_MULT3(src2[alpha], *m, opacity, tmp);
|
|
|
|
dest[alpha] = src1[alpha] - INT_MULT(src1[alpha], src2_alpha, tmp);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-06-18 01:37:36 +08:00
|
|
|
src1 += bytes;
|
|
|
|
src2 += bytes;
|
|
|
|
dest += bytes;
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2001-01-24 23:36:55 +08:00
|
|
|
erase_indexed_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
const guchar *mask,
|
|
|
|
gint opacity,
|
|
|
|
const gboolean *affect,
|
|
|
|
gint length,
|
|
|
|
gint bytes)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint alpha, b;
|
|
|
|
guchar src2_alpha;
|
|
|
|
const guchar *m;
|
2001-01-24 23:36:55 +08:00
|
|
|
glong tmp;
|
2000-12-31 22:58:08 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
if (mask)
|
|
|
|
m = mask;
|
|
|
|
else
|
|
|
|
m = &no_mask;
|
|
|
|
|
|
|
|
alpha = bytes - 1;
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
dest[b] = src1[b];
|
|
|
|
|
1998-12-16 23:48:43 +08:00
|
|
|
src2_alpha = INT_MULT3(src2[alpha], *m, opacity, tmp);
|
1998-01-25 09:24:46 +08:00
|
|
|
dest[alpha] = (src2_alpha > 127) ? TRANSPARENT_OPACITY : src1[alpha];
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
if (mask)
|
|
|
|
m++;
|
|
|
|
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += bytes;
|
|
|
|
dest += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-08-14 05:16:02 +08:00
|
|
|
void
|
2001-01-24 23:36:55 +08:00
|
|
|
anti_erase_inten_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
const guchar *mask,
|
|
|
|
gint opacity,
|
|
|
|
const gboolean *affect,
|
|
|
|
gint length,
|
|
|
|
gint bytes)
|
1999-08-14 05:16:02 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint alpha, b;
|
|
|
|
guchar src2_alpha;
|
|
|
|
const guchar *m;
|
|
|
|
glong tmp;
|
1999-08-14 05:16:02 +08:00
|
|
|
|
|
|
|
if (mask)
|
|
|
|
m = mask;
|
|
|
|
else
|
|
|
|
m = &no_mask;
|
|
|
|
|
|
|
|
alpha = bytes - 1;
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
dest[b] = src1[b];
|
|
|
|
|
|
|
|
src2_alpha = INT_MULT3(src2[alpha], *m, opacity, tmp);
|
|
|
|
dest[alpha] = src1[alpha] + INT_MULT((255 - src1[alpha]), src2_alpha, tmp);
|
|
|
|
|
|
|
|
if (mask)
|
|
|
|
m++;
|
|
|
|
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += bytes;
|
|
|
|
dest += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2001-01-24 23:36:55 +08:00
|
|
|
anti_erase_indexed_pixels (const guchar *src1,
|
|
|
|
const guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
const guchar *mask,
|
|
|
|
gint opacity,
|
|
|
|
const gboolean *affect,
|
|
|
|
gint length,
|
|
|
|
gint bytes)
|
1999-08-14 05:16:02 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint alpha, b;
|
|
|
|
guchar src2_alpha;
|
|
|
|
const guchar *m;
|
|
|
|
glong tmp;
|
|
|
|
|
1999-08-14 05:16:02 +08:00
|
|
|
if (mask)
|
|
|
|
m = mask;
|
|
|
|
else
|
|
|
|
m = &no_mask;
|
|
|
|
|
|
|
|
alpha = bytes - 1;
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
dest[b] = src1[b];
|
|
|
|
|
|
|
|
src2_alpha = INT_MULT3(src2[alpha], *m, opacity, tmp);
|
|
|
|
dest[alpha] = (src2_alpha > 127) ? OPAQUE_OPACITY : src1[alpha];
|
|
|
|
|
|
|
|
if (mask)
|
|
|
|
m++;
|
|
|
|
|
|
|
|
src1 += bytes;
|
|
|
|
src2 += bytes;
|
|
|
|
dest += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
void
|
2000-12-31 22:58:08 +08:00
|
|
|
extract_from_inten_pixels (guchar *src,
|
|
|
|
guchar *dest,
|
|
|
|
const guchar *mask,
|
|
|
|
const guchar *bg,
|
|
|
|
gint cut,
|
|
|
|
gint length,
|
|
|
|
gint bytes,
|
|
|
|
gint has_alpha)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint b, alpha;
|
|
|
|
gint dest_bytes;
|
|
|
|
const guchar *m;
|
|
|
|
gint tmp;
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
if (mask)
|
|
|
|
m = mask;
|
|
|
|
else
|
|
|
|
m = &no_mask;
|
|
|
|
|
|
|
|
alpha = (has_alpha) ? bytes - 1 : bytes;
|
|
|
|
dest_bytes = (has_alpha) ? bytes : bytes + 1;
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
for (b = 0; b < alpha; b++)
|
|
|
|
dest[b] = src[b];
|
|
|
|
|
|
|
|
if (has_alpha)
|
|
|
|
{
|
1998-12-16 23:48:43 +08:00
|
|
|
dest[alpha] = INT_MULT(*m, src[alpha], tmp);
|
1997-11-25 06:05:25 +08:00
|
|
|
if (cut)
|
1998-12-16 23:48:43 +08:00
|
|
|
src[alpha] = INT_MULT((255 - *m), src[alpha], tmp);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dest[alpha] = *m;
|
|
|
|
if (cut)
|
|
|
|
for (b = 0; b < bytes; b++)
|
1998-12-16 23:48:43 +08:00
|
|
|
src[b] = INT_BLEND(bg[b], src[b], *m, tmp);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mask)
|
|
|
|
m++;
|
|
|
|
|
|
|
|
src += bytes;
|
|
|
|
dest += dest_bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2000-12-31 22:58:08 +08:00
|
|
|
extract_from_indexed_pixels (guchar *src,
|
|
|
|
guchar *dest,
|
|
|
|
const guchar *mask,
|
|
|
|
const guchar *cmap,
|
|
|
|
const guchar *bg,
|
|
|
|
gint cut,
|
|
|
|
gint length,
|
|
|
|
gint bytes,
|
|
|
|
gint has_alpha)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint b;
|
|
|
|
gint index;
|
|
|
|
const guchar *m;
|
|
|
|
gint t;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
if (mask)
|
|
|
|
m = mask;
|
|
|
|
else
|
|
|
|
m = &no_mask;
|
|
|
|
|
|
|
|
while (length --)
|
|
|
|
{
|
|
|
|
index = src[0] * 3;
|
|
|
|
for (b = 0; b < 3; b++)
|
|
|
|
dest[b] = cmap[index + b];
|
|
|
|
|
|
|
|
if (has_alpha)
|
|
|
|
{
|
|
|
|
dest[3] = INT_MULT (*m, src[1], t);
|
|
|
|
if (cut)
|
|
|
|
src[1] = INT_MULT ((255 - *m), src[1], t);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dest[3] = *m;
|
|
|
|
if (cut)
|
|
|
|
src[0] = (*m > 127) ? bg[0] : src[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mask)
|
|
|
|
m++;
|
|
|
|
|
|
|
|
src += bytes;
|
|
|
|
dest += 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2000-12-31 22:58:08 +08:00
|
|
|
map_to_color (gint src_type,
|
|
|
|
const guchar *cmap,
|
|
|
|
const guchar *src,
|
|
|
|
guchar *rgb)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
switch (src_type)
|
|
|
|
{
|
|
|
|
case 0: /* RGB */
|
|
|
|
/* Straight copy */
|
|
|
|
*rgb++ = *src++;
|
|
|
|
*rgb++ = *src++;
|
|
|
|
*rgb = *src;
|
|
|
|
break;
|
|
|
|
case 1: /* GRAY */
|
|
|
|
*rgb++ = *src;
|
|
|
|
*rgb++ = *src;
|
|
|
|
*rgb = *src;
|
|
|
|
break;
|
|
|
|
case 2: /* INDEXED */
|
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint index = *src * 3;
|
1997-11-25 06:05:25 +08:00
|
|
|
*rgb++ = cmap [index++];
|
|
|
|
*rgb++ = cmap [index++];
|
|
|
|
*rgb = cmap [index++];
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-12-29 00:19:55 +08:00
|
|
|
gint
|
|
|
|
map_rgb_to_indexed (const guchar *cmap,
|
|
|
|
gint num_cols,
|
|
|
|
const GimpImage *gimage,
|
|
|
|
gint r,
|
|
|
|
gint g,
|
|
|
|
gint b)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
guint pixel;
|
|
|
|
gint hash_index;
|
|
|
|
gint cmap_index;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
pixel = (r << 16) | (g << 8) | b;
|
|
|
|
hash_index = pixel % HASH_TABLE_SIZE;
|
|
|
|
|
|
|
|
/* Hash table lookup hit */
|
1998-06-29 08:24:44 +08:00
|
|
|
if (color_hash_table[hash_index].gimage == gimage &&
|
1997-11-25 06:05:25 +08:00
|
|
|
color_hash_table[hash_index].pixel == pixel)
|
|
|
|
{
|
|
|
|
cmap_index = color_hash_table[hash_index].index;
|
|
|
|
color_hash_hits++;
|
|
|
|
}
|
|
|
|
/* Hash table lookup miss */
|
|
|
|
else
|
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
const guchar *col;
|
|
|
|
gint diff, sum, max;
|
|
|
|
gint i;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
max = MAXDIFF;
|
|
|
|
cmap_index = 0;
|
|
|
|
|
|
|
|
col = cmap;
|
|
|
|
for (i = 0; i < num_cols; i++)
|
|
|
|
{
|
|
|
|
diff = r - *col++;
|
|
|
|
sum = diff * diff;
|
|
|
|
diff = g - *col++;
|
|
|
|
sum += diff * diff;
|
|
|
|
diff = b - *col++;
|
|
|
|
sum += diff * diff;
|
|
|
|
|
|
|
|
if (sum < max)
|
|
|
|
{
|
|
|
|
cmap_index = i;
|
|
|
|
max = sum;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* update the hash table */
|
2000-12-29 00:19:55 +08:00
|
|
|
color_hash_table[hash_index].pixel = pixel;
|
|
|
|
color_hash_table[hash_index].index = cmap_index;
|
|
|
|
color_hash_table[hash_index].gimage = (GimpImage *) gimage;
|
1997-11-25 06:05:25 +08:00
|
|
|
color_hash_misses++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return cmap_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**************************************************/
|
|
|
|
/* REGION FUNCTIONS */
|
|
|
|
/**************************************************/
|
|
|
|
|
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
color_region (PixelRegion *dest,
|
|
|
|
const guchar *col)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
gint h;
|
|
|
|
guchar *s;
|
|
|
|
void *pr;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-12-29 00:19:55 +08:00
|
|
|
for (pr = pixel_regions_register (1, dest);
|
|
|
|
pr != NULL;
|
|
|
|
pr = pixel_regions_process (pr))
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1998-09-15 09:53:40 +08:00
|
|
|
h = dest->h;
|
|
|
|
s = dest->data;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-12-16 19:23:30 +08:00
|
|
|
if (dest->w*dest->bytes == dest->rowstride)
|
2000-12-29 00:19:55 +08:00
|
|
|
{
|
|
|
|
/* do it all in one function call if we can */
|
|
|
|
/* this hasn't been tested to see if it is a
|
|
|
|
signifigant speed gain yet */
|
|
|
|
color_pixels (s, col, dest->w*h, dest->bytes);
|
|
|
|
}
|
1998-12-16 19:23:30 +08:00
|
|
|
else
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
while (h--)
|
|
|
|
{
|
|
|
|
color_pixels (s, col, dest->w, dest->bytes);
|
|
|
|
s += dest->rowstride;
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
blend_region (PixelRegion *src1,
|
|
|
|
PixelRegion *src2,
|
|
|
|
PixelRegion *dest,
|
2000-12-29 00:19:55 +08:00
|
|
|
gint blend)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
gint h;
|
|
|
|
guchar *s1, *s2, * d;
|
|
|
|
void *pr;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-12-29 00:19:55 +08:00
|
|
|
for (pr = pixel_regions_register (3, src1, src2, dest);
|
|
|
|
pr != NULL;
|
|
|
|
pr = pixel_regions_process (pr))
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1999-07-02 00:52:50 +08:00
|
|
|
s1 = src1->data;
|
|
|
|
s2 = src2->data;
|
|
|
|
d = dest->data;
|
|
|
|
h = src1->h;
|
|
|
|
|
|
|
|
while (h --)
|
|
|
|
{
|
|
|
|
blend_pixels (s1, s2, d, blend, src1->w, src1->bytes, FALSE);
|
|
|
|
s1 += src1->rowstride;
|
|
|
|
s2 += src2->rowstride;
|
|
|
|
d += dest->rowstride;
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
shade_region (PixelRegion *src,
|
|
|
|
PixelRegion *dest,
|
|
|
|
guchar *col,
|
|
|
|
gint blend)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
gint h;
|
|
|
|
guchar *s, * d;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
s = src->data;
|
|
|
|
d = dest->data;
|
|
|
|
h = src->h;
|
|
|
|
|
|
|
|
while (h --)
|
|
|
|
{
|
|
|
|
/* blend_pixels (s, d, col, blend, src->w, src->bytes);*/
|
|
|
|
s += src->rowstride;
|
|
|
|
d += dest->rowstride;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
copy_region (PixelRegion *src,
|
|
|
|
PixelRegion *dest)
|
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
gint h;
|
|
|
|
gint pixelwidth;
|
|
|
|
guchar *s, *d;
|
|
|
|
void *pr;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-01-11 04:45:55 +08:00
|
|
|
#ifdef COWSHOW
|
2000-12-29 00:19:55 +08:00
|
|
|
fputc ('[',stderr);
|
1999-01-11 04:45:55 +08:00
|
|
|
#endif
|
1998-07-03 07:29:44 +08:00
|
|
|
for (pr = pixel_regions_register (2, src, dest);
|
|
|
|
pr != NULL;
|
|
|
|
pr = pixel_regions_process (pr))
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1998-08-16 03:17:36 +08:00
|
|
|
if (src->tiles && dest->tiles &&
|
|
|
|
src->curtile && dest->curtile &&
|
|
|
|
src->offx == 0 && dest->offx == 0 &&
|
|
|
|
src->offy == 0 && dest->offy == 0 &&
|
2001-01-23 22:21:37 +08:00
|
|
|
src->w == tile_ewidth (src->curtile) &&
|
|
|
|
dest->w == tile_ewidth (dest->curtile) &&
|
|
|
|
src->h == tile_eheight (src->curtile) &&
|
|
|
|
dest->h == tile_eheight (dest->curtile))
|
1998-08-16 03:17:36 +08:00
|
|
|
{
|
1999-01-11 04:45:55 +08:00
|
|
|
#ifdef COWSHOW
|
1998-08-16 03:17:36 +08:00
|
|
|
fputc('!',stderr);
|
1999-01-11 04:45:55 +08:00
|
|
|
#endif
|
1998-08-16 03:17:36 +08:00
|
|
|
tile_manager_map_over_tile (dest->tiles, dest->curtile, src->curtile);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-01-11 04:45:55 +08:00
|
|
|
#ifdef COWSHOW
|
2000-12-29 00:19:55 +08:00
|
|
|
fputc ('.',stderr);
|
1999-01-11 04:45:55 +08:00
|
|
|
#endif
|
1998-08-16 03:17:36 +08:00
|
|
|
pixelwidth = src->w * src->bytes;
|
|
|
|
s = src->data;
|
|
|
|
d = dest->data;
|
|
|
|
h = src->h;
|
|
|
|
|
|
|
|
while (h --)
|
|
|
|
{
|
|
|
|
memcpy (d, s, pixelwidth);
|
|
|
|
s += src->rowstride;
|
|
|
|
d += dest->rowstride;
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
2000-12-29 00:19:55 +08:00
|
|
|
|
1999-01-11 04:45:55 +08:00
|
|
|
#ifdef COWSHOW
|
2000-12-29 00:19:55 +08:00
|
|
|
fputc (']',stderr);
|
|
|
|
fputc ('\n',stderr);
|
1999-01-11 04:45:55 +08:00
|
|
|
#endif
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
add_alpha_region (PixelRegion *src,
|
|
|
|
PixelRegion *dest)
|
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
gint h;
|
|
|
|
guchar *s, *d;
|
|
|
|
void *pr;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-12-29 00:19:55 +08:00
|
|
|
for (pr = pixel_regions_register (2, src, dest);
|
|
|
|
pr != NULL;
|
|
|
|
pr = pixel_regions_process (pr))
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
s = src->data;
|
|
|
|
d = dest->data;
|
|
|
|
h = src->h;
|
|
|
|
|
|
|
|
while (h --)
|
|
|
|
{
|
|
|
|
add_alpha_pixels (s, d, src->w, src->bytes);
|
|
|
|
s += src->rowstride;
|
|
|
|
d += dest->rowstride;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
flatten_region (PixelRegion *src,
|
|
|
|
PixelRegion *dest,
|
|
|
|
guchar *bg)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
gint h;
|
|
|
|
guchar *s, *d;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
s = src->data;
|
|
|
|
d = dest->data;
|
|
|
|
h = src->h;
|
|
|
|
|
|
|
|
while (h --)
|
|
|
|
{
|
|
|
|
flatten_pixels (s, d, bg, src->w, src->bytes);
|
|
|
|
s += src->rowstride;
|
|
|
|
d += dest->rowstride;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
extract_alpha_region (PixelRegion *src,
|
|
|
|
PixelRegion *mask,
|
|
|
|
PixelRegion *dest)
|
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint h;
|
|
|
|
guchar * s, * m, * d;
|
1997-11-25 06:05:25 +08:00
|
|
|
void * pr;
|
|
|
|
|
|
|
|
for (pr = pixel_regions_register (3, src, mask, dest); pr != NULL; pr = pixel_regions_process (pr))
|
|
|
|
{
|
|
|
|
s = src->data;
|
|
|
|
d = dest->data;
|
|
|
|
if (mask)
|
|
|
|
m = mask->data;
|
|
|
|
else
|
|
|
|
m = NULL;
|
|
|
|
|
|
|
|
h = src->h;
|
|
|
|
while (h --)
|
|
|
|
{
|
|
|
|
extract_alpha_pixels (s, m, d, src->w, src->bytes);
|
|
|
|
s += src->rowstride;
|
|
|
|
d += dest->rowstride;
|
|
|
|
if (mask)
|
|
|
|
m += mask->rowstride;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2000-12-31 22:58:08 +08:00
|
|
|
extract_from_region (PixelRegion *src,
|
|
|
|
PixelRegion *dest,
|
|
|
|
PixelRegion *mask,
|
|
|
|
guchar *cmap,
|
|
|
|
guchar *bg,
|
|
|
|
gint type,
|
|
|
|
gint has_alpha,
|
|
|
|
gint cut)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint h;
|
|
|
|
guchar *s, *d, *m;
|
|
|
|
void *pr;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-12-31 22:58:08 +08:00
|
|
|
for (pr = pixel_regions_register (3, src, dest, mask);
|
|
|
|
pr != NULL;
|
|
|
|
pr = pixel_regions_process (pr))
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
s = src->data;
|
|
|
|
d = dest->data;
|
|
|
|
m = (mask) ? mask->data : NULL;
|
|
|
|
h = src->h;
|
|
|
|
|
|
|
|
while (h --)
|
|
|
|
{
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case 0: /* RGB */
|
|
|
|
case 1: /* GRAY */
|
|
|
|
extract_from_inten_pixels (s, d, m, bg, cut, src->w,
|
|
|
|
src->bytes, has_alpha);
|
|
|
|
break;
|
|
|
|
case 2: /* INDEXED */
|
|
|
|
extract_from_indexed_pixels (s, d, m, cmap, bg, cut, src->w,
|
|
|
|
src->bytes, has_alpha);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
s += src->rowstride;
|
|
|
|
d += dest->rowstride;
|
|
|
|
if (mask)
|
|
|
|
m += mask->rowstride;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
Actually use the enum types GimpImageType, GimpImageBaseType,
* app/*.[ch]: Actually use the enum types GimpImageType,
GimpImageBaseType, LayerModeEffects, PaintApplicationMode,
BrushApplicationMode, GimpFillType and ConvertPaletteType, instead
of just int or gint. Hopefully I catched most of the places
where these should be used.
Add an enum ConvolutionType, suffix the too general constants
NORMAL, ABSOLUTE and NEGATIVE with _CONVOL. Use NORMAL_MODE
instead of NORMAL in some places (this was what was intended). Fix
some minor gccisms.
* app/apptypes.h: New file. This file contains the above
enumeration types, and some opaque struct typedefs. It was
necessary to collect these in one header that doesn't include
other headers, because when we started using the above mentioned
types in the headers, all hell broke loose because of the
spaghetti-like cross-inclusion mess between headers.
(An example: Header A includes header B, which includes header C
which includes A. B uses a type defined in A. This is not defined,
because A hasn't defined it yet at the point where it includes B,
and A included from B of course is skipped as we already are
reading A.)
1999-08-19 07:41:39 +08:00
|
|
|
convolve_region (PixelRegion *srcR,
|
|
|
|
PixelRegion *destR,
|
2000-12-31 22:58:08 +08:00
|
|
|
gint *matrix,
|
|
|
|
gint size,
|
|
|
|
gint divisor,
|
Actually use the enum types GimpImageType, GimpImageBaseType,
* app/*.[ch]: Actually use the enum types GimpImageType,
GimpImageBaseType, LayerModeEffects, PaintApplicationMode,
BrushApplicationMode, GimpFillType and ConvertPaletteType, instead
of just int or gint. Hopefully I catched most of the places
where these should be used.
Add an enum ConvolutionType, suffix the too general constants
NORMAL, ABSOLUTE and NEGATIVE with _CONVOL. Use NORMAL_MODE
instead of NORMAL in some places (this was what was intended). Fix
some minor gccisms.
* app/apptypes.h: New file. This file contains the above
enumeration types, and some opaque struct typedefs. It was
necessary to collect these in one header that doesn't include
other headers, because when we started using the above mentioned
types in the headers, all hell broke loose because of the
spaghetti-like cross-inclusion mess between headers.
(An example: Header A includes header B, which includes header C
which includes A. B uses a type defined in A. This is not defined,
because A hasn't defined it yet at the point where it includes B,
and A included from B of course is skipped as we already are
reading A.)
1999-08-19 07:41:39 +08:00
|
|
|
ConvolutionType mode)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
/* Convolve the src image using the convolution matrix, writing to dest */
|
|
|
|
/* Convolve is not tile-enabled--use accordingly */
|
2000-12-31 22:58:08 +08:00
|
|
|
guchar *src, *s_row, *s;
|
|
|
|
guchar *dest, *d;
|
|
|
|
gint *m;
|
|
|
|
gint total [4];
|
|
|
|
gint b, bytes;
|
|
|
|
gint length;
|
|
|
|
gint wraparound;
|
|
|
|
gint margin; /* margin imposed by size of conv. matrix */
|
|
|
|
gint i, j;
|
|
|
|
gint x, y;
|
|
|
|
gint offset;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
Actually use the enum types GimpImageType, GimpImageBaseType,
* app/*.[ch]: Actually use the enum types GimpImageType,
GimpImageBaseType, LayerModeEffects, PaintApplicationMode,
BrushApplicationMode, GimpFillType and ConvertPaletteType, instead
of just int or gint. Hopefully I catched most of the places
where these should be used.
Add an enum ConvolutionType, suffix the too general constants
NORMAL, ABSOLUTE and NEGATIVE with _CONVOL. Use NORMAL_MODE
instead of NORMAL in some places (this was what was intended). Fix
some minor gccisms.
* app/apptypes.h: New file. This file contains the above
enumeration types, and some opaque struct typedefs. It was
necessary to collect these in one header that doesn't include
other headers, because when we started using the above mentioned
types in the headers, all hell broke loose because of the
spaghetti-like cross-inclusion mess between headers.
(An example: Header A includes header B, which includes header C
which includes A. B uses a type defined in A. This is not defined,
because A hasn't defined it yet at the point where it includes B,
and A included from B of course is skipped as we already are
reading A.)
1999-08-19 07:41:39 +08:00
|
|
|
/* If the mode is NEGATIVE_CONVOL, the offset should be 128 */
|
|
|
|
if (mode == NEGATIVE_CONVOL)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
offset = 128;
|
Actually use the enum types GimpImageType, GimpImageBaseType,
* app/*.[ch]: Actually use the enum types GimpImageType,
GimpImageBaseType, LayerModeEffects, PaintApplicationMode,
BrushApplicationMode, GimpFillType and ConvertPaletteType, instead
of just int or gint. Hopefully I catched most of the places
where these should be used.
Add an enum ConvolutionType, suffix the too general constants
NORMAL, ABSOLUTE and NEGATIVE with _CONVOL. Use NORMAL_MODE
instead of NORMAL in some places (this was what was intended). Fix
some minor gccisms.
* app/apptypes.h: New file. This file contains the above
enumeration types, and some opaque struct typedefs. It was
necessary to collect these in one header that doesn't include
other headers, because when we started using the above mentioned
types in the headers, all hell broke loose because of the
spaghetti-like cross-inclusion mess between headers.
(An example: Header A includes header B, which includes header C
which includes A. B uses a type defined in A. This is not defined,
because A hasn't defined it yet at the point where it includes B,
and A included from B of course is skipped as we already are
reading A.)
1999-08-19 07:41:39 +08:00
|
|
|
mode = NORMAL_CONVOL;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
offset = 0;
|
|
|
|
|
|
|
|
/* check for the boundary cases */
|
|
|
|
if (srcR->w < (size - 1) || srcR->h < (size - 1))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Initialize some values */
|
|
|
|
bytes = srcR->bytes;
|
|
|
|
length = bytes * srcR->w;
|
|
|
|
margin = size / 2;
|
|
|
|
src = srcR->data;
|
|
|
|
dest = destR->data;
|
|
|
|
|
|
|
|
/* calculate the source wraparound value */
|
|
|
|
wraparound = srcR->rowstride - size * bytes;
|
|
|
|
|
|
|
|
/* copy the first (size / 2) scanlines of the src image... */
|
|
|
|
for (i = 0; i < margin; i++)
|
|
|
|
{
|
|
|
|
memcpy (dest, src, length);
|
|
|
|
src += srcR->rowstride;
|
|
|
|
dest += destR->rowstride;
|
|
|
|
}
|
|
|
|
|
|
|
|
src = srcR->data;
|
|
|
|
|
|
|
|
for (y = margin; y < srcR->h - margin; y++)
|
|
|
|
{
|
|
|
|
s_row = src;
|
|
|
|
s = s_row + srcR->rowstride*margin;
|
|
|
|
d = dest;
|
|
|
|
|
|
|
|
/* handle the first margin pixels... */
|
|
|
|
b = bytes * margin;
|
|
|
|
while (b --)
|
|
|
|
*d++ = *s++;
|
|
|
|
|
|
|
|
/* now, handle the center pixels */
|
|
|
|
x = srcR->w - margin*2;
|
|
|
|
while (x--)
|
|
|
|
{
|
|
|
|
s = s_row;
|
|
|
|
|
|
|
|
m = matrix;
|
|
|
|
total [0] = total [1] = total [2] = total [3] = 0;
|
|
|
|
i = size;
|
|
|
|
while (i --)
|
|
|
|
{
|
|
|
|
j = size;
|
|
|
|
while (j --)
|
|
|
|
{
|
|
|
|
for (b = 0; b < bytes; b++)
|
|
|
|
total [b] += *m * *s++;
|
|
|
|
m ++;
|
|
|
|
}
|
|
|
|
|
|
|
|
s += wraparound;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (b = 0; b < bytes; b++)
|
|
|
|
{
|
|
|
|
total [b] = total [b] / divisor + offset;
|
|
|
|
|
Actually use the enum types GimpImageType, GimpImageBaseType,
* app/*.[ch]: Actually use the enum types GimpImageType,
GimpImageBaseType, LayerModeEffects, PaintApplicationMode,
BrushApplicationMode, GimpFillType and ConvertPaletteType, instead
of just int or gint. Hopefully I catched most of the places
where these should be used.
Add an enum ConvolutionType, suffix the too general constants
NORMAL, ABSOLUTE and NEGATIVE with _CONVOL. Use NORMAL_MODE
instead of NORMAL in some places (this was what was intended). Fix
some minor gccisms.
* app/apptypes.h: New file. This file contains the above
enumeration types, and some opaque struct typedefs. It was
necessary to collect these in one header that doesn't include
other headers, because when we started using the above mentioned
types in the headers, all hell broke loose because of the
spaghetti-like cross-inclusion mess between headers.
(An example: Header A includes header B, which includes header C
which includes A. B uses a type defined in A. This is not defined,
because A hasn't defined it yet at the point where it includes B,
and A included from B of course is skipped as we already are
reading A.)
1999-08-19 07:41:39 +08:00
|
|
|
if (total [b] < 0 && mode != NORMAL_CONVOL)
|
1997-11-25 06:05:25 +08:00
|
|
|
total [b] = - total [b];
|
|
|
|
|
|
|
|
if (total [b] < 0)
|
|
|
|
*d++ = 0;
|
|
|
|
else
|
2000-12-31 22:58:08 +08:00
|
|
|
*d++ = (total [b] > 255) ? 255 : (guchar) total [b];
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
s_row += bytes;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* handle the last pixel... */
|
|
|
|
s = s_row + (srcR->rowstride + bytes) * margin;
|
|
|
|
b = bytes * margin;
|
|
|
|
while (b --)
|
|
|
|
*d++ = *s++;
|
|
|
|
|
|
|
|
/* set the memory pointers */
|
|
|
|
src += srcR->rowstride;
|
|
|
|
dest += destR->rowstride;
|
|
|
|
}
|
|
|
|
|
|
|
|
src += srcR->rowstride*margin;
|
|
|
|
|
|
|
|
/* copy the last (margin) scanlines of the src image... */
|
|
|
|
for (i = 0; i < margin; i++)
|
|
|
|
{
|
|
|
|
memcpy (dest, src, length);
|
|
|
|
src += srcR->rowstride;
|
|
|
|
dest += destR->rowstride;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1997-12-08 09:13:10 +08:00
|
|
|
/* Convert from separated alpha to premultiplied alpha. Only works on
|
|
|
|
non-tiled regions! */
|
|
|
|
void
|
|
|
|
multiply_alpha_region (PixelRegion *srcR)
|
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
guchar *src, *s;
|
|
|
|
gint x, y;
|
|
|
|
gint width, height;
|
|
|
|
gint b, bytes;
|
|
|
|
gdouble alpha_val;
|
1997-12-08 09:13:10 +08:00
|
|
|
|
|
|
|
width = srcR->w;
|
|
|
|
height = srcR->h;
|
|
|
|
bytes = srcR->bytes;
|
|
|
|
|
|
|
|
src = srcR->data;
|
|
|
|
|
|
|
|
for (y = 0; y < height; y++)
|
|
|
|
{
|
|
|
|
s = src;
|
|
|
|
for (x = 0; x < width; x++)
|
|
|
|
{
|
|
|
|
alpha_val = s[bytes - 1] * (1.0 / 255.0);
|
|
|
|
for (b = 0; b < bytes - 1; b++)
|
|
|
|
s[b] = 0.5 + s[b] * alpha_val;
|
|
|
|
s += bytes;
|
|
|
|
}
|
|
|
|
src += srcR->rowstride;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Convert from premultiplied alpha to separated alpha. Only works on
|
|
|
|
non-tiled regions! */
|
|
|
|
void
|
|
|
|
separate_alpha_region (PixelRegion *srcR)
|
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
guchar *src, *s;
|
|
|
|
gint x, y;
|
|
|
|
gint width, height;
|
|
|
|
gint b, bytes;
|
|
|
|
gdouble alpha_recip;
|
|
|
|
gint new_val;
|
1997-12-08 09:13:10 +08:00
|
|
|
|
|
|
|
width = srcR->w;
|
|
|
|
height = srcR->h;
|
|
|
|
bytes = srcR->bytes;
|
|
|
|
|
|
|
|
src = srcR->data;
|
|
|
|
|
|
|
|
for (y = 0; y < height; y++)
|
|
|
|
{
|
|
|
|
s = src;
|
|
|
|
for (x = 0; x < width; x++)
|
|
|
|
{
|
|
|
|
/* predicate is equivalent to:
|
|
|
|
(((s[bytes - 1] - 1) & 255) + 2) & 256
|
|
|
|
*/
|
|
|
|
if (s[bytes - 1] != 0 && s[bytes - 1] != 255)
|
|
|
|
{
|
|
|
|
alpha_recip = 255.0 / s[bytes - 1];
|
|
|
|
for (b = 0; b < bytes - 1; b++)
|
|
|
|
{
|
|
|
|
new_val = 0.5 + s[b] * alpha_recip;
|
|
|
|
new_val = MIN (new_val, 255);
|
|
|
|
s[b] = new_val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
s += bytes;
|
|
|
|
}
|
|
|
|
src += srcR->rowstride;
|
|
|
|
}
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
void
|
|
|
|
gaussian_blur_region (PixelRegion *srcR,
|
2000-12-31 22:58:08 +08:00
|
|
|
gdouble radius_x,
|
|
|
|
gdouble radius_y)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gdouble std_dev;
|
|
|
|
glong width, height;
|
|
|
|
gint bytes;
|
|
|
|
guchar *src, *sp;
|
|
|
|
guchar *dest, *dp;
|
|
|
|
guchar *data;
|
|
|
|
gint *buf, *b;
|
|
|
|
gint pixels;
|
|
|
|
gint total;
|
|
|
|
gint i, row, col;
|
|
|
|
gint start, end;
|
|
|
|
gint *curve;
|
|
|
|
gint *sum;
|
|
|
|
gint val;
|
|
|
|
gint length;
|
|
|
|
gint alpha;
|
|
|
|
gint initial_p, initial_m;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-05-07 07:10:29 +08:00
|
|
|
if (radius_x == 0.0 && radius_y == 0.0) return; /* zero blur is a no-op */
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* allocate the result buffer */
|
2000-01-26 07:06:12 +08:00
|
|
|
length = MAX (srcR->w, srcR->h) * srcR->bytes;
|
1997-11-25 06:05:25 +08:00
|
|
|
data = paint_funcs_get_buffer (length * 2);
|
|
|
|
src = data;
|
|
|
|
dest = data + length;
|
|
|
|
|
|
|
|
width = srcR->w;
|
|
|
|
height = srcR->h;
|
|
|
|
bytes = srcR->bytes;
|
|
|
|
alpha = bytes - 1;
|
|
|
|
|
2000-01-26 07:06:12 +08:00
|
|
|
buf = g_malloc (sizeof (int) * MAX (width, height) * 2);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-05-07 07:10:29 +08:00
|
|
|
if (radius_y != 0.0)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1999-05-07 07:10:29 +08:00
|
|
|
std_dev = sqrt (-(radius_y * radius_y) / (2 * log (1.0 / 255.0)));
|
|
|
|
curve = make_curve (std_dev, &length);
|
|
|
|
sum = g_malloc (sizeof (int) * (2 * length + 1));
|
|
|
|
sum[0] = 0;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-05-07 07:10:29 +08:00
|
|
|
for (i = 1; i <= length*2; i++)
|
|
|
|
sum[i] = curve[i-length-1] + sum[i-1];
|
|
|
|
sum += length;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-05-07 07:10:29 +08:00
|
|
|
total = sum[length] - sum[-length];
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-05-07 07:10:29 +08:00
|
|
|
for (col = 0; col < width; col++)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1999-05-07 07:10:29 +08:00
|
|
|
pixel_region_get_col (srcR, col + srcR->x, srcR->y, height, src, 1);
|
|
|
|
sp = src + alpha;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-05-07 07:10:29 +08:00
|
|
|
initial_p = sp[0];
|
|
|
|
initial_m = sp[(height-1) * bytes];
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-05-07 07:10:29 +08:00
|
|
|
/* Determine a run-length encoded version of the column */
|
|
|
|
run_length_encode (sp, buf, height, bytes);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-05-07 07:10:29 +08:00
|
|
|
for (row = 0; row < height; row++)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1999-05-07 07:10:29 +08:00
|
|
|
start = (row < length) ? -row : -length;
|
|
|
|
end = (height <= (row + length)) ? (height - row - 1) : length;
|
|
|
|
|
|
|
|
val = 0;
|
|
|
|
i = start;
|
|
|
|
b = buf + (row + i) * 2;
|
|
|
|
|
|
|
|
if (start != -length)
|
|
|
|
val += initial_p * (sum[start] - sum[-length]);
|
|
|
|
|
|
|
|
while (i < end)
|
|
|
|
{
|
|
|
|
pixels = b[0];
|
|
|
|
i += pixels;
|
|
|
|
if (i > end)
|
|
|
|
i = end;
|
|
|
|
val += b[1] * (sum[i] - sum[start]);
|
|
|
|
b += (pixels * 2);
|
|
|
|
start = i;
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-05-07 07:10:29 +08:00
|
|
|
if (end != length)
|
|
|
|
val += initial_m * (sum[length] - sum[end]);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-05-07 07:10:29 +08:00
|
|
|
sp[row * bytes] = val / total;
|
|
|
|
}
|
|
|
|
|
|
|
|
pixel_region_set_col (srcR, col + srcR->x, srcR->y, height, src);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
1999-05-07 07:10:29 +08:00
|
|
|
g_free (sum - length);
|
|
|
|
g_free (curve - length);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
1999-05-07 07:10:29 +08:00
|
|
|
if (radius_x != 0.0)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1999-05-07 07:10:29 +08:00
|
|
|
std_dev = sqrt (-(radius_x * radius_x) / (2 * log (1.0 / 255.0)));
|
|
|
|
curve = make_curve (std_dev, &length);
|
|
|
|
sum = g_malloc (sizeof (int) * (2 * length + 1));
|
|
|
|
sum[0] = 0;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-05-07 07:10:29 +08:00
|
|
|
for (i = 1; i <= length*2; i++)
|
|
|
|
sum[i] = curve[i-length-1] + sum[i-1];
|
|
|
|
sum += length;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-05-07 07:10:29 +08:00
|
|
|
total = sum[length] - sum[-length];
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-05-07 07:10:29 +08:00
|
|
|
for (row = 0; row < height; row++)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1999-05-07 07:10:29 +08:00
|
|
|
pixel_region_get_row (srcR, srcR->x, row + srcR->y, width, src, 1);
|
|
|
|
sp = src + alpha;
|
|
|
|
dp = dest + alpha;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-05-07 07:10:29 +08:00
|
|
|
initial_p = sp[0];
|
|
|
|
initial_m = sp[(width-1) * bytes];
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-05-07 07:10:29 +08:00
|
|
|
/* Determine a run-length encoded version of the row */
|
|
|
|
run_length_encode (sp, buf, width, bytes);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-05-07 07:10:29 +08:00
|
|
|
for (col = 0; col < width; col++)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1999-05-07 07:10:29 +08:00
|
|
|
start = (col < length) ? -col : -length;
|
|
|
|
end = (width <= (col + length)) ? (width - col - 1) : length;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-05-07 07:10:29 +08:00
|
|
|
val = 0;
|
|
|
|
i = start;
|
|
|
|
b = buf + (col + i) * 2;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-05-07 07:10:29 +08:00
|
|
|
if (start != -length)
|
|
|
|
val += initial_p * (sum[start] - sum[-length]);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-05-07 07:10:29 +08:00
|
|
|
while (i < end)
|
|
|
|
{
|
|
|
|
pixels = b[0];
|
|
|
|
i += pixels;
|
|
|
|
if (i > end)
|
|
|
|
i = end;
|
|
|
|
val += b[1] * (sum[i] - sum[start]);
|
|
|
|
b += (pixels * 2);
|
|
|
|
start = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (end != length)
|
|
|
|
val += initial_m * (sum[length] - sum[end]);
|
|
|
|
|
|
|
|
val = val / total;
|
|
|
|
|
|
|
|
dp[col * bytes] = val;
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-05-07 07:10:29 +08:00
|
|
|
pixel_region_set_row (srcR, srcR->x, row + srcR->y, width, dest);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free (sum - length);
|
|
|
|
g_free (curve - length);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
g_free (buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* non-interpolating scale_region. [adam]
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
scale_region_no_resample (PixelRegion *srcPR,
|
|
|
|
PixelRegion *destPR)
|
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
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;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
orig_width = srcPR->w;
|
|
|
|
orig_height = srcPR->h;
|
|
|
|
|
|
|
|
width = destPR->w;
|
|
|
|
height = destPR->h;
|
|
|
|
|
|
|
|
bytes = srcPR->bytes;
|
|
|
|
|
|
|
|
/* the data pointers... */
|
|
|
|
x_src_offsets = (int *) g_malloc (width * bytes * sizeof(int));
|
|
|
|
y_src_offsets = (int *) g_malloc (height * sizeof(int));
|
2000-12-31 22:58:08 +08:00
|
|
|
src = (guchar *) g_malloc (orig_width * bytes);
|
|
|
|
dest = (guchar *) g_malloc (width * bytes);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-08-20 18:06:54 +08:00
|
|
|
static void
|
2000-12-31 22:58:08 +08:00
|
|
|
get_premultiplied_double_row (PixelRegion *srcPR,
|
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint w,
|
|
|
|
gdouble *row,
|
|
|
|
guchar *tmp_src,
|
|
|
|
gint n)
|
1999-08-20 18:06:54 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint b;
|
|
|
|
gint bytes = srcPR->bytes;
|
|
|
|
|
1999-08-20 18:06:54 +08:00
|
|
|
pixel_region_get_row (srcPR, x, y, w, tmp_src, n);
|
2000-12-31 22:58:08 +08:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
1999-08-20 18:06:54 +08:00
|
|
|
}
|
|
|
|
else /* no alpha */
|
2000-12-31 22:58:08 +08:00
|
|
|
{
|
|
|
|
for (x = 0; x < w*bytes; x++)
|
|
|
|
row[x] = tmp_src[x];
|
|
|
|
}
|
1999-08-20 18:06:54 +08:00
|
|
|
|
|
|
|
/* set the off edge pixels to their nearest neighbor */
|
1999-08-23 17:23:24 +08:00
|
|
|
for (b = 0; b < 2 * bytes; b++)
|
|
|
|
row[-2*bytes + b] = row[(b%bytes)];
|
|
|
|
for (b = 0; b < bytes * 2; b++)
|
1999-08-20 18:06:54 +08:00
|
|
|
row[w*bytes + b] = row[(w - 1) * bytes + (b%bytes)];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-12-31 22:58:08 +08:00
|
|
|
static void
|
|
|
|
expand_line (gdouble *dest,
|
|
|
|
gdouble *src,
|
|
|
|
gint bytes,
|
|
|
|
gint old_width,
|
|
|
|
gint width,
|
|
|
|
InterpolationType interp)
|
1999-08-20 18:06:54 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gdouble ratio;
|
|
|
|
gint x,b;
|
|
|
|
gint src_col;
|
|
|
|
gdouble frac;
|
|
|
|
gdouble *s;
|
|
|
|
|
|
|
|
ratio = old_width / (gdouble) width;
|
1999-08-20 18:06:54 +08:00
|
|
|
|
|
|
|
/* this could be opimized much more by precalculating the coeficients for
|
|
|
|
each x */
|
|
|
|
switch(interp)
|
|
|
|
{
|
|
|
|
case CUBIC_INTERPOLATION:
|
|
|
|
for (x = 0; x < width; x++)
|
|
|
|
{
|
2000-04-01 10:48:00 +08:00
|
|
|
src_col = ((int)((x) * ratio + 2.0 - 0.5)) - 2;
|
1999-08-20 18:06:54 +08:00
|
|
|
/* +2, -2 is there because (int) rounds towards 0 and we need
|
|
|
|
to round down */
|
2000-04-01 10:48:00 +08:00
|
|
|
frac = ((x) * ratio - 0.5) - src_col;
|
1999-08-20 18:06:54 +08:00
|
|
|
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 LINEAR_INTERPOLATION:
|
|
|
|
for (x = 0; x < width; x++)
|
|
|
|
{
|
2000-04-01 10:48:00 +08:00
|
|
|
src_col = ((int)((x) * ratio + 2.0 - 0.5)) - 2;
|
1999-08-20 18:06:54 +08:00
|
|
|
/* +2, -2 is there because (int) rounds towards 0 and we need
|
|
|
|
to round down */
|
2000-04-01 10:48:00 +08:00
|
|
|
frac = ((x) * ratio - 0.5) - src_col;
|
1999-08-20 18:06:54 +08:00
|
|
|
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 NEAREST_NEIGHBOR_INTERPOLATION:
|
|
|
|
g_error("sampling_type can't be "
|
|
|
|
"NEAREST_NEIGHBOR_INTERPOLATION");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-12-31 22:58:08 +08:00
|
|
|
static void
|
|
|
|
shrink_line (gdouble *dest,
|
|
|
|
gdouble *src,
|
|
|
|
gint bytes,
|
|
|
|
gint old_width,
|
|
|
|
gint width,
|
|
|
|
InterpolationType interp)
|
1999-08-20 18:06:54 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint x, b;
|
|
|
|
gdouble *source, *destp;
|
|
|
|
register gdouble accum;
|
|
|
|
register guint max;
|
|
|
|
register gdouble mant, tmp;
|
|
|
|
register const gdouble step = old_width / (gdouble) width;
|
|
|
|
register const gdouble inv_step = 1.0 / step;
|
|
|
|
gdouble position;
|
|
|
|
|
2001-02-11 20:15:42 +08:00
|
|
|
fprintf(stderr, "shrink_line bytes=%d old_width=%d width=%d interp=%d "
|
|
|
|
"step=%f inv_step=%f\n",
|
|
|
|
bytes, old_width, width, interp, step, inv_step);
|
|
|
|
|
1999-08-20 18:06:54 +08:00
|
|
|
for (b = 0; b < bytes; b++)
|
|
|
|
{
|
|
|
|
|
|
|
|
source = &src[b];
|
|
|
|
destp = &dest[b];
|
|
|
|
position = -1;
|
|
|
|
|
|
|
|
mant = *source;
|
|
|
|
|
|
|
|
for (x = 0; x < width; x++)
|
|
|
|
{
|
|
|
|
source+= bytes;
|
|
|
|
accum = 0;
|
|
|
|
max = ((int)(position+step)) - ((int)(position));
|
|
|
|
max--;
|
|
|
|
while (max)
|
|
|
|
{
|
|
|
|
accum += *source;
|
|
|
|
source += bytes;
|
|
|
|
max--;
|
|
|
|
}
|
|
|
|
tmp = accum + mant;
|
|
|
|
mant = ((position+step) - (int)(position + step));
|
|
|
|
mant *= *source;
|
|
|
|
tmp += mant;
|
|
|
|
tmp *= inv_step;
|
|
|
|
mant = *source - mant;
|
|
|
|
*(destp) = tmp;
|
|
|
|
destp += bytes;
|
|
|
|
position += step;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2000-12-31 22:58:08 +08:00
|
|
|
get_scaled_row (void **src,
|
|
|
|
gint y,
|
|
|
|
gint new_width,
|
|
|
|
PixelRegion *srcPR,
|
|
|
|
gdouble *row,
|
|
|
|
guchar *src_tmp)
|
1999-08-20 18:06:54 +08:00
|
|
|
{
|
|
|
|
/* get the necesary lines from the source image, scale them,
|
|
|
|
and put them into src[] */
|
|
|
|
rotate_pointers(src, 4);
|
|
|
|
if (y < 0)
|
|
|
|
y = 0;
|
|
|
|
if (y < srcPR->h)
|
|
|
|
{
|
|
|
|
get_premultiplied_double_row(srcPR, 0, y, srcPR->w,
|
1999-08-23 17:23:24 +08:00
|
|
|
row, src_tmp, 1);
|
1999-08-20 18:06:54 +08:00
|
|
|
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);
|
1999-08-23 17:23:24 +08:00
|
|
|
else /* no scailing needed */
|
|
|
|
memcpy(src[3], row, sizeof (double) * new_width * srcPR->bytes);
|
1999-08-20 18:06:54 +08:00
|
|
|
}
|
|
|
|
else
|
1999-08-23 17:23:24 +08:00
|
|
|
memcpy(src[3], src[2], sizeof (double) * new_width * srcPR->bytes);
|
1999-08-20 18:06:54 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
void
|
|
|
|
scale_region (PixelRegion *srcPR,
|
|
|
|
PixelRegion *destPR)
|
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gdouble *src[4];
|
|
|
|
guchar *src_tmp;
|
|
|
|
guchar *dest;
|
|
|
|
double *row, *accum;
|
|
|
|
gint bytes, b;
|
|
|
|
gint width, height;
|
|
|
|
gint orig_width, orig_height;
|
|
|
|
gdouble y_rat;
|
|
|
|
gint i;
|
|
|
|
gint old_y = -4, new_y;
|
|
|
|
gint x, y;
|
1999-08-20 18:06:54 +08:00
|
|
|
|
|
|
|
if (interpolation_type == NEAREST_NEIGHBOR_INTERPOLATION)
|
|
|
|
{
|
|
|
|
scale_region_no_resample (srcPR, destPR);
|
|
|
|
return;
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
orig_width = srcPR->w;
|
|
|
|
orig_height = srcPR->h;
|
|
|
|
|
|
|
|
width = destPR->w;
|
|
|
|
height = destPR->h;
|
|
|
|
|
2001-02-11 20:15:42 +08:00
|
|
|
fprintf(stderr, "scale_region: (%d x %d) -> (%d x %d)\n",
|
|
|
|
orig_width, orig_height, width, height);
|
|
|
|
|
2000-04-01 10:48:00 +08:00
|
|
|
/* find the ratios of old y to new y */
|
1997-11-25 06:05:25 +08:00
|
|
|
y_rat = (double) orig_height / (double) height;
|
|
|
|
|
1999-08-20 18:06:54 +08:00
|
|
|
bytes = destPR->bytes;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-08-20 18:06:54 +08:00
|
|
|
/* the data pointers... */
|
|
|
|
for (i = 0; i < 4; i++)
|
1999-12-07 06:44:40 +08:00
|
|
|
src[i] = g_new (double, (width) * bytes);
|
|
|
|
dest = g_new (guchar, width * bytes);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-12-07 06:44:40 +08:00
|
|
|
src_tmp = g_new (guchar, orig_width * bytes);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-08-20 18:06:54 +08:00
|
|
|
/* offset the row pointer by 2*bytes so the range of the array
|
|
|
|
is [-2*bytes] to [(orig_width + 2)*bytes] */
|
|
|
|
row = g_new(double, (orig_width + 2*2) * bytes);
|
|
|
|
row += bytes*2;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-08-20 18:06:54 +08:00
|
|
|
accum = g_new(double, (width) * bytes);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* Scale the selected region */
|
1999-08-20 18:06:54 +08:00
|
|
|
|
|
|
|
for (y = 0; y < height; y++)
|
|
|
|
{
|
|
|
|
if (height < orig_height)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint max;
|
1999-08-20 18:06:54 +08:00
|
|
|
double frac;
|
|
|
|
const double inv_ratio = 1.0 / y_rat;
|
|
|
|
if (y == 0) /* load the first row if this it the first time through */
|
|
|
|
get_scaled_row((void **)&src[0], 0, width, srcPR, row,
|
1999-08-23 17:23:24 +08:00
|
|
|
src_tmp);
|
1999-08-20 18:06:54 +08:00
|
|
|
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);
|
|
|
|
max--;
|
|
|
|
|
|
|
|
get_scaled_row((void **)&src[0], ++new_y, width, srcPR, row,
|
1999-08-23 17:23:24 +08:00
|
|
|
src_tmp);
|
1999-08-20 18:06:54 +08:00
|
|
|
|
|
|
|
while (max > 0)
|
|
|
|
{
|
|
|
|
for (x = 0; x < width*bytes; x++)
|
|
|
|
accum[x] += src[3][x];
|
|
|
|
get_scaled_row((void **)&src[0], ++new_y, width, srcPR, row,
|
1999-08-23 17:23:24 +08:00
|
|
|
src_tmp);
|
1999-08-20 18:06:54 +08:00
|
|
|
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)
|
|
|
|
{
|
2000-04-01 10:48:00 +08:00
|
|
|
new_y = floor((y) * y_rat - .5);
|
1999-08-20 18:06:54 +08:00
|
|
|
|
|
|
|
while (old_y <= new_y)
|
|
|
|
{ /* get the necesary lines from the source image, scale them,
|
|
|
|
and put them into src[] */
|
|
|
|
get_scaled_row((void **)&src[0], old_y + 2, width, srcPR, row,
|
1999-08-23 17:23:24 +08:00
|
|
|
src_tmp);
|
1999-08-20 18:06:54 +08:00
|
|
|
old_y++;
|
|
|
|
}
|
|
|
|
switch(interpolation_type)
|
|
|
|
{
|
|
|
|
case CUBIC_INTERPOLATION:
|
|
|
|
{
|
|
|
|
double p0, p1, p2, p3;
|
2000-04-01 10:48:00 +08:00
|
|
|
double dy = ((y) * y_rat - .5) - new_y;
|
1999-08-20 18:06:54 +08:00
|
|
|
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 LINEAR_INTERPOLATION:
|
|
|
|
{
|
2000-04-01 10:48:00 +08:00
|
|
|
double idy = ((y) * y_rat - 0.5) - new_y;
|
1999-08-24 13:55:01 +08:00
|
|
|
double dy = 1.0 - idy;
|
1999-08-20 18:06:54 +08:00
|
|
|
for (x = 0; x < width * bytes; x++)
|
|
|
|
accum[x] = dy * src[1][x] + idy * src[2][x];
|
|
|
|
} break;
|
|
|
|
case NEAREST_NEIGHBOR_INTERPOLATION:
|
|
|
|
g_error("sampling_type can't be "
|
|
|
|
"NEAREST_NEIGHBOR_INTERPOLATION");
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-08-20 18:06:54 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else /* height == orig_height */
|
|
|
|
{
|
|
|
|
get_scaled_row((void **)&src[0], y, width, srcPR, row,
|
1999-08-23 17:23:24 +08:00
|
|
|
src_tmp);
|
1999-08-20 18:06:54 +08:00
|
|
|
memcpy(accum, src[3], sizeof(double) * width * bytes);
|
|
|
|
}
|
|
|
|
if (pixel_region_has_alpha(srcPR))
|
|
|
|
{ /* unmultiply the alpha */
|
|
|
|
double inv_alpha;
|
|
|
|
double *p = accum;
|
2000-12-31 22:58:08 +08:00
|
|
|
gint alpha = bytes - 1;
|
|
|
|
gint result;
|
1999-08-20 18:06:54 +08:00
|
|
|
guchar *d = dest;
|
|
|
|
for (x = 0; x < width; x++)
|
|
|
|
{
|
2000-03-18 10:44:35 +08:00
|
|
|
if (p[alpha] > 0.001)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-03-18 10:44:35 +08:00
|
|
|
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;
|
1997-11-25 06:05:25 +08:00
|
|
|
else
|
2000-03-18 10:44:35 +08:00
|
|
|
d[alpha] = result;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
2000-03-18 10:44:35 +08:00
|
|
|
else /* alpha <= 0 */
|
|
|
|
for (b = 0; b <= alpha; b++)
|
|
|
|
d[b] = 0;
|
1999-08-20 18:06:54 +08:00
|
|
|
d += bytes;
|
|
|
|
p += bytes;
|
2000-03-18 10:44:35 +08:00
|
|
|
|
1999-08-20 18:06:54 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint w = width * bytes;
|
1999-08-20 18:06:54 +08:00
|
|
|
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]);
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
1999-08-20 18:06:54 +08:00
|
|
|
pixel_region_set_row (destPR, 0, y, width, dest);
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* free up temporary arrays */
|
1999-08-20 18:06:54 +08:00
|
|
|
g_free (accum);
|
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
g_free (src[i]);
|
|
|
|
g_free (src_tmp);
|
1997-11-25 06:05:25 +08:00
|
|
|
g_free (dest);
|
1999-08-20 18:06:54 +08:00
|
|
|
row -= 2*bytes;
|
|
|
|
g_free (row);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
subsample_region (PixelRegion *srcPR,
|
|
|
|
PixelRegion *destPR,
|
2000-12-31 22:58:08 +08:00
|
|
|
gint subsample)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2001-01-24 23:36:55 +08:00
|
|
|
guchar * src, * s;
|
|
|
|
guchar * dest, * d;
|
|
|
|
gdouble * row, * r;
|
2000-12-31 22:58:08 +08:00
|
|
|
gint destwidth;
|
|
|
|
gint src_row, src_col;
|
|
|
|
gint bytes, b;
|
|
|
|
gint width, height;
|
|
|
|
gint orig_width, orig_height;
|
2001-01-24 23:36:55 +08:00
|
|
|
gdouble x_rat, y_rat;
|
|
|
|
gdouble x_cum, y_cum;
|
|
|
|
gdouble x_last, y_last;
|
|
|
|
gdouble * x_frac, y_frac, tot_frac;
|
2000-12-31 22:58:08 +08:00
|
|
|
gint i, j;
|
|
|
|
gint frac;
|
|
|
|
gint advance_dest;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
orig_width = srcPR->w / subsample;
|
|
|
|
orig_height = srcPR->h / subsample;
|
|
|
|
width = destPR->w;
|
|
|
|
height = destPR->h;
|
|
|
|
|
2001-02-11 20:15:42 +08:00
|
|
|
fprintf(stderr, "subsample_region: (%d x %d) -> (%d x %d)\n",
|
|
|
|
orig_width, orig_height, width, height);
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
/* Some calculations... */
|
|
|
|
bytes = destPR->bytes;
|
|
|
|
destwidth = destPR->rowstride;
|
|
|
|
|
|
|
|
/* the data pointers... */
|
2000-12-31 22:58:08 +08:00
|
|
|
src = (guchar *) g_malloc (orig_width * bytes);
|
1997-11-25 06:05:25 +08:00
|
|
|
dest = destPR->data;
|
|
|
|
|
|
|
|
/* find the ratios of old x to new x and old y to new y */
|
|
|
|
x_rat = (double) orig_width / (double) width;
|
|
|
|
y_rat = (double) orig_height / (double) height;
|
|
|
|
|
|
|
|
/* allocate an array to help with the calculations */
|
|
|
|
row = (double *) g_malloc (sizeof (double) * width * bytes);
|
|
|
|
x_frac = (double *) g_malloc (sizeof (double) * (width + orig_width));
|
|
|
|
|
|
|
|
/* initialize the pre-calculated pixel fraction array */
|
|
|
|
src_col = 0;
|
|
|
|
x_cum = (double) 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 (double) * width * bytes);
|
|
|
|
|
|
|
|
/* counters... */
|
|
|
|
src_row = 0;
|
|
|
|
y_cum = (double) 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 = (double) 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--)
|
2000-12-31 22:58:08 +08:00
|
|
|
*d++ = (guchar) (*r++ * tot_frac + 0.5);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
dest += destwidth;
|
|
|
|
|
|
|
|
/* clear the "row" array */
|
|
|
|
memset (row, 0, sizeof (double) * 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-01-24 23:36:55 +08:00
|
|
|
gfloat
|
1997-11-25 06:05:25 +08:00
|
|
|
shapeburst_region (PixelRegion *srcPR,
|
|
|
|
PixelRegion *distPR)
|
|
|
|
{
|
|
|
|
Tile *tile;
|
2000-12-31 22:58:08 +08:00
|
|
|
guchar *tile_data;
|
2001-01-24 23:36:55 +08:00
|
|
|
gfloat max_iterations;
|
|
|
|
gfloat *distp_cur;
|
|
|
|
gfloat *distp_prev;
|
|
|
|
gfloat *tmp;
|
|
|
|
gfloat min_prev;
|
|
|
|
gfloat float_tmp;
|
2000-12-31 22:58:08 +08:00
|
|
|
gint min;
|
|
|
|
gint min_left;
|
|
|
|
gint length;
|
|
|
|
gint i, j, k;
|
|
|
|
gint src;
|
|
|
|
gint fraction;
|
|
|
|
gint prev_frac;
|
|
|
|
gint x, y;
|
|
|
|
gint end;
|
|
|
|
gint boundary;
|
|
|
|
gint inc;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
src = 0;
|
|
|
|
|
|
|
|
max_iterations = 0.0;
|
|
|
|
|
|
|
|
length = distPR->w + 1;
|
|
|
|
distp_prev = (float *) paint_funcs_get_buffer (sizeof (float) * length * 2);
|
|
|
|
for (i = 0; i < length; i++)
|
|
|
|
distp_prev[i] = 0.0;
|
|
|
|
|
|
|
|
distp_prev += 1;
|
|
|
|
distp_cur = distp_prev + length;
|
|
|
|
|
|
|
|
for (i = 0; i < srcPR->h; i++)
|
|
|
|
{
|
|
|
|
/* set the current dist row to 0's */
|
1998-01-20 12:51:56 +08:00
|
|
|
memset(distp_cur - 1, 0, sizeof(float) * (length - 1));
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
for (j = 0; j < srcPR->w; j++)
|
|
|
|
{
|
2000-01-26 07:06:12 +08:00
|
|
|
min_prev = MIN (distp_cur[j-1], distp_prev[j]);
|
|
|
|
min_left = MIN ((srcPR->w - j - 1), (srcPR->h - i - 1));
|
|
|
|
min = (int) MIN (min_left, min_prev);
|
1997-11-25 06:05:25 +08:00
|
|
|
fraction = 255;
|
|
|
|
|
|
|
|
/* This might need to be changed to 0 instead of k = (min) ? (min - 1) : 0 */
|
|
|
|
for (k = (min) ? (min - 1) : 0; k <= min; k++)
|
|
|
|
{
|
|
|
|
x = j;
|
|
|
|
y = i + k;
|
|
|
|
end = y - k;
|
|
|
|
|
|
|
|
while (y >= end)
|
|
|
|
{
|
2001-01-23 22:21:37 +08:00
|
|
|
tile = tile_manager_get_tile (srcPR->tiles,
|
|
|
|
x, y, TRUE, FALSE);
|
|
|
|
tile_data = tile_data_pointer (tile,
|
|
|
|
x % TILE_WIDTH,
|
|
|
|
y % TILE_HEIGHT);
|
2000-01-26 07:06:12 +08:00
|
|
|
boundary = MIN ((y % TILE_HEIGHT),
|
2001-01-23 22:21:37 +08:00
|
|
|
(tile_ewidth (tile) - (x % TILE_WIDTH) - 1));
|
2000-01-26 07:06:12 +08:00
|
|
|
boundary = MIN (boundary, (y - end)) + 1;
|
2001-01-23 22:21:37 +08:00
|
|
|
inc = 1 - tile_ewidth (tile);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
while (boundary--)
|
|
|
|
{
|
|
|
|
src = *tile_data;
|
|
|
|
if (src == 0)
|
|
|
|
{
|
|
|
|
min = k;
|
|
|
|
y = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (src < fraction)
|
|
|
|
fraction = src;
|
|
|
|
|
|
|
|
x++;
|
|
|
|
y--;
|
|
|
|
tile_data += inc;
|
|
|
|
}
|
|
|
|
|
1998-07-10 10:43:12 +08:00
|
|
|
tile_release (tile, FALSE);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (src != 0)
|
|
|
|
{
|
|
|
|
/* If min_left != min_prev use the previous fraction
|
|
|
|
* if it is less than the one found
|
|
|
|
*/
|
|
|
|
if (min_left != min)
|
|
|
|
{
|
|
|
|
prev_frac = (int) (255 * (min_prev - min));
|
|
|
|
if (prev_frac == 255)
|
|
|
|
prev_frac = 0;
|
2000-01-26 07:06:12 +08:00
|
|
|
fraction = MIN (fraction, prev_frac);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
min++;
|
|
|
|
}
|
|
|
|
|
1998-01-20 12:51:56 +08:00
|
|
|
float_tmp = distp_cur[j] = min + fraction / 256.0;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-01-20 12:51:56 +08:00
|
|
|
if (float_tmp > max_iterations)
|
|
|
|
max_iterations = float_tmp;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* set the dist row */
|
2000-12-31 22:58:08 +08:00
|
|
|
pixel_region_set_row (distPR, distPR->x, distPR->y + i, distPR->w, (guchar *) distp_cur);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* swap pointers around */
|
|
|
|
tmp = distp_prev;
|
|
|
|
distp_prev = distp_cur;
|
|
|
|
distp_cur = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
return max_iterations;
|
|
|
|
}
|
|
|
|
|
1998-06-18 03:17:00 +08:00
|
|
|
static void
|
2001-01-24 23:36:55 +08:00
|
|
|
rotate_pointers (gpointer *p,
|
|
|
|
guint32 n)
|
1998-06-18 03:17:00 +08:00
|
|
|
{
|
2001-01-24 23:36:55 +08:00
|
|
|
guint32 i;
|
|
|
|
gpointer tmp;
|
|
|
|
|
1998-06-18 03:17:00 +08:00
|
|
|
tmp = p[0];
|
|
|
|
for (i = 0; i < n-1; i++)
|
2001-01-24 23:36:55 +08:00
|
|
|
{
|
|
|
|
p[i] = p[i+1];
|
|
|
|
}
|
1998-06-18 03:17:00 +08:00
|
|
|
p[i] = tmp;
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-06-18 03:17:00 +08:00
|
|
|
static void
|
2001-01-24 23:36:55 +08:00
|
|
|
compute_border (gint16 *circ,
|
|
|
|
guint16 xradius,
|
|
|
|
guint16 yradius)
|
1998-06-18 03:17:00 +08:00
|
|
|
{
|
|
|
|
gint32 i;
|
1999-03-25 16:58:30 +08:00
|
|
|
gint32 diameter = xradius*2 +1;
|
1998-06-18 03:17:00 +08:00
|
|
|
gdouble tmp;
|
2001-01-24 23:36:55 +08:00
|
|
|
|
1998-06-18 03:17:00 +08:00
|
|
|
for (i = 0; i < diameter; i++)
|
|
|
|
{
|
1999-03-25 16:58:30 +08:00
|
|
|
if (i > xradius)
|
|
|
|
tmp = (i - xradius) - .5;
|
|
|
|
else if (i < xradius)
|
|
|
|
tmp = (xradius - i) - .5;
|
1998-06-18 03:17:00 +08:00
|
|
|
else
|
|
|
|
tmp = 0.0;
|
2001-01-24 23:36:55 +08:00
|
|
|
|
|
|
|
circ[i] = RINT (yradius / (gdouble) xradius *
|
|
|
|
sqrt ((xradius) * (xradius) - (tmp) * (tmp)));
|
1998-06-18 03:17:00 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2000-12-31 22:58:08 +08:00
|
|
|
fatten_region (PixelRegion *src,
|
|
|
|
gint16 xradius,
|
|
|
|
gint16 yradius)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1998-06-18 03:17:00 +08:00
|
|
|
/*
|
|
|
|
Any bugs in this fuction are probably also in thin_region
|
2000-11-05 21:58:17 +08:00
|
|
|
Blame all bugs in this function on jaycox@gimp.org
|
1998-06-18 03:17:00 +08:00
|
|
|
*/
|
|
|
|
register gint32 i, j, x, y;
|
|
|
|
|
2000-12-31 22:58:08 +08:00
|
|
|
guchar **buf; /* caches the region's pixel data */
|
|
|
|
guchar *out; /* holds the new scan line we are computing */
|
|
|
|
guchar **max; /* caches the largest values for each column */
|
|
|
|
gint16 *circ; /* holds the y coords of the filter's mask */
|
|
|
|
gint16 last_max, last_index;
|
|
|
|
|
|
|
|
guchar *buffer;
|
1998-06-18 03:17:00 +08:00
|
|
|
|
1999-03-25 16:58:30 +08:00
|
|
|
if (xradius <= 0 || yradius <= 0)
|
1998-06-18 03:17:00 +08:00
|
|
|
return;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-03-25 16:58:30 +08:00
|
|
|
max = (guchar **)g_malloc ((src->w + 2*xradius) * sizeof(void *));
|
|
|
|
buf = (guchar **)g_malloc((yradius + 1) * sizeof(void *));
|
|
|
|
for (i = 0; i < yradius+1; i++)
|
1998-06-18 03:17:00 +08:00
|
|
|
{
|
|
|
|
buf[i] = (guchar *)g_malloc(src->w * sizeof(guchar));
|
|
|
|
}
|
1999-03-25 16:58:30 +08:00
|
|
|
buffer = g_malloc((src->w + 2*xradius)*(yradius + 1) * sizeof(guchar));
|
|
|
|
for (i = 0; i < src->w + 2*xradius; i++)
|
1998-06-18 03:17:00 +08:00
|
|
|
{
|
1999-03-25 16:58:30 +08:00
|
|
|
if (i < xradius)
|
1998-06-18 03:17:00 +08:00
|
|
|
max[i] = buffer;
|
1999-03-25 16:58:30 +08:00
|
|
|
else if (i < src->w + xradius)
|
|
|
|
max[i] = &buffer[(yradius+1)*(i - xradius)];
|
1998-06-18 03:17:00 +08:00
|
|
|
else
|
1999-03-25 16:58:30 +08:00
|
|
|
max[i] = &buffer[(yradius+1)*(src->w + xradius - 1)];
|
1998-06-18 03:17:00 +08:00
|
|
|
|
1999-03-25 16:58:30 +08:00
|
|
|
for (j = 0 ; j < xradius + 1; j++)
|
1998-06-18 03:17:00 +08:00
|
|
|
max[i][j] = 0;
|
|
|
|
}
|
2000-11-05 21:58:17 +08:00
|
|
|
/* offset the max pointer by xradius so the range of the array
|
|
|
|
is [-xradius] to [src->w + xradius] */
|
1999-03-25 16:58:30 +08:00
|
|
|
max += xradius;
|
2000-11-05 21:58:17 +08:00
|
|
|
|
1998-06-18 03:17:00 +08:00
|
|
|
out = (guchar *)g_malloc (src->w * sizeof(guchar));
|
|
|
|
|
1999-03-25 16:58:30 +08:00
|
|
|
circ = (short *)g_malloc ((2*xradius + 1) * sizeof(gint16));
|
|
|
|
compute_border (circ, xradius, yradius);
|
2000-11-05 21:58:17 +08:00
|
|
|
|
|
|
|
/* offset the circ pointer by xradius so the range of the array
|
|
|
|
is [-xradius] to [xradius] */
|
1999-03-25 16:58:30 +08:00
|
|
|
circ += xradius;
|
1998-06-18 03:17:00 +08:00
|
|
|
|
|
|
|
memset (buf[0], 0, src->w);
|
1999-03-25 16:58:30 +08:00
|
|
|
for (i = 0; i < yradius && i < src->h; i++) /* load top of image */
|
1998-06-18 03:17:00 +08:00
|
|
|
pixel_region_get_row (src, src->x, src->y + i, src->w, buf[i+1], 1);
|
|
|
|
|
|
|
|
for (x = 0; x < src->w; x++) /* set up max for top of image */
|
|
|
|
{
|
|
|
|
max[x][0] = buf[0][x];
|
1999-03-25 16:58:30 +08:00
|
|
|
for (j = 1; j < yradius+1; j++)
|
1998-06-18 03:17:00 +08:00
|
|
|
if (max[x][j] < buf[j][x])
|
|
|
|
max[x][j] = buf[j][x];
|
|
|
|
else
|
|
|
|
max[x][j] = max[x][j-1];
|
|
|
|
}
|
|
|
|
for (y = 0; y < src->h; y++)
|
|
|
|
{
|
1999-03-25 16:58:30 +08:00
|
|
|
rotate_pointers((void **)buf, yradius+1);
|
|
|
|
if (y < src->h - (yradius))
|
|
|
|
pixel_region_get_row (src, src->x, src->y + y + yradius, src->w,
|
|
|
|
buf[yradius], 1);
|
1998-06-18 03:17:00 +08:00
|
|
|
else
|
1999-03-25 16:58:30 +08:00
|
|
|
memset (buf[yradius], 0, src->w);
|
1998-06-18 03:17:00 +08:00
|
|
|
for (x = 0 ; x < src->w; x++) /* update max array */
|
|
|
|
{
|
1999-03-25 16:58:30 +08:00
|
|
|
for (i = yradius; i > 0; i--)
|
1998-06-18 03:17:00 +08:00
|
|
|
{
|
|
|
|
max[x][i] = (MAX (MAX (max[x][i - 1], buf[i-1][x]), buf[i][x]));
|
|
|
|
}
|
|
|
|
max[x][0] = buf[0][x];
|
|
|
|
}
|
|
|
|
last_max = max[0][circ[-1]];
|
|
|
|
last_index = 1;
|
|
|
|
for (x = 0 ; x < src->w; x++) /* render scan line */
|
|
|
|
{
|
|
|
|
last_index--;
|
|
|
|
if (last_index >= 0)
|
|
|
|
{
|
|
|
|
if (last_max == 255)
|
|
|
|
out[x] = 255;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
last_max = 0;
|
1999-03-25 16:58:30 +08:00
|
|
|
for (i = xradius; i >= 0; i--)
|
1998-06-18 03:17:00 +08:00
|
|
|
if (last_max < max[x+i][circ[i]])
|
|
|
|
{
|
|
|
|
last_max = max[x+i][circ[i]];
|
|
|
|
last_index = i;
|
|
|
|
}
|
|
|
|
out[x] = last_max;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-03-25 16:58:30 +08:00
|
|
|
last_index = xradius;
|
|
|
|
last_max = max[x+xradius][circ[xradius]];
|
|
|
|
for (i = xradius-1; i >= -xradius; i--)
|
1998-06-18 03:17:00 +08:00
|
|
|
if (last_max < max[x+i][circ[i]])
|
|
|
|
{
|
|
|
|
last_max = max[x+i][circ[i]];
|
|
|
|
last_index = i;
|
|
|
|
}
|
|
|
|
out[x] = last_max;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pixel_region_set_row (src, src->x, src->y + y, src->w, out);
|
|
|
|
}
|
2000-11-05 21:58:17 +08:00
|
|
|
/* undo the offsets to the pointers so we can free the malloced memmory */
|
1999-03-25 16:58:30 +08:00
|
|
|
circ -= xradius;
|
|
|
|
max -= xradius;
|
2000-11-05 21:58:17 +08:00
|
|
|
|
1998-06-18 03:17:00 +08:00
|
|
|
g_free (circ);
|
|
|
|
g_free (buffer);
|
|
|
|
g_free (max);
|
1999-03-25 16:58:30 +08:00
|
|
|
for (i = 0; i < yradius + 1; i++)
|
1998-06-18 03:17:00 +08:00
|
|
|
g_free (buf[i]);
|
|
|
|
g_free (buf);
|
|
|
|
g_free (out);
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-06-18 03:17:00 +08:00
|
|
|
void
|
2000-12-31 22:58:08 +08:00
|
|
|
thin_region (PixelRegion *src,
|
|
|
|
gint16 xradius,
|
|
|
|
gint16 yradius,
|
|
|
|
gint edge_lock)
|
1998-06-18 03:17:00 +08:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
pretty much the same as fatten_region only different
|
2000-11-05 21:58:17 +08:00
|
|
|
blame all bugs in this function on jaycox@gimp.org
|
1998-06-18 03:17:00 +08:00
|
|
|
*/
|
1999-03-25 16:58:30 +08:00
|
|
|
/* If edge_lock is true we assume that pixels outside the region
|
|
|
|
we are passed are identical to the edge pixels.
|
|
|
|
If edge_lock is false, we assume that pixels outside the region are 0
|
|
|
|
*/
|
1998-06-18 03:17:00 +08:00
|
|
|
register gint32 i, j, x, y;
|
2000-12-31 22:58:08 +08:00
|
|
|
guchar **buf; /* caches the the region's pixels */
|
|
|
|
guchar *out; /* holds the new scan line we are computing */
|
|
|
|
guchar **max; /* caches the smallest values for each column */
|
|
|
|
gint16 *circ; /* holds the y coords of the filter's mask */
|
|
|
|
gint16 last_max, last_index;
|
1998-06-18 03:17:00 +08:00
|
|
|
|
2000-12-31 22:58:08 +08:00
|
|
|
guchar *buffer;
|
1998-06-18 03:17:00 +08:00
|
|
|
|
1999-03-25 16:58:30 +08:00
|
|
|
if (xradius <= 0 || yradius <= 0)
|
1998-06-18 03:17:00 +08:00
|
|
|
return;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-03-25 16:58:30 +08:00
|
|
|
max = (guchar **)g_malloc ((src->w+2*xradius) * sizeof(void *));
|
|
|
|
buf = (guchar **)g_malloc ((yradius+1) * sizeof(void *));
|
|
|
|
for (i = 0; i < yradius+1; i++)
|
1998-06-18 03:17:00 +08:00
|
|
|
{
|
|
|
|
buf[i] = (guchar *)g_malloc (src->w * sizeof(guchar));
|
|
|
|
}
|
1999-03-25 16:58:30 +08:00
|
|
|
buffer = g_malloc ((src->w+2*xradius + 1)*(yradius+1));
|
2000-04-29 07:59:40 +08:00
|
|
|
if (edge_lock)
|
|
|
|
memset(buffer, 255, (src->w+2*xradius + 1)*(yradius+1));
|
|
|
|
else
|
|
|
|
memset(buffer, 0, (src->w+2*xradius + 1)*(yradius+1));
|
1999-03-25 16:58:30 +08:00
|
|
|
for (i = 0; i < src->w+2*xradius; i++)
|
1998-06-18 03:17:00 +08:00
|
|
|
{
|
1999-03-25 16:58:30 +08:00
|
|
|
if (i < xradius)
|
|
|
|
if (edge_lock)
|
|
|
|
max[i] = buffer;
|
|
|
|
else
|
|
|
|
max[i] = &buffer[(yradius+1)*(src->w + xradius)];
|
|
|
|
else if (i < src->w + xradius)
|
|
|
|
max[i] = &buffer[(yradius+1)*(i - xradius)];
|
1998-06-18 03:17:00 +08:00
|
|
|
else
|
1999-03-25 16:58:30 +08:00
|
|
|
if (edge_lock)
|
|
|
|
max[i] = &buffer[(yradius+1)*(src->w + xradius - 1)];
|
|
|
|
else
|
|
|
|
max[i] = &buffer[(yradius+1)*(src->w + xradius)];
|
1998-06-18 03:17:00 +08:00
|
|
|
}
|
1999-03-25 16:58:30 +08:00
|
|
|
if (!edge_lock)
|
|
|
|
for (j = 0 ; j < xradius+1; j++)
|
|
|
|
max[0][j] = 0;
|
2000-11-05 21:58:17 +08:00
|
|
|
|
|
|
|
/* offset the max pointer by xradius so the range of the array
|
|
|
|
is [-xradius] to [src->w + xradius] */
|
1999-03-25 16:58:30 +08:00
|
|
|
max += xradius;
|
2000-11-05 21:58:17 +08:00
|
|
|
|
1998-10-25 13:55:36 +08:00
|
|
|
out = (guchar *)g_malloc(src->w);
|
1998-06-18 03:17:00 +08:00
|
|
|
|
1999-03-25 16:58:30 +08:00
|
|
|
circ = (short *)g_malloc((2*xradius + 1)*sizeof(gint16));
|
|
|
|
compute_border(circ, xradius, yradius);
|
2000-11-05 21:58:17 +08:00
|
|
|
|
|
|
|
/* offset the circ pointer by xradius so the range of the array
|
|
|
|
is [-xradius] to [xradius] */
|
1999-03-25 16:58:30 +08:00
|
|
|
circ += xradius;
|
1998-06-18 03:17:00 +08:00
|
|
|
|
1999-03-25 16:58:30 +08:00
|
|
|
for (i = 0; i < yradius && i < src->h; i++) /* load top of image */
|
1998-06-18 03:17:00 +08:00
|
|
|
pixel_region_get_row (src, src->x, src->y + i, src->w, buf[i+1], 1);
|
1999-03-25 16:58:30 +08:00
|
|
|
if (edge_lock)
|
|
|
|
memcpy (buf[0], buf[1], src->w);
|
|
|
|
else
|
2000-04-29 07:59:40 +08:00
|
|
|
memset (buf[0], 0, src->w);
|
1998-06-18 03:17:00 +08:00
|
|
|
for (x = 0; x < src->w; x++) /* set up max for top of image */
|
|
|
|
{
|
|
|
|
max[x][0] = buf[0][x];
|
1999-03-25 16:58:30 +08:00
|
|
|
for (j = 1; j < yradius+1; j++)
|
1998-06-18 03:17:00 +08:00
|
|
|
if (max[x][j] > buf[j][x])
|
|
|
|
max[x][j] = buf[j][x];
|
|
|
|
else
|
|
|
|
max[x][j] = max[x][j-1];
|
|
|
|
}
|
|
|
|
for (y = 0; y < src->h; y++)
|
|
|
|
{
|
1999-03-25 16:58:30 +08:00
|
|
|
rotate_pointers ((void **)buf, yradius+1);
|
|
|
|
if (y < src->h - (yradius))
|
|
|
|
pixel_region_get_row (src, src->x, src->y + y + yradius, src->w,
|
|
|
|
buf[yradius], 1);
|
|
|
|
else if (edge_lock)
|
|
|
|
memcpy (buf[yradius], buf[yradius -1], src->w);
|
1998-06-18 03:17:00 +08:00
|
|
|
else
|
1999-03-25 16:58:30 +08:00
|
|
|
memset (buf[yradius], 0, src->w);
|
1998-06-18 03:17:00 +08:00
|
|
|
for (x = 0 ; x < src->w; x++) /* update max array */
|
|
|
|
{
|
1999-03-25 16:58:30 +08:00
|
|
|
for (i = yradius; i > 0; i--)
|
1998-06-18 03:17:00 +08:00
|
|
|
{
|
|
|
|
max[x][i] = (MIN (MIN (max[x][i - 1], buf[i-1][x]), buf[i][x]));
|
|
|
|
}
|
|
|
|
max[x][0] = buf[0][x];
|
|
|
|
}
|
|
|
|
last_max = max[0][circ[-1]];
|
1999-03-25 16:58:30 +08:00
|
|
|
last_index = 0;
|
1998-06-18 03:17:00 +08:00
|
|
|
for (x = 0 ; x < src->w; x++) /* render scan line */
|
|
|
|
{
|
|
|
|
last_index--;
|
|
|
|
if (last_index >= 0)
|
|
|
|
{
|
|
|
|
if (last_max == 0)
|
|
|
|
out[x] = 0;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
last_max = 255;
|
1999-03-25 16:58:30 +08:00
|
|
|
for (i = xradius; i >= 0; i--)
|
1998-06-18 03:17:00 +08:00
|
|
|
if (last_max > max[x+i][circ[i]])
|
|
|
|
{
|
|
|
|
last_max = max[x+i][circ[i]];
|
|
|
|
last_index = i;
|
|
|
|
}
|
|
|
|
out[x] = last_max;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-03-25 16:58:30 +08:00
|
|
|
last_index = xradius;
|
|
|
|
last_max = max[x+xradius][circ[xradius]];
|
|
|
|
for (i = xradius-1; i >= -xradius; i--)
|
1998-06-18 03:17:00 +08:00
|
|
|
if (last_max > max[x+i][circ[i]])
|
|
|
|
{
|
|
|
|
last_max = max[x+i][circ[i]];
|
|
|
|
last_index = i;
|
|
|
|
}
|
|
|
|
out[x] = last_max;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pixel_region_set_row (src, src->x, src->y + y, src->w, out);
|
|
|
|
}
|
1999-03-25 16:58:30 +08:00
|
|
|
/* undo the offsets to the pointers so we can free the malloced memmory */
|
|
|
|
circ -= xradius;
|
|
|
|
max -= xradius;
|
|
|
|
/* free the memmory */
|
1998-06-18 03:17:00 +08:00
|
|
|
g_free (circ);
|
|
|
|
g_free (buffer);
|
|
|
|
g_free (max);
|
1999-03-25 16:58:30 +08:00
|
|
|
for (i = 0; i < yradius + 1; i++)
|
1998-06-18 03:17:00 +08:00
|
|
|
g_free (buf[i]);
|
|
|
|
g_free (buf);
|
|
|
|
g_free (out);
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-06-18 03:17:00 +08:00
|
|
|
static void
|
2000-12-31 22:58:08 +08:00
|
|
|
compute_transition (guchar *transition,
|
|
|
|
guchar **buf,
|
|
|
|
gint32 width)
|
1998-06-18 03:17:00 +08:00
|
|
|
{
|
|
|
|
register gint32 x = 0;
|
2000-12-31 22:58:08 +08:00
|
|
|
|
1998-06-18 03:17:00 +08:00
|
|
|
if (width == 1)
|
|
|
|
{
|
|
|
|
if (buf[1][x] > 127 && (buf[0][x] < 128 || buf[2][x] < 128))
|
|
|
|
transition[x] = 255;
|
|
|
|
else
|
|
|
|
transition[x] = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (buf[1][x] > 127)
|
|
|
|
{
|
|
|
|
if ( buf[0][x] < 128 || buf[0][x+1] < 128 ||
|
|
|
|
buf[1][x+1] < 128 ||
|
|
|
|
buf[2][x] < 128 || buf[2][x+1] < 128 )
|
|
|
|
transition[x] = 255;
|
|
|
|
else
|
|
|
|
transition[x] = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
transition[x] = 0;
|
|
|
|
for (x = 1; x < width - 1; x++)
|
|
|
|
{
|
|
|
|
if (buf[1][x] >= 128)
|
|
|
|
{
|
|
|
|
if (buf[0][x-1] < 128 || buf[0][x] < 128 || buf[0][x+1] < 128 ||
|
|
|
|
buf[1][x-1] < 128 || buf[1][x+1] < 128 ||
|
|
|
|
buf[2][x-1] < 128 || buf[2][x] < 128 || buf[2][x+1] < 128)
|
|
|
|
transition[x] = 255;
|
|
|
|
else
|
|
|
|
transition[x] = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
transition[x] = 0;
|
|
|
|
}
|
|
|
|
if (buf[1][x] >= 128)
|
|
|
|
{
|
|
|
|
if ( buf[0][x-1] < 128 || buf[0][x] < 128 ||
|
|
|
|
buf[1][x-1] < 128 ||
|
|
|
|
buf[2][x-1] < 128 || buf[2][x] < 128)
|
|
|
|
transition[x] = 255;
|
|
|
|
else
|
|
|
|
transition[x] = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
transition[x] = 0;
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-06-18 03:17:00 +08:00
|
|
|
void
|
2000-12-31 22:58:08 +08:00
|
|
|
border_region (PixelRegion *src,
|
|
|
|
gint16 xradius,
|
|
|
|
gint16 yradius)
|
1998-06-18 03:17:00 +08:00
|
|
|
{
|
|
|
|
/*
|
1998-07-12 19:40:43 +08:00
|
|
|
This function has no bugs, but if you imagine some you can
|
2000-11-05 21:58:17 +08:00
|
|
|
blame them on jaycox@gimp.org
|
1998-06-18 03:17:00 +08:00
|
|
|
*/
|
|
|
|
register gint32 i, j, x, y;
|
|
|
|
guchar **buf, *out;
|
|
|
|
gint16 *max;
|
|
|
|
guchar **density;
|
|
|
|
guchar **transition;
|
|
|
|
guchar last_max;
|
|
|
|
gint16 last_index;
|
|
|
|
|
1999-05-05 17:10:35 +08:00
|
|
|
if (xradius < 0 || yradius < 0)
|
1998-06-18 03:17:00 +08:00
|
|
|
{
|
1999-06-06 07:41:45 +08:00
|
|
|
g_warning ("border_region: negative radius specified.");
|
1998-06-18 03:17:00 +08:00
|
|
|
return;
|
|
|
|
}
|
1999-05-05 17:10:35 +08:00
|
|
|
if (xradius == 0 || yradius == 0)
|
1998-06-18 03:17:00 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
guchar color[] = "\0\0\0\0";
|
1998-06-18 03:17:00 +08:00
|
|
|
color_region(src, color);
|
|
|
|
return;
|
|
|
|
}
|
1999-05-05 17:10:35 +08:00
|
|
|
if (xradius == 1 && yradius == 1) /* optimize this case specifically */
|
1998-06-18 03:17:00 +08:00
|
|
|
{
|
|
|
|
guchar *transition;
|
|
|
|
guchar *source[3];
|
|
|
|
for (i = 0; i < 3; i++)
|
|
|
|
source[i] = (guchar *)g_malloc ((src->w)*sizeof(guchar));
|
|
|
|
|
|
|
|
transition = (guchar *)g_malloc ((src->w)*sizeof(guchar));
|
|
|
|
|
|
|
|
pixel_region_get_row (src, src->x, src->y + 0, src->w, source[0], 1);
|
|
|
|
memcpy (source[1], source[0], src->w);
|
|
|
|
if (src->h > 1)
|
|
|
|
pixel_region_get_row (src, src->x, src->y + 1, src->w, source[2], 1);
|
|
|
|
else
|
|
|
|
memcpy (source[2], source[1], src->w);
|
|
|
|
|
|
|
|
compute_transition (transition, source, src->w);
|
|
|
|
pixel_region_set_row (src, src->x, src->y , src->w, transition);
|
|
|
|
|
|
|
|
for (y = 1; y < src->h; y++)
|
|
|
|
{
|
|
|
|
rotate_pointers ((void **)source, 3);
|
|
|
|
if (y +1 < src->h)
|
|
|
|
pixel_region_get_row (src, src->x, src->y +y +1, src->w, source[2], 1);
|
|
|
|
else
|
|
|
|
memcpy(source[2], source[1], src->w);
|
|
|
|
compute_transition (transition, source, src->w);
|
|
|
|
pixel_region_set_row (src, src->x, src->y + y, src->w, transition);
|
|
|
|
|
|
|
|
}
|
|
|
|
for (i = 0; i < 3; i++)
|
|
|
|
g_free(source[i]);
|
|
|
|
g_free(transition);
|
|
|
|
return;
|
1999-05-05 17:10:35 +08:00
|
|
|
} /* end of if (xradius == 1 && yradius == 1) */
|
|
|
|
max = (gint16 *)g_malloc ((src->w+2*xradius)*sizeof(gint16 *));
|
|
|
|
for (i = 0; i < (src->w+2*xradius); i++)
|
|
|
|
max[i] = yradius+2;
|
|
|
|
max += xradius;
|
1998-06-18 03:17:00 +08:00
|
|
|
|
|
|
|
buf = (guchar **)g_malloc ((3)*sizeof(void *));
|
|
|
|
for (i = 0; i < 3; i++)
|
|
|
|
{
|
|
|
|
buf[i] = (guchar *)g_malloc ((src->w)*sizeof(guchar));
|
|
|
|
}
|
1999-05-05 17:10:35 +08:00
|
|
|
transition = (guchar **)g_malloc ((yradius+1)*sizeof(void*));
|
|
|
|
for (i = 0; i < yradius +1; i++)
|
1998-06-18 03:17:00 +08:00
|
|
|
{
|
1999-05-05 17:10:35 +08:00
|
|
|
transition[i] = (guchar *)g_malloc (src->w+2*xradius);
|
|
|
|
memset(transition[i], 0, src->w+2*xradius);
|
|
|
|
transition[i] += xradius;
|
1998-06-18 03:17:00 +08:00
|
|
|
}
|
|
|
|
out = (guchar *)g_malloc ((src->w)*sizeof(guchar));
|
1999-05-05 17:10:35 +08:00
|
|
|
density = (guchar **)g_malloc ((2*xradius + 1)*sizeof(void *));
|
|
|
|
density += xradius;
|
1998-07-10 16:59:55 +08:00
|
|
|
|
1999-05-05 17:10:35 +08:00
|
|
|
for (x = 0; x < (xradius+1); x++) /* allocate density[][] */
|
1998-06-18 03:17:00 +08:00
|
|
|
{
|
1999-05-05 17:10:35 +08:00
|
|
|
density[ x] = (guchar *)g_malloc (2*yradius +1);
|
|
|
|
density[ x] += yradius;
|
|
|
|
density[-x] = density[x];
|
1998-07-10 16:59:55 +08:00
|
|
|
}
|
1999-05-05 17:10:35 +08:00
|
|
|
for (x = 0; x < (xradius+1); x++) /* compute density[][] */
|
1998-07-10 16:59:55 +08:00
|
|
|
{
|
1999-05-05 17:10:35 +08:00
|
|
|
register double tmpx, tmpy, dist;
|
1998-07-10 16:59:55 +08:00
|
|
|
guchar a;
|
1999-05-05 17:10:35 +08:00
|
|
|
if (x > 0)
|
|
|
|
tmpx = x - 0.5;
|
|
|
|
else if (x < 0)
|
|
|
|
tmpx = x + 0.5;
|
|
|
|
else
|
|
|
|
tmpx = 0.0;
|
|
|
|
for (y = 0; y < (yradius+1); y++)
|
1998-06-18 03:17:00 +08:00
|
|
|
{
|
|
|
|
if (y > 0)
|
|
|
|
tmpy = y - 0.5;
|
|
|
|
else if (y < 0)
|
|
|
|
tmpy = y + 0.5;
|
|
|
|
else
|
|
|
|
tmpy = 0.0;
|
1999-05-05 17:10:35 +08:00
|
|
|
dist = (tmpy*tmpy)/(yradius*yradius) + (tmpx*tmpx)/(xradius*xradius);
|
|
|
|
if (dist < 1.0)
|
|
|
|
a = 255*(1.0 - sqrt (dist));
|
1997-11-25 06:05:25 +08:00
|
|
|
else
|
1998-07-10 16:59:55 +08:00
|
|
|
a = 0;
|
|
|
|
density[ x][ y] = a;
|
|
|
|
density[ x][-y] = a;
|
1999-05-05 17:10:35 +08:00
|
|
|
density[-x][ y] = a;
|
|
|
|
density[-x][-y] = a;
|
1998-06-18 03:17:00 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pixel_region_get_row (src, src->x, src->y + 0, src->w, buf[0], 1);
|
|
|
|
memcpy (buf[1], buf[0], src->w);
|
|
|
|
if (src->h > 1)
|
|
|
|
pixel_region_get_row (src, src->x, src->y + 1, src->w, buf[2], 1);
|
|
|
|
else
|
|
|
|
memcpy (buf[2], buf[1], src->w);
|
|
|
|
compute_transition (transition[1], buf, src->w);
|
|
|
|
|
1999-05-05 17:10:35 +08:00
|
|
|
for (y = 1; y < yradius && y + 1< src->h; y++) /* set up top of image */
|
1998-06-18 03:17:00 +08:00
|
|
|
{
|
|
|
|
rotate_pointers ((void **)buf, 3);
|
|
|
|
pixel_region_get_row (src, src->x, src->y + y + 1, src->w, buf[2], 1);
|
|
|
|
compute_transition (transition[y + 1], buf, src->w);
|
|
|
|
}
|
|
|
|
for (x = 0; x < src->w; x++) /* set up max[] for top of image */
|
|
|
|
{
|
1999-05-05 17:10:35 +08:00
|
|
|
max[x] = -(yradius+7);
|
|
|
|
for (j = 1; j < yradius+1; j++)
|
1998-06-18 03:17:00 +08:00
|
|
|
if (transition[j][x])
|
|
|
|
{
|
|
|
|
max[x] = j;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (y = 0; y < src->h; y++) /* main calculation loop */
|
|
|
|
{
|
|
|
|
rotate_pointers ((void **)buf, 3);
|
1999-05-05 17:10:35 +08:00
|
|
|
rotate_pointers ((void **)transition, yradius + 1);
|
|
|
|
if (y < src->h - (yradius+1))
|
1998-06-18 03:17:00 +08:00
|
|
|
{
|
1999-05-05 17:10:35 +08:00
|
|
|
pixel_region_get_row (src, src->x, src->y + y + yradius + 1, src->w,
|
1998-06-18 03:17:00 +08:00
|
|
|
buf[2], 1);
|
1999-05-05 17:10:35 +08:00
|
|
|
compute_transition (transition[yradius], buf, src->w);
|
1998-06-18 03:17:00 +08:00
|
|
|
}
|
|
|
|
else
|
1999-05-05 17:10:35 +08:00
|
|
|
memcpy (transition[yradius], transition[yradius - 1], src->w);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-06-18 03:17:00 +08:00
|
|
|
for (x = 0; x < src->w; x++) /* update max array */
|
|
|
|
{
|
|
|
|
if (max[x] < 1)
|
|
|
|
{
|
1999-05-05 17:10:35 +08:00
|
|
|
if (max[x] <= -yradius)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1999-05-05 17:10:35 +08:00
|
|
|
if (transition[yradius][x])
|
|
|
|
max[x] = yradius;
|
1997-11-25 06:05:25 +08:00
|
|
|
else
|
1998-06-18 03:17:00 +08:00
|
|
|
max[x]--;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
1998-06-18 03:17:00 +08:00
|
|
|
else
|
|
|
|
if (transition[-max[x]][x])
|
|
|
|
max[x] = -max[x];
|
|
|
|
else if (transition[-max[x]+1][x])
|
|
|
|
max[x] = -max[x]+1;
|
|
|
|
else
|
|
|
|
max[x]--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
max[x]--;
|
1999-05-05 17:10:35 +08:00
|
|
|
if (max[x] < -yradius - 1)
|
|
|
|
max[x] = -yradius -1;
|
1998-06-18 03:17:00 +08:00
|
|
|
}
|
|
|
|
last_max = max[0][density[-1]];
|
|
|
|
last_index = 1;
|
|
|
|
for (x = 0 ; x < src->w; x++) /* render scan line */
|
|
|
|
{
|
|
|
|
last_index--;
|
|
|
|
if (last_index >= 0)
|
|
|
|
{
|
|
|
|
last_max = 0;
|
1999-05-05 17:10:35 +08:00
|
|
|
for (i = xradius; i >= 0; i--)
|
|
|
|
if (max[x+i] <= yradius && max[x+i] >= -yradius &&
|
1998-06-18 03:17:00 +08:00
|
|
|
density[i][max[x+i]] > last_max)
|
|
|
|
{
|
|
|
|
last_max = density[i][max[x+i]];
|
|
|
|
last_index = i;
|
|
|
|
}
|
|
|
|
out[x] = last_max;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
last_max = 0;
|
1999-05-05 17:10:35 +08:00
|
|
|
for (i = xradius; i >= -xradius; i--)
|
|
|
|
if (max[x+i] <= yradius && max[x+i] >= -yradius &&
|
|
|
|
density[i][max[x+i]] > last_max)
|
1998-06-18 03:17:00 +08:00
|
|
|
{
|
|
|
|
last_max = density[i][max[x+i]];
|
|
|
|
last_index = i;
|
|
|
|
}
|
|
|
|
out[x] = last_max;
|
|
|
|
}
|
|
|
|
if (last_max == 0)
|
|
|
|
{
|
|
|
|
for (i = x+1; i < src->w; i++)
|
|
|
|
{
|
1999-05-05 17:10:35 +08:00
|
|
|
if (max[i] >= -yradius)
|
1998-06-18 03:17:00 +08:00
|
|
|
break;
|
|
|
|
}
|
1999-05-05 17:10:35 +08:00
|
|
|
if (i - x > xradius)
|
1998-06-18 03:17:00 +08:00
|
|
|
{
|
1999-05-05 17:10:35 +08:00
|
|
|
for (; x < i - xradius; x++)
|
1998-06-18 03:17:00 +08:00
|
|
|
out[x] = 0;
|
|
|
|
x--;
|
|
|
|
}
|
1999-05-05 17:10:35 +08:00
|
|
|
last_index = xradius;
|
1998-06-18 03:17:00 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pixel_region_set_row (src, src->x, src->y + y, src->w, out);
|
|
|
|
}
|
|
|
|
g_free(out);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-06-18 03:17:00 +08:00
|
|
|
for (i = 0; i < 3; i++)
|
|
|
|
g_free(buf[i]);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-06-18 03:17:00 +08:00
|
|
|
g_free (buf);
|
1999-05-05 17:10:35 +08:00
|
|
|
max -= xradius;
|
1998-06-18 03:17:00 +08:00
|
|
|
g_free (max);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-05-05 17:10:35 +08:00
|
|
|
for (i = 0; i < yradius +1; i++)
|
2000-12-31 22:58:08 +08:00
|
|
|
{
|
|
|
|
transition[i] -= xradius;
|
|
|
|
g_free (transition[i]);
|
|
|
|
}
|
1998-06-18 03:17:00 +08:00
|
|
|
g_free (transition);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-05-05 17:10:35 +08:00
|
|
|
for (i = 0; i < xradius +1 ; i++)
|
2000-12-31 22:58:08 +08:00
|
|
|
{
|
|
|
|
density[i]-= yradius;
|
|
|
|
g_free(density[i]);
|
|
|
|
}
|
1999-05-05 17:10:35 +08:00
|
|
|
density -= xradius;
|
1998-06-18 03:17:00 +08:00
|
|
|
g_free(density);
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
void
|
|
|
|
swap_region (PixelRegion *src,
|
|
|
|
PixelRegion *dest)
|
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint h;
|
|
|
|
gint length;
|
|
|
|
guchar * s, * d;
|
1997-11-25 06:05:25 +08:00
|
|
|
void * pr;
|
|
|
|
|
2000-12-31 22:58:08 +08:00
|
|
|
for (pr = pixel_regions_register (2, src, dest);
|
|
|
|
pr != NULL;
|
|
|
|
pr = pixel_regions_process (pr))
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
s = src->data;
|
|
|
|
h = src->h;
|
|
|
|
d = dest->data;
|
|
|
|
length = src->w * src->bytes;
|
|
|
|
|
|
|
|
while (h --)
|
|
|
|
{
|
|
|
|
swap_pixels (s, d, length);
|
|
|
|
s += src->rowstride;
|
|
|
|
d += dest->rowstride;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-05-05 17:10:35 +08:00
|
|
|
static void
|
2000-12-31 22:58:08 +08:00
|
|
|
apply_mask_to_sub_region (gint *opacityp,
|
1999-02-01 16:22:18 +08:00
|
|
|
PixelRegion *src,
|
|
|
|
PixelRegion *mask)
|
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint h;
|
|
|
|
guchar *s;
|
|
|
|
guchar *m;
|
|
|
|
gint opacity = *opacityp;
|
1999-02-01 16:22:18 +08:00
|
|
|
|
|
|
|
s = src->data;
|
|
|
|
m = mask->data;
|
|
|
|
h = src->h;
|
|
|
|
|
|
|
|
while (h --)
|
2000-12-31 22:58:08 +08:00
|
|
|
{
|
|
|
|
apply_mask_to_alpha_channel (s, m, opacity, src->w, src->bytes);
|
|
|
|
s += src->rowstride;
|
|
|
|
m += mask->rowstride;
|
|
|
|
}
|
1999-02-01 16:22:18 +08:00
|
|
|
}
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
void
|
|
|
|
apply_mask_to_region (PixelRegion *src,
|
|
|
|
PixelRegion *mask,
|
2000-12-31 22:58:08 +08:00
|
|
|
gint opacity)
|
1999-02-01 16:22:18 +08:00
|
|
|
{
|
|
|
|
pixel_regions_process_parallel ((p_func)apply_mask_to_sub_region,
|
|
|
|
&opacity, 2, src, mask);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-05-05 17:10:35 +08:00
|
|
|
static void
|
2000-12-31 22:58:08 +08:00
|
|
|
combine_mask_and_sub_region (gint *opacityp,
|
1999-02-01 16:22:18 +08:00
|
|
|
PixelRegion *src,
|
|
|
|
PixelRegion *mask)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint h;
|
|
|
|
guchar *s;
|
|
|
|
guchar *m;
|
|
|
|
gint opacity = *opacityp;
|
1999-02-01 16:22:18 +08:00
|
|
|
|
|
|
|
s = src->data;
|
|
|
|
m = mask->data;
|
|
|
|
h = src->h;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-02-01 16:22:18 +08:00
|
|
|
while (h --)
|
|
|
|
{
|
|
|
|
combine_mask_and_alpha_channel (s, m, opacity, src->w, src->bytes);
|
|
|
|
s += src->rowstride;
|
|
|
|
m += mask->rowstride;
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
combine_mask_and_region (PixelRegion *src,
|
|
|
|
PixelRegion *mask,
|
2000-12-31 22:58:08 +08:00
|
|
|
gint opacity)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
|
1999-02-01 16:22:18 +08:00
|
|
|
pixel_regions_process_parallel ((p_func)combine_mask_and_sub_region,
|
|
|
|
&opacity, 2, src, mask);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
copy_gray_to_region (PixelRegion *src,
|
|
|
|
PixelRegion *dest)
|
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint h;
|
|
|
|
guchar *s;
|
|
|
|
guchar *d;
|
|
|
|
void *pr;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-12-31 22:58:08 +08:00
|
|
|
for (pr = pixel_regions_register (2, src, dest);
|
|
|
|
pr != NULL;
|
|
|
|
pr = pixel_regions_process (pr))
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
s = src->data;
|
|
|
|
d = dest->data;
|
|
|
|
h = src->h;
|
|
|
|
|
|
|
|
while (h --)
|
|
|
|
{
|
|
|
|
copy_gray_to_inten_a_pixels (s, d, src->w, dest->bytes);
|
|
|
|
s += src->rowstride;
|
|
|
|
d += dest->rowstride;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-02-01 16:22:18 +08:00
|
|
|
struct initial_regions_struct
|
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint opacity;
|
|
|
|
LayerModeEffects mode;
|
2001-01-24 23:36:55 +08:00
|
|
|
gboolean *affect;
|
2000-12-31 22:58:08 +08:00
|
|
|
gint type;
|
|
|
|
guchar *data;
|
1999-02-01 16:22:18 +08:00
|
|
|
};
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
void
|
2001-01-24 23:36:55 +08:00
|
|
|
initial_sub_region (struct initial_regions_struct *st,
|
|
|
|
PixelRegion *src,
|
|
|
|
PixelRegion *dest,
|
|
|
|
PixelRegion *mask)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint h;
|
|
|
|
guchar *s, *d, *m;
|
|
|
|
guchar buf[512];
|
|
|
|
guchar *data;
|
|
|
|
gint opacity;
|
|
|
|
LayerModeEffects mode;
|
2001-01-24 23:36:55 +08:00
|
|
|
gboolean *affect;
|
2000-12-31 22:58:08 +08:00
|
|
|
gint type;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2001-01-24 23:36:55 +08:00
|
|
|
data = st->data;
|
1999-02-01 16:22:18 +08:00
|
|
|
opacity = st->opacity;
|
2001-01-24 23:36:55 +08:00
|
|
|
mode = st->mode;
|
|
|
|
affect = st->affect;
|
|
|
|
type = st->type;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-02-01 16:22:18 +08:00
|
|
|
if (src->w * (src->bytes + 1) > 512)
|
2001-01-24 23:36:55 +08:00
|
|
|
g_printerr ("initial_sub_region:: error :: src->w * (src->bytes + 1) > 512\n");
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-02-01 16:22:18 +08:00
|
|
|
s = src->data;
|
|
|
|
d = dest->data;
|
|
|
|
m = (mask) ? mask->data : NULL;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-02-01 16:22:18 +08:00
|
|
|
for (h = 0; h < src->h; h++)
|
|
|
|
{
|
|
|
|
/* based on the type of the initial image... */
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case INITIAL_CHANNEL_MASK:
|
|
|
|
case INITIAL_CHANNEL_SELECTION:
|
|
|
|
initial_channel_pixels (s, d, src->w, dest->bytes);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case INITIAL_INDEXED:
|
|
|
|
initial_indexed_pixels (s, d, data, src->w);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case INITIAL_INDEXED_ALPHA:
|
|
|
|
initial_indexed_a_pixels (s, d, m, data, opacity, src->w);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case INITIAL_INTENSITY:
|
|
|
|
if (mode == DISSOLVE_MODE)
|
|
|
|
{
|
|
|
|
dissolve_pixels (s, buf, src->x, src->y + h, opacity, src->w, src->bytes,
|
|
|
|
src->bytes + 1, 0);
|
|
|
|
initial_inten_pixels (buf, d, m, opacity, affect,
|
|
|
|
src->w, src->bytes);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
initial_inten_pixels (s, d, m, opacity, affect, src->w, src->bytes);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case INITIAL_INTENSITY_ALPHA:
|
|
|
|
if (mode == DISSOLVE_MODE)
|
|
|
|
{
|
|
|
|
dissolve_pixels (s, buf, src->x, src->y + h, opacity, src->w, src->bytes,
|
|
|
|
src->bytes, 1);
|
|
|
|
initial_inten_a_pixels (buf, d, m, opacity, affect,
|
|
|
|
src->w, src->bytes);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
initial_inten_a_pixels (s, d, m, opacity, affect, src->w, src->bytes);
|
|
|
|
break;
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-02-01 16:22:18 +08:00
|
|
|
s += src->rowstride;
|
|
|
|
d += dest->rowstride;
|
|
|
|
if (mask)
|
|
|
|
m += mask->rowstride;
|
|
|
|
}
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-02-01 16:22:18 +08:00
|
|
|
void
|
2000-12-31 22:58:08 +08:00
|
|
|
initial_region (PixelRegion *src,
|
|
|
|
PixelRegion *dest,
|
|
|
|
PixelRegion *mask,
|
|
|
|
guchar *data,
|
|
|
|
gint opacity,
|
|
|
|
LayerModeEffects mode,
|
2001-01-24 23:36:55 +08:00
|
|
|
gboolean *affect,
|
2000-12-31 22:58:08 +08:00
|
|
|
gint type)
|
1999-02-01 16:22:18 +08:00
|
|
|
{
|
|
|
|
struct initial_regions_struct st;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-02-01 16:22:18 +08:00
|
|
|
st.opacity = opacity;
|
2001-01-24 23:36:55 +08:00
|
|
|
st.mode = mode;
|
|
|
|
st.affect = affect;
|
|
|
|
st.type = type;
|
|
|
|
st.data = data;
|
1999-02-01 16:22:18 +08:00
|
|
|
|
|
|
|
pixel_regions_process_parallel ((p_func)initial_sub_region, &st, 3,
|
|
|
|
src, dest, mask);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
1999-01-23 07:46:44 +08:00
|
|
|
struct combine_regions_struct
|
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint opacity;
|
|
|
|
LayerModeEffects mode;
|
2001-01-24 23:36:55 +08:00
|
|
|
gboolean *affect;
|
2000-12-31 22:58:08 +08:00
|
|
|
gint type;
|
|
|
|
guchar *data;
|
2001-01-24 23:36:55 +08:00
|
|
|
gboolean has_alpha1, has_alpha2;
|
2000-12-31 22:58:08 +08:00
|
|
|
gboolean opacity_quickskip_possible;
|
|
|
|
gboolean transparency_quickskip_possible;
|
1999-01-23 07:46:44 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2000-12-31 22:58:08 +08:00
|
|
|
combine_sub_region (struct combine_regions_struct *st,
|
|
|
|
PixelRegion *src1,
|
|
|
|
PixelRegion *src2,
|
|
|
|
PixelRegion *dest,
|
|
|
|
PixelRegion *mask)
|
1999-01-23 07:46:44 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
guchar *data;
|
|
|
|
gint opacity;
|
|
|
|
LayerModeEffects mode;
|
2001-01-24 23:36:55 +08:00
|
|
|
gboolean *affect;
|
2000-12-31 22:58:08 +08:00
|
|
|
gint type;
|
|
|
|
gint h;
|
2001-01-24 23:36:55 +08:00
|
|
|
gboolean has_alpha1, has_alpha2;
|
2000-12-31 22:58:08 +08:00
|
|
|
gint combine = 0;
|
|
|
|
gint mode_affect;
|
|
|
|
guchar *s, *s1, *s2;
|
|
|
|
guchar *d, *m;
|
|
|
|
guchar buf[512];
|
|
|
|
gboolean opacity_quickskip_possible;
|
|
|
|
gboolean transparency_quickskip_possible;
|
|
|
|
TileRowHint hint;
|
1999-01-23 07:46:44 +08:00
|
|
|
|
2001-01-24 23:36:55 +08:00
|
|
|
opacity = st->opacity;
|
|
|
|
mode = st->mode;
|
|
|
|
affect = st->affect;
|
|
|
|
type = st->type;
|
|
|
|
data = st->data;
|
1999-01-23 07:46:44 +08:00
|
|
|
has_alpha1 = st->has_alpha1;
|
|
|
|
has_alpha2 = st->has_alpha2;
|
|
|
|
|
1999-05-23 20:51:12 +08:00
|
|
|
opacity_quickskip_possible = (st->opacity_quickskip_possible &&
|
|
|
|
src2->tiles);
|
|
|
|
transparency_quickskip_possible = (st->transparency_quickskip_possible &&
|
|
|
|
src2->tiles);
|
|
|
|
|
1999-01-23 07:46:44 +08:00
|
|
|
s1 = src1->data;
|
|
|
|
s2 = src2->data;
|
|
|
|
d = dest->data;
|
|
|
|
m = (mask) ? mask->data : NULL;
|
|
|
|
|
|
|
|
if (src1->w > 128)
|
1999-02-01 01:58:16 +08:00
|
|
|
g_error("combine_sub_region::src1->w = %d\n", src1->w);
|
1999-01-23 07:46:44 +08:00
|
|
|
|
1999-05-23 20:51:12 +08:00
|
|
|
if (transparency_quickskip_possible || opacity_quickskip_possible)
|
1999-01-23 07:46:44 +08:00
|
|
|
{
|
1999-05-09 23:45:37 +08:00
|
|
|
#ifdef HINTS_SANITY
|
|
|
|
if (src1->h != src2->h)
|
|
|
|
g_error("HEIGHTS SUCK!!");
|
|
|
|
if (src1->offy != dest->offy)
|
|
|
|
g_error("SRC1 OFFSET != DEST OFFSET");
|
|
|
|
#endif
|
|
|
|
update_tile_rowhints (src2->curtile,
|
|
|
|
src2->offy, src2->offy + (src1->h - 1));
|
1999-01-23 07:46:44 +08:00
|
|
|
}
|
1999-05-09 23:45:37 +08:00
|
|
|
/* else it's probably a brush-composite */
|
1999-01-23 07:46:44 +08:00
|
|
|
|
1999-05-09 23:45:37 +08:00
|
|
|
for (h = 0; h < src1->h; h++)
|
1999-01-23 07:46:44 +08:00
|
|
|
{
|
1999-05-09 23:45:37 +08:00
|
|
|
hint = TILEROWHINT_UNDEFINED;
|
1999-01-23 07:46:44 +08:00
|
|
|
|
1999-05-23 09:46:08 +08:00
|
|
|
if (transparency_quickskip_possible)
|
1999-05-09 23:45:37 +08:00
|
|
|
{
|
1999-05-23 09:46:08 +08:00
|
|
|
hint = tile_get_rowhint (src2->curtile, (src2->offy + h));
|
|
|
|
|
|
|
|
if (hint == TILEROWHINT_TRANSPARENT)
|
|
|
|
{
|
|
|
|
goto next_row;
|
|
|
|
}
|
1999-05-09 23:45:37 +08:00
|
|
|
}
|
1999-05-23 09:46:08 +08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if (opacity_quickskip_possible)
|
|
|
|
{
|
|
|
|
hint = tile_get_rowhint (src2->curtile, (src2->offy + h));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-05-09 23:45:37 +08:00
|
|
|
s = buf;
|
1999-01-23 07:46:44 +08:00
|
|
|
|
1999-05-09 23:45:37 +08:00
|
|
|
/* apply the paint mode based on the combination type & mode */
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case COMBINE_INTEN_A_INDEXED_A:
|
|
|
|
case COMBINE_INTEN_A_CHANNEL_MASK:
|
|
|
|
case COMBINE_INTEN_A_CHANNEL_SELECTION:
|
|
|
|
combine = type;
|
|
|
|
break;
|
1999-01-23 07:46:44 +08:00
|
|
|
|
1999-05-09 23:45:37 +08:00
|
|
|
case COMBINE_INDEXED_INDEXED:
|
|
|
|
case COMBINE_INDEXED_INDEXED_A:
|
|
|
|
case COMBINE_INDEXED_A_INDEXED_A:
|
|
|
|
/* Now, apply the paint mode--for indexed images */
|
1999-05-23 20:51:12 +08:00
|
|
|
combine = apply_indexed_layer_mode (s1, s2, &s, mode,
|
|
|
|
has_alpha1, has_alpha2);
|
1999-05-09 23:45:37 +08:00
|
|
|
break;
|
1999-01-23 07:46:44 +08:00
|
|
|
|
1999-05-09 23:45:37 +08:00
|
|
|
case COMBINE_INTEN_INTEN_A:
|
|
|
|
case COMBINE_INTEN_A_INTEN:
|
|
|
|
case COMBINE_INTEN_INTEN:
|
|
|
|
case COMBINE_INTEN_A_INTEN_A:
|
|
|
|
/* Now, apply the paint mode */
|
1999-05-23 20:51:12 +08:00
|
|
|
combine = apply_layer_mode (s1, s2, &s, src1->x, src1->y + h,
|
|
|
|
opacity, src1->w, mode,
|
|
|
|
src1->bytes, src2->bytes,
|
|
|
|
has_alpha1, has_alpha2, &mode_affect);
|
1999-05-09 23:45:37 +08:00
|
|
|
break;
|
1999-01-23 07:46:44 +08:00
|
|
|
|
1999-05-09 23:45:37 +08:00
|
|
|
default:
|
|
|
|
g_warning ("combine_sub_region: unhandled combine-type.");
|
|
|
|
break;
|
|
|
|
}
|
1999-01-23 07:46:44 +08:00
|
|
|
|
1999-05-09 23:45:37 +08:00
|
|
|
/* based on the type of the initial image... */
|
|
|
|
switch (combine)
|
|
|
|
{
|
|
|
|
case COMBINE_INDEXED_INDEXED:
|
|
|
|
combine_indexed_and_indexed_pixels (s1, s2, d, m, opacity,
|
|
|
|
affect, src1->w,
|
|
|
|
src1->bytes);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case COMBINE_INDEXED_INDEXED_A:
|
|
|
|
combine_indexed_and_indexed_a_pixels (s1, s2, d, m, opacity,
|
|
|
|
affect, src1->w,
|
|
|
|
src1->bytes);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case COMBINE_INDEXED_A_INDEXED_A:
|
|
|
|
combine_indexed_a_and_indexed_a_pixels (s1, s2, d, m, opacity,
|
|
|
|
affect, src1->w,
|
|
|
|
src1->bytes);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case COMBINE_INTEN_A_INDEXED_A:
|
|
|
|
/* assume the data passed to this procedure is the
|
|
|
|
* indexed layer's colormap
|
|
|
|
*/
|
|
|
|
combine_inten_a_and_indexed_a_pixels (s1, s2, d, m, data, opacity,
|
|
|
|
src1->w, dest->bytes);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case COMBINE_INTEN_A_CHANNEL_MASK:
|
|
|
|
/* assume the data passed to this procedure is the
|
|
|
|
* indexed layer's colormap
|
|
|
|
*/
|
|
|
|
combine_inten_a_and_channel_mask_pixels (s1, s2, d, data, opacity,
|
|
|
|
src1->w, dest->bytes);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case COMBINE_INTEN_A_CHANNEL_SELECTION:
|
|
|
|
combine_inten_a_and_channel_selection_pixels (s1, s2, d, data,
|
|
|
|
opacity,
|
|
|
|
src1->w,
|
|
|
|
src1->bytes);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case COMBINE_INTEN_INTEN:
|
|
|
|
if ((hint == TILEROWHINT_OPAQUE) &&
|
|
|
|
opacity_quickskip_possible)
|
|
|
|
{
|
|
|
|
memcpy (d, s, dest->w * dest->bytes);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
combine_inten_and_inten_pixels (s1, s, d, m, opacity,
|
|
|
|
affect, src1->w, src1->bytes);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case COMBINE_INTEN_INTEN_A:
|
|
|
|
combine_inten_and_inten_a_pixels (s1, s, d, m, opacity,
|
|
|
|
affect, src1->w, src1->bytes);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case COMBINE_INTEN_A_INTEN:
|
|
|
|
combine_inten_a_and_inten_pixels (s1, s, d, m, opacity,
|
|
|
|
affect, mode_affect, src1->w,
|
|
|
|
src1->bytes);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case COMBINE_INTEN_A_INTEN_A:
|
|
|
|
if ((hint == TILEROWHINT_OPAQUE) &&
|
|
|
|
opacity_quickskip_possible)
|
|
|
|
{
|
|
|
|
memcpy (d, s, dest->w * dest->bytes);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
combine_inten_a_and_inten_a_pixels (s1, s, d, m, opacity,
|
|
|
|
affect, mode_affect,
|
|
|
|
src1->w, src1->bytes);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BEHIND_INTEN:
|
|
|
|
behind_inten_pixels (s1, s, d, m, opacity,
|
1999-01-23 07:46:44 +08:00
|
|
|
affect, src1->w, src1->bytes,
|
|
|
|
src2->bytes, has_alpha1, has_alpha2);
|
1999-05-09 23:45:37 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case BEHIND_INDEXED:
|
|
|
|
behind_indexed_pixels (s1, s, d, m, opacity,
|
|
|
|
affect, src1->w, src1->bytes,
|
|
|
|
src2->bytes, has_alpha1, has_alpha2);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case REPLACE_INTEN:
|
|
|
|
replace_inten_pixels (s1, s, d, m, opacity,
|
|
|
|
affect, src1->w, src1->bytes,
|
|
|
|
src2->bytes, has_alpha1, has_alpha2);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case REPLACE_INDEXED:
|
|
|
|
replace_indexed_pixels (s1, s, d, m, opacity,
|
|
|
|
affect, src1->w, src1->bytes,
|
|
|
|
src2->bytes, has_alpha1, has_alpha2);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ERASE_INTEN:
|
|
|
|
erase_inten_pixels (s1, s, d, m, opacity,
|
|
|
|
affect, src1->w, src1->bytes);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ERASE_INDEXED:
|
|
|
|
erase_indexed_pixels (s1, s, d, m, opacity,
|
|
|
|
affect, src1->w, src1->bytes);
|
|
|
|
break;
|
|
|
|
|
1999-08-14 05:16:02 +08:00
|
|
|
case ANTI_ERASE_INTEN:
|
|
|
|
anti_erase_inten_pixels (s1, s, d, m, opacity,
|
|
|
|
affect, src1->w, src1->bytes);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ANTI_ERASE_INDEXED:
|
|
|
|
anti_erase_indexed_pixels (s1, s, d, m, opacity,
|
|
|
|
affect, src1->w, src1->bytes);
|
|
|
|
break;
|
|
|
|
|
1999-05-09 23:45:37 +08:00
|
|
|
case NO_COMBINATION:
|
|
|
|
g_warning("NO_COMBINATION");
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
g_warning("UNKNOWN COMBINATION");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
next_row:
|
|
|
|
s1 += src1->rowstride;
|
|
|
|
s2 += src2->rowstride;
|
|
|
|
d += dest->rowstride;
|
|
|
|
if (mask)
|
|
|
|
m += mask->rowstride;
|
1999-01-23 07:46:44 +08:00
|
|
|
}
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-05-09 23:45:37 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
void
|
2000-12-31 22:58:08 +08:00
|
|
|
combine_regions (PixelRegion *src1,
|
|
|
|
PixelRegion *src2,
|
|
|
|
PixelRegion *dest,
|
|
|
|
PixelRegion *mask,
|
|
|
|
guchar *data,
|
|
|
|
gint opacity,
|
|
|
|
LayerModeEffects mode,
|
2001-01-24 23:36:55 +08:00
|
|
|
gboolean *affect,
|
2000-12-31 22:58:08 +08:00
|
|
|
gint type)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2001-01-24 23:36:55 +08:00
|
|
|
gboolean has_alpha1, has_alpha2;
|
2000-12-31 22:58:08 +08:00
|
|
|
gint i;
|
1999-01-23 07:46:44 +08:00
|
|
|
struct combine_regions_struct st;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* Determine which sources have alpha channels */
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case COMBINE_INTEN_INTEN:
|
|
|
|
case COMBINE_INDEXED_INDEXED:
|
2001-01-24 23:36:55 +08:00
|
|
|
has_alpha1 = has_alpha2 = FALSE;
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
|
|
|
case COMBINE_INTEN_A_INTEN:
|
2001-01-24 23:36:55 +08:00
|
|
|
has_alpha1 = TRUE;
|
|
|
|
has_alpha2 = FALSE;
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
|
|
|
case COMBINE_INTEN_INTEN_A:
|
|
|
|
case COMBINE_INDEXED_INDEXED_A:
|
2001-01-24 23:36:55 +08:00
|
|
|
has_alpha1 = FALSE;
|
|
|
|
has_alpha2 = TRUE;
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
|
|
|
case COMBINE_INTEN_A_INTEN_A:
|
|
|
|
case COMBINE_INDEXED_A_INDEXED_A:
|
2001-01-24 23:36:55 +08:00
|
|
|
has_alpha1 = has_alpha2 = TRUE;
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
|
|
|
default:
|
2001-01-24 23:36:55 +08:00
|
|
|
has_alpha1 = has_alpha2 = FALSE;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
2001-01-24 23:36:55 +08:00
|
|
|
st.opacity = opacity;
|
|
|
|
st.mode = mode;
|
|
|
|
st.affect = affect;
|
|
|
|
st.type = type;
|
|
|
|
st.data = data;
|
1999-01-23 07:46:44 +08:00
|
|
|
st.has_alpha1 = has_alpha1;
|
|
|
|
st.has_alpha2 = has_alpha2;
|
1999-05-23 20:51:12 +08:00
|
|
|
|
|
|
|
/* cheap and easy when the row of src2 is completely opaque/transparent
|
1999-06-19 01:34:29 +08:00
|
|
|
and the wind is otherwise blowing in the right direction.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* First check - we can't do an opacity quickskip if the drawable
|
|
|
|
has a mask, or non-full opacity, or the layer mode dictates
|
|
|
|
that we might gain transparency.
|
|
|
|
*/
|
2001-01-24 23:36:55 +08:00
|
|
|
st.opacity_quickskip_possible = ((!mask) &&
|
|
|
|
(opacity == 255) &&
|
1999-05-23 20:51:12 +08:00
|
|
|
(!layer_modes[mode].decrease_opacity) &&
|
2001-01-24 23:36:55 +08:00
|
|
|
(layer_modes[mode].affect_alpha &&
|
|
|
|
has_alpha1 &&
|
|
|
|
affect[src1->bytes - 1]));
|
1999-06-19 01:34:29 +08:00
|
|
|
|
|
|
|
/* Second check - if any single colour channel can't be affected,
|
|
|
|
we can't use the opacity quickskip.
|
|
|
|
*/
|
|
|
|
if (st.opacity_quickskip_possible)
|
|
|
|
{
|
2001-01-24 23:36:55 +08:00
|
|
|
for (i = 0; i < src1->bytes - 1; i++)
|
1999-06-19 01:34:29 +08:00
|
|
|
{
|
|
|
|
if (!affect[i])
|
|
|
|
{
|
|
|
|
st.opacity_quickskip_possible = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* transparency quickskip is only possible if the layer mode
|
|
|
|
dictates that we cannot possibly gain opacity, or the 'overall'
|
|
|
|
opacity of the layer is set to zero anyway.
|
|
|
|
*/
|
1999-05-23 20:51:12 +08:00
|
|
|
st.transparency_quickskip_possible = ((!layer_modes[mode].increase_opacity)
|
|
|
|
|| (opacity==0));
|
1999-06-19 01:34:29 +08:00
|
|
|
|
|
|
|
/* Start the actual processing.
|
|
|
|
*/
|
1999-01-23 07:46:44 +08:00
|
|
|
pixel_regions_process_parallel ((p_func)combine_sub_region, &st, 4,
|
|
|
|
src1, src2, dest, mask);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
1997-12-08 09:13:10 +08:00
|
|
|
void
|
2000-12-31 22:58:08 +08:00
|
|
|
combine_regions_replace (PixelRegion *src1,
|
|
|
|
PixelRegion *src2,
|
|
|
|
PixelRegion *dest,
|
|
|
|
PixelRegion *mask,
|
|
|
|
guchar *data,
|
|
|
|
gint opacity,
|
2001-01-24 23:36:55 +08:00
|
|
|
gboolean *affect,
|
2000-12-31 22:58:08 +08:00
|
|
|
gint type)
|
1997-12-08 09:13:10 +08:00
|
|
|
{
|
2001-01-24 23:36:55 +08:00
|
|
|
gint h;
|
|
|
|
guchar *s1;
|
|
|
|
guchar *s2;
|
|
|
|
guchar *d;
|
|
|
|
guchar *m;
|
|
|
|
gpointer pr;
|
1997-12-08 09:13:10 +08:00
|
|
|
|
2000-12-31 22:58:08 +08:00
|
|
|
for (pr = pixel_regions_register (4, src1, src2, dest, mask);
|
|
|
|
pr != NULL;
|
|
|
|
pr = pixel_regions_process (pr))
|
1997-12-08 09:13:10 +08:00
|
|
|
{
|
|
|
|
s1 = src1->data;
|
|
|
|
s2 = src2->data;
|
|
|
|
d = dest->data;
|
|
|
|
m = mask->data;
|
|
|
|
|
|
|
|
for (h = 0; h < src1->h; h++)
|
|
|
|
{
|
|
|
|
|
|
|
|
/* Now, apply the paint mode */
|
2000-12-31 22:58:08 +08:00
|
|
|
apply_layer_mode_replace (s1, s2, d, m, src1->x, src1->y + h,
|
|
|
|
opacity, src1->w,
|
|
|
|
src1->bytes, src2->bytes, affect);
|
1997-12-08 09:13:10 +08:00
|
|
|
|
|
|
|
s1 += src1->rowstride;
|
|
|
|
s2 += src2->rowstride;
|
|
|
|
d += dest->rowstride;
|
|
|
|
m += mask->rowstride;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
/************************************/
|
|
|
|
/* apply layer modes */
|
|
|
|
/************************************/
|
|
|
|
|
2000-12-31 22:58:08 +08:00
|
|
|
gint
|
|
|
|
apply_layer_mode (guchar *src1,
|
|
|
|
guchar *src2,
|
|
|
|
guchar **dest,
|
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint opacity,
|
|
|
|
gint length,
|
|
|
|
LayerModeEffects mode,
|
2001-01-24 23:36:55 +08:00
|
|
|
gint bytes1,
|
|
|
|
gint bytes2,
|
|
|
|
gboolean has_alpha1,
|
|
|
|
gboolean has_alpha2,
|
2000-12-31 22:58:08 +08:00
|
|
|
gint *mode_affect)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint combine;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
if (!has_alpha1 && !has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
combine = COMBINE_INTEN_INTEN;
|
1998-09-15 09:53:40 +08:00
|
|
|
else if (!has_alpha1 && has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
combine = COMBINE_INTEN_INTEN_A;
|
1998-09-15 09:53:40 +08:00
|
|
|
else if (has_alpha1 && !has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
combine = COMBINE_INTEN_A_INTEN;
|
|
|
|
else
|
|
|
|
combine = COMBINE_INTEN_A_INTEN_A;
|
|
|
|
|
|
|
|
/* assumes we're applying src2 TO src1 */
|
|
|
|
switch (mode)
|
|
|
|
{
|
|
|
|
case NORMAL_MODE:
|
|
|
|
*dest = src2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DISSOLVE_MODE:
|
|
|
|
/* Since dissolve requires an alpha channels... */
|
1998-09-15 09:53:40 +08:00
|
|
|
if (! has_alpha2)
|
|
|
|
add_alpha_pixels (src2, *dest, length, bytes2);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
dissolve_pixels (src2, *dest, x, y, opacity, length, bytes2,
|
|
|
|
((has_alpha2) ? bytes2 : bytes2 + 1), has_alpha2);
|
|
|
|
combine = (has_alpha1) ? COMBINE_INTEN_A_INTEN_A : COMBINE_INTEN_INTEN_A;
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MULTIPLY_MODE:
|
1998-09-15 09:53:40 +08:00
|
|
|
multiply_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2);
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
|
|
|
|
1998-06-09 12:04:43 +08:00
|
|
|
case DIVIDE_MODE:
|
1998-09-15 09:53:40 +08:00
|
|
|
divide_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2);
|
1998-06-09 12:04:43 +08:00
|
|
|
break;
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
case SCREEN_MODE:
|
1998-09-15 09:53:40 +08:00
|
|
|
screen_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2);
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case OVERLAY_MODE:
|
1998-09-15 09:53:40 +08:00
|
|
|
overlay_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2);
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DIFFERENCE_MODE:
|
1998-09-15 09:53:40 +08:00
|
|
|
difference_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2);
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ADDITION_MODE:
|
1998-09-15 09:53:40 +08:00
|
|
|
add_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2);
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SUBTRACT_MODE:
|
1998-09-15 09:53:40 +08:00
|
|
|
subtract_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2);
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DARKEN_ONLY_MODE:
|
1998-09-15 09:53:40 +08:00
|
|
|
darken_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2);
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case LIGHTEN_ONLY_MODE:
|
1998-09-15 09:53:40 +08:00
|
|
|
lighten_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2);
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case HUE_MODE: case SATURATION_MODE: case VALUE_MODE:
|
|
|
|
/* only works on RGB color images */
|
1998-09-15 09:53:40 +08:00
|
|
|
if (bytes1 > 2)
|
|
|
|
hsv_only_pixels (src1, src2, *dest, mode, length, bytes1, bytes2, has_alpha1, has_alpha2);
|
1997-11-25 06:05:25 +08:00
|
|
|
else
|
|
|
|
*dest = src2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case COLOR_MODE:
|
|
|
|
/* only works on RGB color images */
|
1998-09-15 09:53:40 +08:00
|
|
|
if (bytes1 > 2)
|
|
|
|
color_only_pixels (src1, src2, *dest, mode, length, bytes1, bytes2, has_alpha1, has_alpha2);
|
1997-11-25 06:05:25 +08:00
|
|
|
else
|
|
|
|
*dest = src2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BEHIND_MODE:
|
|
|
|
*dest = src2;
|
1998-09-15 09:53:40 +08:00
|
|
|
if (has_alpha1)
|
1997-11-25 06:05:25 +08:00
|
|
|
combine = BEHIND_INTEN;
|
|
|
|
else
|
|
|
|
combine = NO_COMBINATION;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case REPLACE_MODE:
|
|
|
|
*dest = src2;
|
|
|
|
combine = REPLACE_INTEN;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ERASE_MODE:
|
|
|
|
*dest = src2;
|
|
|
|
/* If both sources have alpha channels, call erase function.
|
|
|
|
* Otherwise, just combine in the normal manner
|
|
|
|
*/
|
1998-09-15 09:53:40 +08:00
|
|
|
combine = (has_alpha1 && has_alpha2) ? ERASE_INTEN : combine;
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
|
|
|
|
1999-08-14 05:16:02 +08:00
|
|
|
case ANTI_ERASE_MODE:
|
|
|
|
*dest = src2;
|
|
|
|
combine = (has_alpha1 && has_alpha2) ? ANTI_ERASE_INTEN : combine;
|
|
|
|
break;
|
|
|
|
|
2001-01-09 10:45:27 +08:00
|
|
|
case DODGE_MODE:
|
|
|
|
dodge_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BURN_MODE:
|
|
|
|
burn_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case HARDLIGHT_MODE:
|
|
|
|
hardlight_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2);
|
|
|
|
break;
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
default :
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Determine whether the alpha channel of the destination can be affected
|
|
|
|
* by the specified mode--This keeps consistency with varying opacities
|
|
|
|
*/
|
|
|
|
*mode_affect = layer_modes[mode].affect_alpha;
|
|
|
|
|
|
|
|
return combine;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-01-24 23:36:55 +08:00
|
|
|
gint
|
2000-12-31 22:58:08 +08:00
|
|
|
apply_indexed_layer_mode (guchar *src1,
|
|
|
|
guchar *src2,
|
|
|
|
guchar **dest,
|
|
|
|
LayerModeEffects mode,
|
2001-01-24 23:36:55 +08:00
|
|
|
gboolean has_alpha1, /* has alpha */
|
|
|
|
gboolean has_alpha2) /* has alpha */
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-12-31 22:58:08 +08:00
|
|
|
gint combine;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-09-15 09:53:40 +08:00
|
|
|
if (!has_alpha1 && !has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
combine = COMBINE_INDEXED_INDEXED;
|
1998-09-15 09:53:40 +08:00
|
|
|
else if (!has_alpha1 && has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
combine = COMBINE_INDEXED_INDEXED_A;
|
1998-09-15 09:53:40 +08:00
|
|
|
else if (has_alpha1 && has_alpha2)
|
1997-11-25 06:05:25 +08:00
|
|
|
combine = COMBINE_INDEXED_A_INDEXED_A;
|
|
|
|
else
|
|
|
|
combine = NO_COMBINATION;
|
|
|
|
|
|
|
|
/* assumes we're applying src2 TO src1 */
|
|
|
|
switch (mode)
|
|
|
|
{
|
|
|
|
case REPLACE_MODE:
|
|
|
|
*dest = src2;
|
|
|
|
combine = REPLACE_INDEXED;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BEHIND_MODE:
|
|
|
|
*dest = src2;
|
1998-09-15 09:53:40 +08:00
|
|
|
if (has_alpha1)
|
1997-11-25 06:05:25 +08:00
|
|
|
combine = BEHIND_INDEXED;
|
|
|
|
else
|
|
|
|
combine = NO_COMBINATION;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ERASE_MODE:
|
|
|
|
*dest = src2;
|
|
|
|
/* If both sources have alpha channels, call erase function.
|
|
|
|
* Otherwise, just combine in the normal manner
|
|
|
|
*/
|
1998-09-15 09:53:40 +08:00
|
|
|
combine = (has_alpha1 && has_alpha2) ? ERASE_INDEXED : combine;
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return combine;
|
|
|
|
}
|
1997-12-08 09:13:10 +08:00
|
|
|
|
|
|
|
static void
|
2001-01-24 23:36:55 +08:00
|
|
|
apply_layer_mode_replace (guchar *src1,
|
|
|
|
guchar *src2,
|
|
|
|
guchar *dest,
|
|
|
|
guchar *mask,
|
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint opacity,
|
|
|
|
gint length,
|
|
|
|
gint bytes1,
|
|
|
|
gint bytes2,
|
|
|
|
gboolean *affect)
|
1997-12-08 09:13:10 +08:00
|
|
|
{
|
1998-09-15 09:53:40 +08:00
|
|
|
replace_pixels (src1, src2, dest, mask, length, opacity, affect, bytes1, bytes2);
|
1997-12-08 09:13:10 +08:00
|
|
|
}
|