gimp/app/paint-funcs/paint-funcs-rgb.c
Daniel Egger 11c51fa948 Added new files seperated and specialised from paint_funcs.c. Not used so
2001-04-07  Daniel Egger  <egger@suse.de>

	* app/paint-funcs/paint-funcs-gray.c:
	* app/paint-funcs/paint-funcs-gray.h:
	* app/paint-funcs/paint-funcs-graya.c:
	* app/paint-funcs/paint-funcs-graya.h:
	* app/paint-funcs/paint-funcs-indexed.c:
	* app/paint-funcs/paint-funcs-indexed.h:
	* app/paint-funcs/paint-funcs-indexeda.c:
	* app/paint-funcs/paint-funcs-indexeda.h:
	* app/paint-funcs/paint-funcs-rgb.c:
	* app/paint-funcs/paint-funcs-rgb.h:
	* app/paint-funcs/paint-funcs-rgba.c:
	* app/paint-funcs/paint-funcs-rgba.h: Added new files seperated and
	specialised from paint_funcs.c. Not used so far.
2001-04-07 14:08:15 +00:00

1558 lines
31 KiB
C

/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef CRAZY_PAINT_REWORK
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <glib.h>
#include "libgimpcolor/gimpcolor.h"
#include "libgimpmath/gimpmath.h"
#include "apptypes.h"
#include "gimprc.h"
#include "paint_funcsP.h"
#include "paint_funcs_rgb.h"
#include "pixel_processor.h"
#include "pixel_region.h"
#include "tile_manager.h"
#include "tile.h"
#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))
/* This version of INT_MULT3 is very fast, but suffers from some
slight roundoff errors. It returns the correct result 99.987
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)
*/
#define INT_BLEND(a,b,alpha,tmp) (INT_MULT((a)-(b), alpha, tmp) + (b))
typedef enum
{
MinifyX_MinifyY,
MinifyX_MagnifyY,
MagnifyX_MinifyY,
MagnifyX_MagnifyY
} ScaleType;
/* Layer modes information */
typedef struct _LayerMode LayerMode;
struct _LayerMode
{
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 */
};
static const LayerMode layer_modes[] =
/* This must obviously be in the same
* order as the corresponding values
* in the LayerModeEffects enumeration.
*/
{
{ 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 */
};
/* ColorHash structure */
typedef struct _ColorHash ColorHash;
struct _ColorHash
{
gint pixel; /* R << 16 | G << 8 | B */
gint index; /* colormap index */
GimpImage *gimage;
};
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];
void
update_tile_rowhints_rgb (Tile *tile,
guint ymin,
guint ymax)
{
guint y;
tile_sanitize_rowhints (tile);
for (y = ymin; y <= ymax; y++)
tile_set_rowhint (tile, y, TILEROWHINT_OPAQUE);
return;
}
void
run_length_encode_rgb (const guchar *src,
guint *dest,
guint w)
{
guint start;
guint i;
guint j;
guchar last;
last = *src;
src += 3;
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 += 3;
}
for (j = start; j < i; j++)
{
*dest++ = (i - j);
*dest++ = last;
}
}
void
color_pixels_rgb (guchar *dest,
const guchar *color,
guint w)
{
register guchar c0, c1, c2;
c0 = color[0];
c1 = color[1];
c2 = color[2];
while (w--)
{
dest[0] = c0;
dest[1] = c1;
dest[2] = c2;
dest += 3;
}
}
void
blend_pixels_rgb (const guchar *src1,
const guchar *src2,
guchar *dest,
guint blend,
guint w)
{
guint b;
guchar blend2 = (255 - blend);
while (w --)
{
for (b = 0; b < 3; b++)
dest[b] = (src1[b] * blend2 + src2[b] * blend) / 255;
src1 += 3;
src2 += 3;
dest += 3;
}
}
void
shade_pixels_rgb (const guchar *src,
guchar *dest,
const guchar *col,
guint blend,
guint w)
{
guint b;
guchar blend2 = (255 - blend);
while (w --)
{
for (b = 0; b < 3; b++)
dest[b] = (src[b] * blend2 + col[b] * blend) / 255;
src += 3;
dest += 3;
}
}
void
darken_pixels_rgb_rgb (const guchar *src1,
const guchar *src2,
guchar *dest,
guint length)
{
while (length--)
{
dest[0] = (src1[0] < src2[0]) ? src1[0] : src2[0];
dest[1] = (src1[1] < src2[1]) ? src1[1] : src2[1];
dest[2] = (src1[2] < src2[2]) ? src1[2] : src2[2];
src1 += 3;
src2 += 3;
dest += 3;
}
}
void
darken_pixels_rgb_rgba (const guchar *src1,
const guchar *src2,
guchar *dest,
guint length)
{
while (length--)
{
dest[0] = (src1[0] < src2[0]) ? src1[0] : src2[0];
dest[1] = (src1[1] < src2[1]) ? src1[1] : src2[1];
dest[2] = (src1[2] < src2[2]) ? src1[2] : src2[2];
dest[3] = src2[3];
src1 += 3;
src2 += 4;
dest += 4;
}
}
void
lighten_pixels_rgb_rgb (const guchar *src1,
const guchar *src2,
guchar *dest,
guint length)
{
while (length--)
{
dest[0] = (src1[0] > src2[0]) ? src1[0] : src2[0];
dest[1] = (src1[1] > src2[1]) ? src1[1] : src2[1];
dest[2] = (src1[2] > src2[2]) ? src1[2] : src2[2];
src1 += 3;
src2 += 3;
dest += 3;
}
}
void
lighten_pixels_rgb_rgba (const guchar *src1,
const guchar *src2,
guchar *dest,
guint length)
{
while (length--)
{
dest[0] = (src1[0] > src2[0]) ? src1[0] : src2[0];
dest[1] = (src1[1] > src2[1]) ? src1[1] : src2[1];
dest[2] = (src1[2] > src2[2]) ? src1[2] : src2[2];
dest[3] = src2[3];
src1 += 3;
src2 += 4;
dest += 4;
}
}
void
multiply_pixels_rgb_rgb (const guchar *src1,
const guchar *src2,
guchar *dest,
guint length)
{
guint tmp;
while (length --)
{
dest[0] = INT_MULT(src1[0], src2[0], tmp);
dest[1] = INT_MULT(src1[1], src2[1], tmp);
dest[2] = INT_MULT(src1[2], src2[2], tmp);
src1 += 3;
src2 += 3;
dest += 3;
}
}
void
multiply_pixels_rgb_rgba (const guchar *src1,
const guchar *src2,
guchar *dest,
guint length)
{
guint tmp;
while (length --)
{
dest[0] = INT_MULT(src1[0], src2[0], tmp);
dest[1] = INT_MULT(src1[1], src2[1], tmp);
dest[2] = INT_MULT(src1[2], src2[2], tmp);
dest[3] = src2[3];
src1 += 3;
src2 += 4;
dest += 4;
}
}
void
divide_pixels_rgb_rgb (const guchar *src1,
const guchar *src2,
guchar *dest,
gint length)
{
guint b,result;
while (length --)
{
for (b = 0; b < 3; b++)
{
result = ((src1[b] * 256) / (1+src2[b]));
dest[b] = MIN (result, 255);
}
src1 += 3;
src2 += 3;
dest += 3;
}
}
void
divide_pixels_rgb_rgba (const guchar *src1,
const guchar *src2,
guchar *dest,
gint length)
{
guint b, result;
while (length --)
{
for (b = 0; b < 3; b++)
{
result = ((src1[b] * 256) / (1+src2[b]));
dest[b] = MIN (result, 255);
}
dest[3] = src2[3];
src1 += 3;
src2 += 4;
dest += 4;
}
}
void
screen_pixels_rgb_rgb (const guchar *src1,
const guchar *src2,
guchar *dest,
gint length)
{
gint b;
gint tmp;
while (length --)
{
for (b = 0; b < 3; b++)
dest[b] = 255 - INT_MULT((255 - src1[b]), (255 - src2[b]), tmp);
src1 += 3;
src2 += 3;
dest += 3;
}
}
void
screen_pixels_rgb_rgba (const guchar *src1,
const guchar *src2,
guchar *dest,
gint length)
{
gint b;
gint tmp;
while (length --)
{
for (b = 0; b < 3; b++)
dest[b] = 255 - INT_MULT((255 - src1[b]), (255 - src2[b]), tmp);
dest[3] = src2[3];
src1 += 3;
src2 += 4;
dest += 4;
}
}
void
overlay_pixels_rgb_rgb (const guchar *src1,
const guchar *src2,
guchar *dest,
gint length)
{
guint tmp;
while (length --)
{
dest[0] = INT_MULT(src1[0], src1[0] + INT_MULT(2 * src2[0],
255 - src1[0],
tmp), tmp);
dest[1] = INT_MULT(src1[1], src1[1] + INT_MULT(2 * src2[1],
255 - src1[1],
tmp), tmp);
dest[2] = INT_MULT(src1[2], src1[2] + INT_MULT(2 * src2[2],
255 - src1[2],
tmp), tmp);
src1 += 3;
src2 += 3;
dest += 3;
}
}
void
overlay_pixels_rgb_rgba (const guchar *src1,
const guchar *src2,
guchar *dest,
guint length)
{
gint tmp;
while (length --)
{
dest[0] = INT_MULT(src1[0], src1[0] + INT_MULT(2 * src2[0],
255 - src1[0],
tmp), tmp);
dest[1] = INT_MULT(src1[1], src1[1] + INT_MULT(2 * src2[1],
255 - src1[1],
tmp), tmp);
dest[2] = INT_MULT(src1[2], src1[2] + INT_MULT(2 * src2[2],
255 - src1[2],
tmp), tmp);
dest[3] = src2[3];
src1 += 3;
src2 += 4;
dest += 4;
}
}
void
dodge_pixels_rgb_rgb (const guchar *src1,
const guchar *src2,
guchar *dest,
guint length)
{
int tmp1;
while (length --)
{
tmp1 = src1[0] << 8;
tmp1 /= 256 - src2[0];
dest[0] = (guchar) CLAMP (tmp1, 0, 255);
tmp1 = src1[1] << 8;
tmp1 /= 256 - src2[1];
dest[1] = (guchar) CLAMP (tmp1, 0, 255);
tmp1 = src1[2] << 8;
tmp1 /= 256 - src2[2];
dest[2] = (guchar) CLAMP (tmp1, 0, 255);
src1 += 3;
src2 += 3;
dest += 3;
}
}
void
dodge_pixels_rgb_rgba (const guchar *src1,
const guchar *src2,
guchar *dest,
guint length)
{
int tmp1;
while (length --)
{
tmp1 = src1[0] << 8;
tmp1 /= 256 - src2[0];
dest[0] = (guchar) CLAMP (tmp1, 0, 255);
tmp1 = src1[1] << 8;
tmp1 /= 256 - src2[1];
dest[1] = (guchar) CLAMP (tmp1, 0, 255);
tmp1 = src1[2] << 8;
tmp1 /= 256 - src2[2];
dest[2] = (guchar) CLAMP (tmp1, 0, 255);
dest[3] = src2[3];
src1 += 3;
src2 += 4;
dest += 4;
}
}
void
burn_pixels_rgb_rgba (const guchar *src1,
const guchar *src2,
guchar *dest,
guint length)
{
gint tmp1;
while (length --)
{
tmp1 = (255 - src1[0]) << 8;
tmp1 /= src2[0] + 1;
dest[0] = (guchar) CLAMP (255 - tmp1, 0, 255);
tmp1 = (255 - src1[1]) << 8;
tmp1 /= src2[1] + 1;
dest[1] = (guchar) CLAMP (255 - tmp1, 0, 255);
tmp1 = (255 - src1[2]) << 8;
tmp1 /= src2[2] + 1;
dest[2] = (guchar) CLAMP (255 - tmp1, 0, 255);
dest[3] = src2[3];
src1 += 3;
src2 += 4;
dest += 4;
}
}
void
burn_pixels_rgb_rgb (const guchar *src1,
const guchar *src2,
guchar *dest,
guint length)
{
gint tmp1;
while (length --)
{
tmp1 = (255 - src1[0]) << 8;
tmp1 /= src2[0] + 1;
dest[0] = (guchar) CLAMP (255 - tmp1, 0, 255);
tmp1 = (255 - src1[1]) << 8;
tmp1 /= src2[1] + 1;
dest[1] = (guchar) CLAMP (255 - tmp1, 0, 255);
tmp1 = (255 - src1[2]) << 8;
tmp1 /= src2[2] + 1;
dest[2] = (guchar) CLAMP (255 - tmp1, 0, 255);
src1 += 3;
src2 += 3;
dest += 3;
}
}
void
hardlight_pixels_rgb_rgba (const guchar *src1,
const guchar *src2,
guchar *dest,
gint length)
{
gint tmp1;
while (length --)
{
if (src2[0] > 128) {
tmp1 = ((gint)255 - src1[0]) * ((gint)255 - ((src2[0] - 128) << 1));
dest[0] = (guchar)CLAMP(255 - (tmp1 >> 8), 0, 255);
} else {
tmp1 = (gint)src1[0] * ((gint)src2[0] << 1);
dest[0] = (guchar)CLAMP(tmp1 >> 8, 0, 255);
}
if (src2[1] > 128) {
tmp1 = ((gint)255 - src1[1]) * ((gint)255 - ((src2[1] - 128) << 1));
dest[1] = (guchar)CLAMP(255 - (tmp1 >> 8), 0, 255);
} else {
tmp1 = (gint)src1[1] * ((gint)src2[1] << 1);
dest[1] = (guchar)CLAMP(tmp1 >> 8, 0, 255);
}
if (src2[2] > 128) {
tmp1 = ((gint)255 - src1[2]) * ((gint)255 - ((src2[2] - 128) << 1));
dest[2] = (guchar)CLAMP(255 - (tmp1 >> 8), 0, 255);
} else {
tmp1 = (gint)src1[2] * ((gint)src2[2] << 1);
dest[2] = (guchar)CLAMP(tmp1 >> 8, 0, 255);
}
dest[3] = src2[3];
src1 += 3;
src2 += 4;
dest += 4;
}
}
void
hardlight_pixels_rgb_rgb (const guchar *src1,
const guchar *src2,
guchar *dest,
gint length)
{
gint tmp1;
while (length --)
{
if (src2[0] > 128) {
tmp1 = ((gint)255 - src1[0]) * ((gint)255 - ((src2[0] - 128) << 1));
dest[0] = (guchar)CLAMP(255 - (tmp1 >> 8), 0, 255);
} else {
tmp1 = (gint)src1[0] * ((gint)src2[0] << 1);
dest[0] = (guchar)CLAMP(tmp1 >> 8, 0, 255);
}
if (src2[1] > 128) {
tmp1 = ((gint)255 - src1[1]) * ((gint)255 - ((src2[1] - 128) << 1));
dest[1] = (guchar)CLAMP(255 - (tmp1 >> 8), 0, 255);
} else {
tmp1 = (gint)src1[1] * ((gint)src2[1] << 1);
dest[1] = (guchar)CLAMP(tmp1 >> 8, 0, 255);
}
if (src2[2] > 128) {
tmp1 = ((gint)255 - src1[2]) * ((gint)255 - ((src2[2] - 128) << 1));
dest[2] = (guchar)CLAMP(255 - (tmp1 >> 8), 0, 255);
} else {
tmp1 = (gint)src1[2] * ((gint)src2[2] << 1);
dest[2] = (guchar)CLAMP(tmp1 >> 8, 0, 255);
}
src1 += 3;
src2 += 3;
dest += 3;
}
}
void
add_pixels_rgb_rgb (const guchar *src1,
const guchar *src2,
guchar *dest,
guint length)
{
while (length --)
{
dest[0] = add_lut[(src1[0])] [(src2[0])];
dest[1] = add_lut[(src1[1])] [(src2[1])];
dest[2] = add_lut[(src1[2])] [(src2[2])];
src1 += 3;
src2 += 3;
dest += 3;
}
}
void
add_pixels_rgb_rgba (const guchar *src1,
const guchar *src2,
guchar *dest,
guint length)
{
while (length --)
{
dest[0] = add_lut[(src1[0])] [(src2[0])];
dest[1] = add_lut[(src1[1])] [(src2[1])];
dest[2] = add_lut[(src1[2])] [(src2[2])];
dest[3] = src2[3];
src1 += 3;
src2 += 4;
dest += 4;
}
}
void
subtract_pixels_rgb_rgb (const guchar *src1,
const guchar *src2,
guchar *dest,
guint length)
{
gint diff;
while (length --)
{
diff = src1[0] - src2[0];
dest[0] = (diff < 0) ? 0 : diff;
diff = src1[1] - src2[1];
dest[1] = (diff < 0) ? 0 : diff;
diff = src1[2] - src2[2];
dest[2] = (diff < 0) ? 0 : diff;
src1 += 3;
src2 += 3;
dest += 3;
}
}
void
subtract_pixels_rgb_rgba (const guchar *src1,
const guchar *src2,
guchar *dest,
guint length)
{
gint diff;
while (length --)
{
diff = src1[0] - src2[0];
dest[0] = (diff < 0) ? 0 : diff;
diff = src1[1] - src2[1];
dest[1] = (diff < 0) ? 0 : diff;
diff = src1[2] - src2[2];
dest[2] = (diff < 0) ? 0 : diff;
dest[3] = src2[3];
src1 += 3;
src2 += 4;
dest += 4;
}
}
void
difference_pixels_rgb_rgb (const guchar *src1,
const guchar *src2,
guchar *dest,
guint length)
{
gint diff;
while (length --)
{
diff = src1[0] - src2[0];
dest[0] = (diff < 0) ? -diff : diff;
diff = src1[1] - src2[1];
dest[1] = (diff < 0) ? -diff : diff;
diff = src1[2] - src2[2];
dest[2] = (diff < 0) ? -diff : diff;
src1 += 3;
src2 += 3;
dest += 3;
}
}
void
difference_pixels_rgb_rgba (const guchar *src1,
const guchar *src2,
guchar *dest,
guint length)
{
gint diff;
while (length --)
{
diff = src1[0] - src2[0];
dest[0] = (diff < 0) ? -diff : diff;
diff = src1[1] - src2[1];
dest[1] = (diff < 0) ? -diff : diff;
diff = src1[2] - src2[2];
dest[2] = (diff < 0) ? -diff : diff;
dest[3] = src2[3];
src1 += 3;
src2 += 4;
dest += 4;
}
}
void
add_alpha_pixels_rgb (const guchar *src,
guchar *dest,
gint length)
{
while (length --)
{
dest[0] = src[0];
dest[1] = src[1];
dest[2] = src[2];
dest[3] = OPAQUE_OPACITY;
src += 3;
dest += 4;
}
}
void
initial_pixels_rgb (const guchar *src,
guchar *dest,
const guchar *mask,
guint opacity,
const guint *affect,
guint length)
{
gint b;
gint tmp;
gint l;
const guchar *m;
guchar *destp;
const guchar *srcp;
if (mask)
{
m = mask;
/* This function assumes the source has no alpha channel and
* the destination has an alpha channel. So dest_bytes = bytes + 1
*/
if (affect[0] && affect[1] && affect[2])
{
if (!affect[3])
opacity = 0;
destp = dest + 3;
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 += 3;
dest += 4;
m++;
}
else
while(length--)
{
dest[0] = src[0];
dest[1] = src[1];
dest[2] = src[2];
dest[3] = 0;
src += 3;
dest += 4;
}
return;
}
for (b = 0; b < 3; b++)
{
destp = dest + b;
srcp = src + b;
l = length;
if (affect[b])
while(l--)
{
*destp = *srcp;
srcp += 3;
destp += 4;
}
else
while(l--)
{
*destp = 0;
destp += 4;
}
}
/* fill the alpha channel */
if (!affect[3])
opacity = 0;
destp = dest + 3;
if (opacity != 0)
while (length--)
{
*destp = INT_MULT(opacity , *m, tmp);
destp += 4;
m++;
}
else
while (length--)
{
*destp = 0;
destp += 4;
}
}
/* 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 (affect[0] && affect[1] && affect[2])
{
if (!affect[3])
opacity = 0;
destp = dest + 3;
while(length--)
{
dest[0] = src[0];
dest[1] = src[1];
dest[2] = src[2];
dest[3] = opacity;
src += 3;
dest += 4;
}
return;
}
for (b = 0; b < 3; b++)
{
destp = dest + b;
srcp = src + b;
l = length;
if (affect[b])
while(l--)
{
*destp = *srcp;
srcp += 3;
destp += 4;
}
else
while(l--)
{
*destp = 0;
destp += 4;
}
}
/* fill the alpha channel */
if (!affect[3])
opacity = 0;
destp = dest + 3;
while (length--)
{
*destp = opacity;
destp += 4;
}
}
}
void
combine_rgb_and_rgb_pixels (const guchar *src1,
const guchar *src2,
guchar *dest,
const guchar *mask,
gint opacity,
const gboolean *affect,
gint length)
{
const guchar * m;
gint b;
guchar new_alpha;
gint tmp;
if (mask)
{
m = mask;
while (length --)
{
new_alpha = INT_MULT(*m, opacity, tmp);
for (b = 0; b < 3; b++)
dest[b] = (affect[b]) ?
INT_BLEND(src2[b], src1[b], new_alpha, tmp) :
src1[b];
m++;
src1 += 3;
src2 += 3;
dest += 3;
}
}
else
{
while (length --)
{
for (b = 0; b < 3; b++)
dest[b] = (affect[b]) ?
INT_BLEND(src2[b], src1[b], opacity, tmp) :
src1[b];
src1 += 3;
src2 += 3;
dest += 3;
}
}
}
void
combine_rgb_and_rgba_pixels (const guchar *src1,
const guchar *src2,
guchar *dest,
const guchar *mask,
gint opacity,
const gboolean *affect,
gint length)
{
gint b;
guchar new_alpha;
const guchar *m;
register glong t1;
if (mask)
{
m = mask;
while (length --)
{
new_alpha = INT_MULT3(src2[3], *m, opacity, t1);
for (b = 0; b < 3; b++)
dest[b] = (affect[b]) ?
INT_BLEND(src2[b], src1[b], new_alpha, t1) :
src1[b];
m++;
src1 += 3;
src2 += 4;
dest += 3;
}
}
else
{
if (affect[0] && affect[1] && affect[2])
while (length --)
{
new_alpha = INT_MULT(src2[3], 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 += 3;
src2 += 4;
dest += 3;
}
else
while (length --)
{
new_alpha = INT_MULT(src2[3],opacity,t1);
for (b = 0; b < 3; b++)
dest[b] = (affect[b]) ?
INT_BLEND(src2[b] , src1[b] , new_alpha, t1) :
src1[b];
src1 += 3;
src2 += 4;
dest += 3;
}
}
}
void
replace_rgb_pixels (const guchar *src1,
const guchar *src2,
guchar *dest,
const guchar *mask,
gint opacity,
const gboolean *affect,
gint length,
gint bytes2,
gint has_alpha2)
{
gint b;
gint tmp;
if (mask)
{
guchar mask_alpha;
const guchar *m = mask;
while (length --)
{
mask_alpha = INT_MULT(*m, opacity, tmp);
for (b = 0; b < 3; b++)
dest[b] = (affect[b]) ?
INT_BLEND(src2[b], src1[b], mask_alpha, tmp) :
src1[b];
m++;
src1 += 3;
src2 += bytes2;
dest += 3;
}
}
else
{
static const guchar mask_alpha = OPAQUE_OPACITY ;
while (length --)
{
for (b = 0; b < 3; b++)
dest[b] = (affect[b]) ?
INT_BLEND(src2[b], src1[b], mask_alpha, tmp) :
src1[b];
src1 += 3;
src2 += bytes2;
dest += 3;
}
}
}
void
extract_from_pixels_rgb (guchar *src,
guchar *dest,
const guchar *mask,
const guchar *bg,
gboolean cut,
guint length)
{
gint b;
const guchar *m;
gint tmp;
if (mask)
m = mask;
else
m = &no_mask;
while (length --)
{
for (b = 0; b < 3; b++)
dest[b] = src[b];
dest[3] = *m;
if (cut)
for (b = 0; b < 3; b++)
src[b] = INT_BLEND(bg[b], src[b], *m, tmp);
if (mask)
m++;
src += 3;
dest += 4;
}
}
gint
map_rgb_to_indexed (const guchar *cmap,
gint num_cols,
const GimpImage *gimage,
gint r,
gint g,
gint b)
{
guint pixel;
gint hash_index;
gint cmap_index;
pixel = (r << 16) | (g << 8) | b;
hash_index = pixel % HASH_TABLE_SIZE;
/* Hash table lookup hit */
if (color_hash_table[hash_index].gimage == gimage &&
color_hash_table[hash_index].pixel == pixel)
{
cmap_index = color_hash_table[hash_index].index;
color_hash_hits++;
}
/* Hash table lookup miss */
else
{
const guchar *col;
gint diff, sum, max;
gint i;
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 */
color_hash_table[hash_index].pixel = pixel;
color_hash_table[hash_index].index = cmap_index;
color_hash_table[hash_index].gimage = (GimpImage *) gimage;
color_hash_misses++;
}
return cmap_index;
}
static void
shrink_line_rgb (gdouble *dest,
gdouble *src,
gint old_width,
gint width,
InterpolationType interp)
{
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;
for (b = 0; b < 3; b++)
{
source = &src[b];
destp = &dest[b];
position = -1;
mant = *source;
for (x = 0; x < width; x++)
{
source += 3;
accum = 0;
max = ((int)(position+step)) - ((int)(position));
max--;
while (max)
{
accum += *source;
source += 3;
max--;
}
tmp = accum + mant;
mant = ((position+step) - (int)(position + step));
mant *= *source;
tmp += mant;
tmp *= inv_step;
mant = *source - mant;
*(destp) = tmp;
destp += 3;
position += step;
}
}
}
void
apply_layer_mode_rgb_rgb (apply_combine_layer_info *info)
{
const guchar *src1 = info->src1;
const guchar *src2 = info->src2;
guchar *dest = info->dest;
guint x = info->x;
guint y = info->y;
guint opacity = opacity;
guint length = info->length;
LayerModeEffects mode = info->mode;
guint *mode_affect = info->mode_affect;
gint combine = COMBINE_INTEN_INTEN;
/* assumes we're applying src2 TO src1 */
switch (mode)
{
case NORMAL_MODE:
case ERASE_MODE:
case ANTI_ERASE_MODE:
dest = (guchar *) src2;
break;
case DISSOLVE_MODE:
/* Since dissolve requires an alpha channels... */
add_alpha_pixels_rgb (src2, dest, length);
dissolve_pixels_rgba (src2, dest, x, y, opacity, length);
combine = COMBINE_INTEN_INTEN_A;
break;
case MULTIPLY_MODE:
multiply_pixels_rgb_rgb (src1, src2, dest, length);
break;
case DIVIDE_MODE:
divide_pixels_rgb_rgb (src1, src2, dest, length);
break;
case SCREEN_MODE:
screen_pixels_rgb_rgb (src1, src2, dest, length);
break;
case OVERLAY_MODE:
overlay_pixels_rgb_rgb (src1, src2, dest, length);
break;
case DIFFERENCE_MODE:
difference_pixels_rgb_rgb (src1, src2, dest, length);
break;
case ADDITION_MODE:
add_pixels_rgb_rgb (src1, src2, dest, length);
break;
case SUBTRACT_MODE:
subtract_pixels_rgb_rgb (src1, src2, dest, length);
break;
case DARKEN_ONLY_MODE:
darken_pixels_rgb_rgb (src1, src2, dest, length);
break;
case LIGHTEN_ONLY_MODE:
lighten_pixels_rgb_rgb (src1, src2, dest, length);
break;
case HUE_MODE: case SATURATION_MODE: case VALUE_MODE:
hsv_only_pixels_rgba_rgba (src1, src2, dest, mode, length);
break;
case COLOR_MODE:
color_only_pixels_rgba_rgba (src1, src2, dest, mode, length);
break;
case BEHIND_MODE:
dest = src2;
combine = NO_COMBINATION;
break;
case REPLACE_MODE:
dest = src2;
combine = REPLACE_INTEN;
break;
case DODGE_MODE:
dodge_pixels_rgb_rgb (src1, src2, dest, length);
break;
case BURN_MODE:
burn_pixels_rgb_rgb (src1, src2, dest, length);
break;
case HARDLIGHT_MODE:
hardlight_pixels_rgb_rgb (src1, src2, dest, length);
break;
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;
}
void
apply_layer_mode_rgb_rgba (apply_combine_layer_info *info)
{
const guchar *src1 = info->src1;
const guchar *src2 = info->src2;
guchar *dest = info->dest;
guint x = info->x;
guint y = info->y;
guint opacity = opacity;
guint length = info->length;
LayerModeEffects mode = info->mode;
guint *mode_affect = info->mode_affect;
gint combine = COMBINE_INTEN_INTEN_A;
switch (mode)
{
case NORMAL_MODE:
case ERASE_MODE:
case ANTI_ERASE_MODE:
dest = src2;
break;
case DISSOLVE_MODE:
dissolve_pixels_rgba (src2, dest, x, y, opacity, length);
break;
case MULTIPLY_MODE:
multiply_pixels_rgb_rgba (src1, src2, dest, length);
break;
case DIVIDE_MODE:
divide_pixels_rgb_rgba (src1, src2, dest, length);
break;
case SCREEN_MODE:
screen_pixels_rgb_rgba (src1, src2, dest, length);
break;
case OVERLAY_MODE:
overlay_pixels_rgb_rgba (src1, src2, dest, length);
break;
case DIFFERENCE_MODE:
difference_pixels_rgb_rgba (src1, src2, dest, length);
break;
case ADDITION_MODE:
add_pixels_rgb_rgba (src1, src2, dest, length);
break;
case SUBTRACT_MODE:
subtract_pixels_rgb_rgba (src1, src2, dest, length);
break;
case DARKEN_ONLY_MODE:
darken_pixels_rgb_rgba (src1, src2, dest, length);
break;
case LIGHTEN_ONLY_MODE:
lighten_pixels_rgb_rgba (src1, src2, dest, length);
break;
case HUE_MODE: case SATURATION_MODE: case VALUE_MODE:
g_warning ("Cannot calculate hsv only view of nonalpha nonRGB images!\n");
break;
case COLOR_MODE:
g_warning ("Cannot calculate color only view of nonalpha nonRGB images!\n");
break;
case BEHIND_MODE:
dest = src2;
combine = NO_COMBINATION;
break;
case REPLACE_MODE:
dest = src2;
combine = REPLACE_INTEN;
break;
case DODGE_MODE:
dodge_pixels_rgb_rgba (src1, src2, dest, length);
break;
case BURN_MODE:
burn_pixels_rgb_rgba (src1, src2, dest, length);
break;
case HARDLIGHT_MODE:
hardlight_pixels_rgb_rgba (src1, src2, dest, length);
break;
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;
}
#endif