Finally adding layer blending modes Multiply, Divide, Screen, Overlay,

Difference, Addition, Subtraction, Darken, Lighten.

Still to do: Hue, Saturation, Value, Color, Dissolve.


SVN revision: 3337
This commit is contained in:
Christian Kreibich 2000-09-06 15:56:43 +00:00
parent cc59ec53ac
commit cc551409ad
2 changed files with 357 additions and 134 deletions

View File

@ -297,10 +297,18 @@ static char xcf_file_init(char* filename);
static void xcf_cleanup(void);
static void xcf_to_imlib(ImlibImage *im);
/* Stuff for pixel merging:
/* Stuff for layer merging:
*/
extern void combine_pixels (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y);
/* ... */
extern void combine_pixels_normal (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y);
extern void combine_pixels_add (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y);
extern void combine_pixels_sub (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y);
extern void combine_pixels_diff (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y);
extern void combine_pixels_darken (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y);
extern void combine_pixels_lighten (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y);
extern void combine_pixels_mult (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y);
extern void combine_pixels_div (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y);
extern void combine_pixels_screen (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y);
extern void combine_pixels_overlay (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y);
/* ---------------------------------------------------------------------------- globals ------------ */
@ -1432,106 +1440,69 @@ flatten_image(void)
{
switch (l->mode)
{
case DISSOLVE_MODE:
/*
if (! has_alpha2)
add_alpha_pixels (src2, *dest, length, bytes2);
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;
break;
*/
case MULTIPLY_MODE:
/*
multiply_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2);
break;
*/
combine_pixels_mult(l->data, l->width, l->height,
image->data, image->width, image->height,
l->offset_x, l->offset_y);
break;
case DIVIDE_MODE:
/*
divide_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2);
break;
*/
combine_pixels_div(l->data, l->width, l->height,
image->data, image->width, image->height,
l->offset_x, l->offset_y);
break;
case SCREEN_MODE:
/*
screen_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2);
break;
*/
combine_pixels_screen(l->data, l->width, l->height,
image->data, image->width, image->height,
l->offset_x, l->offset_y);
break;
case OVERLAY_MODE:
/*
overlay_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2);
break;
*/
combine_pixels_overlay(l->data, l->width, l->height,
image->data, image->width, image->height,
l->offset_x, l->offset_y);
break;
case DIFFERENCE_MODE:
/*
difference_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2);
break;
*/
combine_pixels_diff(l->data, l->width, l->height,
image->data, image->width, image->height,
l->offset_x, l->offset_y);
break;
case ADDITION_MODE:
/*
add_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2);
break;
*/
combine_pixels_add(l->data, l->width, l->height,
image->data, image->width, image->height,
l->offset_x, l->offset_y);
break;
case SUBTRACT_MODE:
/*
subtract_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2);
break;
*/
combine_pixels_sub(l->data, l->width, l->height,
image->data, image->width, image->height,
l->offset_x, l->offset_y);
break;
case DARKEN_ONLY_MODE:
/*
darken_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2);
break;
*/
combine_pixels_darken(l->data, l->width, l->height,
image->data, image->width, image->height,
l->offset_x, l->offset_y);
break;
case LIGHTEN_ONLY_MODE:
/*
lighten_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2);
break;
*/
case HUE_MODE: case SATURATION_MODE: case VALUE_MODE:
/*
if (bytes1 > 2)
hsv_only_pixels (src1, src2, *dest, mode, length, bytes1, bytes2, has_alpha1, has_alpha2);
else
*dest = src2;
break;
*/
combine_pixels_lighten(l->data, l->width, l->height,
image->data, image->width, image->height,
l->offset_x, l->offset_y);
break;
/* These are still to be finished ... */
case HUE_MODE:
case SATURATION_MODE:
case VALUE_MODE:
case COLOR_MODE:
/*
if (bytes1 > 2)
color_only_pixels (src1, src2, *dest, mode, length, bytes1, bytes2, has_alpha1, has_alpha2);
else
*dest = src2;
break;
*/
case DISSOLVE_MODE:
/* None of those is actually valid for layer blending, fall through: */
case BEHIND_MODE:
/*
*dest = src2;
if (has_alpha1)
combine = BEHIND_INTEN;
else
combine = NO_COMBINATION;
break;
*/
case REPLACE_MODE:
/*
*dest = src2;
combine = REPLACE_INTEN;
break;
*/
case ERASE_MODE:
/*
*dest = src2;
combine = ERASE_INTEN;
break;
*/
case ANTI_ERASE_MODE:
/*
*dest = src2;
combine = ANTI_ERASE_INTEN;
break;
*/
case NORMAL_MODE:
combine_pixels(l->data, l->width, l->height, image->data, image->width, image->height, l->offset_x, l->offset_y);
combine_pixels_normal(l->data, l->width, l->height,
image->data, image->width, image->height,
l->offset_x, l->offset_y);
break;
default:

View File

@ -30,6 +30,9 @@
#define RANDOM_SEED 314159265
#define EPSILON 0.0001
#define MAX(a, b) ((a > b) ? a : b)
#define MIN(a, b) ((a < b) ? a : b)
#define INT_MULT(a,b,t) ((t) = (a) * (b) + 0x80, ((((t) >> 8) + (t)) >> 8))
#define LINEAR(x,y,w) ((w*y + x)*4)
@ -48,8 +51,33 @@
}
/* translate negative destinations */
void clip(int * src_tl_x, int * src_tl_y,
int * src_br_x, int * src_br_y,
int * dest_x, int * dest_y,
int dest_w, int dest_h)
{
if (*dest_x + *src_br_x >= dest_w)
{ *src_br_x -= (*dest_x + *src_br_x) - dest_w; }
if (*dest_y + *src_br_y >= dest_h)
{ *src_br_y -= (*dest_y + *src_br_y) - dest_h; }
if (*dest_x < 0)
{
*src_tl_x = -(*dest_x);
*dest_x = 0;
}
if (*dest_y < 0)
{
*src_tl_y = -(*dest_y);
*dest_y = 0;
}
}
void
combine_pixels (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
combine_pixels_normal (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
{
int x, y, s_idx, d_idx;
int src_tl_x = 0, src_tl_y = 0;
@ -60,51 +88,275 @@ combine_pixels (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int d
unsigned char new_alpha;
float ratio, compl_ratio;
long tmp;
/*printf ("Blending %ix%i onto %ix%i at %i, %i -->", src_w, src_h, dest_w, dest_h, dest_x, dest_y);*/
/* translate negative destinations */
if (dest_x + src_br_x >= dest_w)
src_br_x -= (dest_x + src_br_x) - dest_w;
if (dest_y + src_br_y >= dest_h)
src_br_y -= (dest_y + src_br_y) - dest_h;
if (dest_x < 0)
{
src_tl_x = -dest_x;
dest_x = 0;
}
if (dest_y < 0)
{
src_tl_y = -dest_y;
dest_y = 0;
}
clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
for (y = src_tl_y; y < src_br_y; y++)
{
for (x = src_tl_x; x < src_br_x; x++)
{
d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
s_idx = LINEAR(x, y, src_w);
src_alpha = A_VAL(src + s_idx);
if (src_alpha != 0)
{
if (src_alpha == 255)
{
new_alpha = src_alpha;
alphify (src_alpha, new_alpha);
A_VAL(dest + d_idx) = new_alpha;
}
else
{
new_alpha = A_VAL(dest + d_idx) + INT_MULT((255 - A_VAL(dest + d_idx)), src_alpha, tmp);
alphify (src_alpha, new_alpha);
A_VAL(dest + d_idx) = new_alpha;
}
}
}
}
for (x = src_tl_x; x < src_br_x; x++)
{
d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
s_idx = LINEAR(x, y, src_w);
src_alpha = A_VAL(src + s_idx);
if (src_alpha != 0)
{
if (src_alpha == 255)
{
new_alpha = src_alpha;
alphify (src_alpha, new_alpha);
A_VAL(dest + d_idx) = new_alpha;
}
else
{
new_alpha = A_VAL(dest + d_idx) + INT_MULT((255 - A_VAL(dest + d_idx)), src_alpha, tmp);
alphify (src_alpha, new_alpha);
A_VAL(dest + d_idx) = new_alpha;
}
}
}
}
void
combine_pixels_add (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
{
int x, y, s_idx, d_idx;
int src_tl_x = 0, src_tl_y = 0;
int src_br_x = src_w, src_br_y = src_h;
int tmp;
clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
for (y = src_tl_y; y < src_br_y; y++)
for (x = src_tl_x; x < src_br_x; x++)
{
d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
s_idx = LINEAR(x, y, src_w);
tmp = R_VAL(dest + d_idx) + R_VAL(src + s_idx);
R_VAL(dest + d_idx) = (tmp > 255 ? 255 : tmp);
tmp = G_VAL(dest + d_idx) + G_VAL(src + s_idx);
G_VAL(dest + d_idx) = (tmp > 255 ? 255 : tmp);
tmp = B_VAL(dest + d_idx) + B_VAL(src + s_idx);
B_VAL(dest + d_idx) = (tmp > 255 ? 255 : tmp);
A_VAL(dest + d_idx) = A_VAL(src + s_idx);
}
}
void
combine_pixels_sub (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
{
int x, y, s_idx, d_idx;
int src_tl_x = 0, src_tl_y = 0;
int src_br_x = src_w, src_br_y = src_h;
int tmp;
clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
for (y = src_tl_y; y < src_br_y; y++)
for (x = src_tl_x; x < src_br_x; x++)
{
d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
s_idx = LINEAR(x, y, src_w);
tmp = R_VAL(dest + d_idx) - R_VAL(src + s_idx);
R_VAL(dest + d_idx) = (tmp < 0 ? 0 : tmp);
tmp = G_VAL(dest + d_idx) - G_VAL(src + s_idx);
G_VAL(dest + d_idx) = (tmp < 0 ? 0 : tmp);
tmp = B_VAL(dest + d_idx) - B_VAL(src + s_idx);
B_VAL(dest + d_idx) = (tmp < 0 ? 0 : tmp);
A_VAL(dest + d_idx) = A_VAL(src + s_idx);
}
}
void
combine_pixels_diff (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
{
int x, y, s_idx, d_idx;
int src_tl_x = 0, src_tl_y = 0;
int src_br_x = src_w, src_br_y = src_h;
int tmp;
clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
for (y = src_tl_y; y < src_br_y; y++)
for (x = src_tl_x; x < src_br_x; x++)
{
d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
s_idx = LINEAR(x, y, src_w);
tmp = R_VAL(dest + d_idx) - R_VAL(src + s_idx);
R_VAL(dest + d_idx) = (tmp < 0 ? -tmp : tmp);
tmp = G_VAL(dest + d_idx) - G_VAL(src + s_idx);
G_VAL(dest + d_idx) = (tmp < 0 ? -tmp : tmp);
tmp = B_VAL(dest + d_idx) - B_VAL(src + s_idx);
B_VAL(dest + d_idx) = (tmp < 0 ? -tmp : tmp);
A_VAL(dest + d_idx) = A_VAL(src + s_idx);
}
}
void
combine_pixels_darken (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
{
int x, y, s_idx, d_idx;
int src_tl_x = 0, src_tl_y = 0;
int src_br_x = src_w, src_br_y = src_h;
clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
for (y = src_tl_y; y < src_br_y; y++)
for (x = src_tl_x; x < src_br_x; x++)
{
d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
s_idx = LINEAR(x, y, src_w);
R_VAL(dest + d_idx) = MIN(R_VAL(dest + d_idx), R_VAL(src + s_idx));
G_VAL(dest + d_idx) = MIN(G_VAL(dest + d_idx), G_VAL(src + s_idx));
B_VAL(dest + d_idx) = MIN(B_VAL(dest + d_idx), B_VAL(src + s_idx));
A_VAL(dest + d_idx) = A_VAL(src + s_idx);
}
}
void
combine_pixels_lighten (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
{
int x, y, s_idx, d_idx;
int src_tl_x = 0, src_tl_y = 0;
int src_br_x = src_w, src_br_y = src_h;
clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
for (y = src_tl_y; y < src_br_y; y++)
for (x = src_tl_x; x < src_br_x; x++)
{
d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
s_idx = LINEAR(x, y, src_w);
R_VAL(dest + d_idx) = MAX(R_VAL(dest + d_idx), R_VAL(src + s_idx));
G_VAL(dest + d_idx) = MAX(G_VAL(dest + d_idx), G_VAL(src + s_idx));
B_VAL(dest + d_idx) = MAX(B_VAL(dest + d_idx), B_VAL(src + s_idx));
A_VAL(dest + d_idx) = A_VAL(src + s_idx);
}
}
void
combine_pixels_mult (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
{
int x, y, s_idx, d_idx;
int src_tl_x = 0, src_tl_y = 0;
int src_br_x = src_w, src_br_y = src_h;
clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
for (y = src_tl_y; y < src_br_y; y++)
for (x = src_tl_x; x < src_br_x; x++)
{
d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
s_idx = LINEAR(x, y, src_w);
R_VAL(dest + d_idx) = (R_VAL(dest + d_idx) * R_VAL(src + s_idx)) >> 8;
G_VAL(dest + d_idx) = (G_VAL(dest + d_idx) * G_VAL(src + s_idx)) >> 8;
B_VAL(dest + d_idx) = (B_VAL(dest + d_idx) * B_VAL(src + s_idx)) >> 8;
A_VAL(dest + d_idx) = A_VAL(src + s_idx);
}
}
void
combine_pixels_div (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
{
int x, y, s_idx, d_idx;
int src_tl_x = 0, src_tl_y = 0;
int src_br_x = src_w, src_br_y = src_h;
clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
for (y = src_tl_y; y < src_br_y; y++)
for (x = src_tl_x; x < src_br_x; x++)
{
d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
s_idx = LINEAR(x, y, src_w);
R_VAL(dest + d_idx) = MIN(255, ((float)R_VAL(dest + d_idx) / (R_VAL(src + s_idx) + 1)) * 256);
G_VAL(dest + d_idx) = MIN(255, ((float)G_VAL(dest + d_idx) / (G_VAL(src + s_idx) + 1)) * 256);
B_VAL(dest + d_idx) = MIN(255, ((float)B_VAL(dest + d_idx) / (B_VAL(src + s_idx) + 1)) * 256);
A_VAL(dest + d_idx) = A_VAL(src + s_idx);
}
}
void
combine_pixels_screen (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
{
int x, y, s_idx, d_idx;
int src_tl_x = 0, src_tl_y = 0;
int src_br_x = src_w, src_br_y = src_h;
clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
for (y = src_tl_y; y < src_br_y; y++)
for (x = src_tl_x; x < src_br_x; x++)
{
d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
s_idx = LINEAR(x, y, src_w);
R_VAL(dest + d_idx) = 255 - (((255 - R_VAL(dest + d_idx)) * (255 - R_VAL(src + s_idx))) >> 8);
G_VAL(dest + d_idx) = 255 - (((255 - G_VAL(dest + d_idx)) * (255 - G_VAL(src + s_idx))) >> 8);
B_VAL(dest + d_idx) = 255 - (((255 - B_VAL(dest + d_idx)) * (255 - B_VAL(src + s_idx))) >> 8);
A_VAL(dest + d_idx) = A_VAL(src + s_idx);
}
}
void
combine_pixels_overlay (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
{
int x, y, s_idx, d_idx;
int src_tl_x = 0, src_tl_y = 0;
int src_br_x = src_w, src_br_y = src_h;
int tmp_screen, tmp_mult;
clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
for (y = src_tl_y; y < src_br_y; y++)
for (x = src_tl_x; x < src_br_x; x++)
{
d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
s_idx = LINEAR(x, y, src_w);
tmp_screen = 255 - (((255 - R_VAL(dest + d_idx)) * (255 - R_VAL(src + s_idx))) >> 8);
tmp_mult = (R_VAL(dest + d_idx) * R_VAL(src + s_idx)) >> 8;
R_VAL(dest + d_idx) = (R_VAL(dest + d_idx) * tmp_screen + (255 - R_VAL(dest + d_idx)) * tmp_mult) >> 8;
tmp_screen = 255 - (((255 - G_VAL(dest + d_idx)) * (255 - G_VAL(src + s_idx))) >> 8);
tmp_mult = (G_VAL(dest + d_idx) * G_VAL(src + s_idx)) >> 8;
G_VAL(dest + d_idx) = (G_VAL(dest + d_idx) * tmp_screen + (255 - G_VAL(dest + d_idx)) * tmp_mult) >> 8;
tmp_screen = 255 - (((255 - B_VAL(dest + d_idx)) * (255 - B_VAL(src + s_idx))) >> 8);
tmp_mult = (B_VAL(dest + d_idx) * B_VAL(src + s_idx)) >> 8;
B_VAL(dest + d_idx) = (B_VAL(dest + d_idx) * tmp_screen + (255 - B_VAL(dest + d_idx)) * tmp_mult) >> 8;
A_VAL(dest + d_idx) = A_VAL(src + s_idx);
}
}