Hue, Saturation, Value and Color blending modes. Only Dissolve still

needed :)

Also lots of cleanups and an alphalevel fix (use minimum of source and
destination instead of always source) ...


SVN revision: 3380
This commit is contained in:
Christian Kreibich 2000-09-10 16:26:31 +00:00
parent 7149339729
commit d4fa780358
2 changed files with 431 additions and 81 deletions

View File

@ -264,7 +264,7 @@ void formats(ImlibLoader *l);
static void xcf_seek_pos (int pos);
static int xcf_read_int32 (FILE *fp, DATA32 *data, int count);
static int xcf_read_float (FILE *fp, float *data, int count);
/*static int xcf_read_float (FILE *fp, float *data, int count);*/
static int xcf_read_int8 (FILE *fp, DATA8 *data, int count);
static int xcf_read_string (FILE *fp, char **data, int count);
static char xcf_load_prop (PropType *prop_type, DATA32 *prop_size);
@ -309,6 +309,10 @@ extern void combine_pixels_mult (DATA8* src, int src_w, int src_h, DATA8* dest,
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);
extern void combine_pixels_hue (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_sat (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_val (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_col (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y);
/* ---------------------------------------------------------------------------- globals ------------ */
@ -350,6 +354,7 @@ xcf_read_int32 (FILE *fp,
return total * 4;
}
/*
static int
xcf_read_float (FILE *fp,
float *data,
@ -357,6 +362,7 @@ xcf_read_float (FILE *fp,
{
return (xcf_read_int32(fp, (DATA32 *)((void *)data), count));
}
*/
static int
xcf_read_int8 (FILE *fp,
@ -1431,10 +1437,8 @@ flatten_image(void)
while (l)
{
/* Ok, paste each layer on top of the image, using the mode's merging type.
We're moving upward through the layer stack. The code that's commented
out is directly from Gimp. Right now fall through all of these
and simply combine the layers.
--cK.
We're moving upward through the layer stack.
--cK.
*/
if (image->single_layer_index < 0 || layer_index == image->single_layer_index)
{
@ -1486,11 +1490,26 @@ flatten_image(void)
l->offset_x, l->offset_y);
break;
/* These are still to be finished ... */
case HUE_MODE:
combine_pixels_hue(l->data, l->width, l->height,
image->data, image->width, image->height,
l->offset_x, l->offset_y);
break;
case SATURATION_MODE:
combine_pixels_sat(l->data, l->width, l->height,
image->data, image->width, image->height,
l->offset_x, l->offset_y);
break;
case VALUE_MODE:
combine_pixels_val(l->data, l->width, l->height,
image->data, image->width, image->height,
l->offset_x, l->offset_y);
break;
case COLOR_MODE:
combine_pixels_col(l->data, l->width, l->height,
image->data, image->width, image->height,
l->offset_x, l->offset_y);
break;
case DISSOLVE_MODE:
/* None of those is actually valid for layer blending, fall through: */
@ -1633,6 +1652,10 @@ load(ImlibImage *im, ImlibProgressFunction progress, char progress_granularity,
xcf_cleanup();
return 1;
/* shut up warnings: */
progress_granularity = 0;
immediate_load = 0;
}
char

View File

@ -7,6 +7,7 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <math.h>
#include <X11/Xlib.h>
#include <X11/extensions/XShm.h>
#include <X11/Xutil.h>
@ -16,27 +17,259 @@
#include "image.h"
#include "color_values.h"
#define EPSILON 0.0001
#define RS R_VAL(src + s_idx)
#define GS G_VAL(src + s_idx)
#define BS B_VAL(src + s_idx)
#define AS A_VAL(src + s_idx)
#define RD R_VAL(dest + d_idx)
#define GD G_VAL(dest + d_idx)
#define BD B_VAL(dest + d_idx)
#define AD A_VAL(dest + d_idx)
#define EPS 0.00001
#define PI 3.141592654
#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)
#define alphify(src_alpha,new_alpha) \
b = 3; \
if (new_alpha != 0) \
{ \
ratio = (float) src_alpha / new_alpha; \
compl_ratio = 1.0 - ratio; \
\
do { b--; \
dest[d_idx + b] = \
(unsigned char) (src[s_idx + b] * ratio + dest[d_idx + b] * compl_ratio + EPSILON); \
} while (b); \
}
void
rgb_to_hls (DATA8 *red, DATA8 *green, DATA8 *blue)
{
int r, g, b;
double h, l, s;
int min, max;
int delta;
r = *red;
g = *green;
b = *blue;
if (r > g)
{
max = MAX (r, b);
min = MIN (g, b);
}
else
{
max = MAX (g, b);
min = MIN (r, b);
}
l = (max + min) / 2.0;
if (max == min)
{
s = 0.0;
h = 0.0;
}
else
{
delta = (max - min);
if (l < 128)
s = 255 * (double) delta / (double) (max + min);
else
s = 255 * (double) delta / (double) (511 - max - min);
if (r == max)
h = (g - b) / (double) delta;
else if (g == max)
h = 2 + (b - r) / (double) delta;
else
h = 4 + (r - g) / (double) delta;
h = h * 42.5;
if (h < 0)
h += 255;
else if (h > 255)
h -= 255;
}
*red = h;
*green = l;
*blue = s;
}
/* translate negative destinations */
DATA8
gimp_hls_value (double n1, double n2, double hue)
{
double value;
if (hue > 255)
hue -= 255;
else if (hue < 0)
hue += 255;
if (hue < 42.5)
value = n1 + (n2 - n1) * (hue / 42.5);
else if (hue < 127.5)
value = n2;
else if (hue < 170)
value = n1 + (n2 - n1) * ((170 - hue) / 42.5);
else
value = n1;
return (DATA8) (value * 255);
}
void
hls_to_rgb (DATA8 *hue, DATA8 *lightness, DATA8 *saturation)
{
double h, l, s;
double m1, m2;
h = *hue;
l = *lightness;
s = *saturation;
if (s == 0)
{
/* achromatic case */
*hue = l;
*lightness = l;
*saturation = l;
}
else
{
if (l < 128)
m2 = (l * (255 + s)) / 65025.0;
else
m2 = (l + s - (l * s) / 255.0) / 255.0;
m1 = (l / 127.5) - m2;
/* chromatic case */
*hue = gimp_hls_value (m1, m2, h + 85);
*lightness = gimp_hls_value (m1, m2, h);
*saturation = gimp_hls_value (m1, m2, h - 85);
}
}
void
rgb_to_hsv (DATA8 *red, DATA8 *green, DATA8 *blue)
{
int r, g, b;
double h, s, v;
int min, max;
int delta;
h = 0.0;
r = *red;
g = *green;
b = *blue;
if (r > g)
{
max = MAX (r, b);
min = MIN (g, b);
}
else
{
max = MAX (g, b);
min = MIN (r, b);
}
v = max;
if (max != 0)
s = ((max - min) * 255) / (double) max;
else
s = 0;
if (s == 0)
h = 0;
else
{
delta = max - min;
if (r == max)
h = (g - b) / (double) delta;
else if (g == max)
h = 2 + (b - r) / (double) delta;
else if (b == max)
h = 4 + (r - g) / (double) delta;
h *= 42.5;
if (h < 0)
h += 255;
if (h > 255)
h -= 255;
}
*red = h;
*green = s;
*blue = v;
}
void
hsv_to_rgb (DATA8 *hue, DATA8 *saturation, DATA8 *value)
{
double h, s, v;
double f, p, q, t;
if (*saturation == 0)
{
*hue = *value;
*saturation = *value;
*value = *value;
}
else
{
h = *hue * 6.0 / 255.0;
s = *saturation / 255.0;
v = *value / 255.0;
f = h - (int) h;
p = v * (1.0 - s);
q = v * (1.0 - (s * f));
t = v * (1.0 - (s * (1.0 - f)));
switch ((int) h)
{
case 0:
*hue = v * 255;
*saturation = t * 255;
*value = p * 255;
break;
case 1:
*hue = q * 255;
*saturation = v * 255;
*value = p * 255;
break;
case 2:
*hue = p * 255;
*saturation = v * 255;
*value = t * 255;
break;
case 3:
*hue = p * 255;
*saturation = q * 255;
*value = v * 255;
break;
case 4:
*hue = t * 255;
*saturation = p * 255;
*value = v * 255;
break;
case 5:
*hue = v * 255;
*saturation = p * 255;
*value = q * 255;
break;
}
}
}
/* 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,
@ -82,22 +315,31 @@ combine_pixels_normal (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w
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);
src_alpha = AS;
if (src_alpha != 0)
{
if (src_alpha == 255)
{
new_alpha = src_alpha;
alphify (src_alpha, new_alpha);
A_VAL(dest + d_idx) = new_alpha;
}
new_alpha = src_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;
new_alpha = AD + INT_MULT((255 - AD), src_alpha, tmp);
b = 3;
if (new_alpha != 0)
{
ratio = (float) src_alpha / new_alpha;
compl_ratio = 1.0 - ratio;
do
{
b--;
dest[d_idx + b] =
(unsigned char) (src[s_idx + b] * ratio + dest[d_idx + b] * compl_ratio + EPS);
}
while (b);
}
AD = new_alpha;
}
}
}
@ -119,16 +361,16 @@ combine_pixels_add (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, i
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 = RD + RS;
RD = (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 = GD + GS;
GD = (tmp > 255 ? 255 : tmp);
tmp = B_VAL(dest + d_idx) + B_VAL(src + s_idx);
B_VAL(dest + d_idx) = (tmp > 255 ? 255 : tmp);
tmp = BD + BS;
BD = (tmp > 255 ? 255 : tmp);
A_VAL(dest + d_idx) = A_VAL(src + s_idx);
AD = MIN(AD, AS);
}
}
@ -149,16 +391,16 @@ combine_pixels_sub (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, i
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 = RD - RS;
RD = (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 = GD - GS;
GD = (tmp < 0 ? 0 : tmp);
tmp = B_VAL(dest + d_idx) - B_VAL(src + s_idx);
B_VAL(dest + d_idx) = (tmp < 0 ? 0 : tmp);
tmp = BD - BS;
BD = (tmp < 0 ? 0 : tmp);
A_VAL(dest + d_idx) = A_VAL(src + s_idx);
AD = MIN(AD, AS);
}
}
@ -179,16 +421,16 @@ combine_pixels_diff (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w,
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 = RD - RS;
RD = (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 = GD - GS;
GD = (tmp < 0 ? -tmp : tmp);
tmp = B_VAL(dest + d_idx) - B_VAL(src + s_idx);
B_VAL(dest + d_idx) = (tmp < 0 ? -tmp : tmp);
tmp = BD - BS;
BD = (tmp < 0 ? -tmp : tmp);
A_VAL(dest + d_idx) = A_VAL(src + s_idx);
AD = MIN(AD, AS);
}
}
@ -208,11 +450,11 @@ combine_pixels_darken (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w
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));
RD = MIN(RD, RS);
GD = MIN(GD, GS);
BD = MIN(BD, BS);
A_VAL(dest + d_idx) = A_VAL(src + s_idx);
AD = MIN(AD, AS);
}
}
@ -232,11 +474,11 @@ combine_pixels_lighten (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_
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));
RD = MAX(RD, RS);
GD = MAX(GD, GS);
BD = MAX(BD, BS);
A_VAL(dest + d_idx) = A_VAL(src + s_idx);
AD = MIN(AD, AS);
}
}
@ -256,11 +498,11 @@ combine_pixels_mult (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w,
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;
RD = (RD * RS) >> 8;
GD = (GD * GS) >> 8;
BD = (BD * BS) >> 8;
A_VAL(dest + d_idx) = A_VAL(src + s_idx);
AD = MIN(AD, AS);
}
}
@ -280,11 +522,11 @@ combine_pixels_div (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, i
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);
RD = MIN(255, ((float)RD / (RS + 1)) * 256);
GD = MIN(255, ((float)GD / (GS + 1)) * 256);
BD = MIN(255, ((float)BD / (BS + 1)) * 256);
A_VAL(dest + d_idx) = A_VAL(src + s_idx);
AD = MIN(AD, AS);
}
}
@ -304,11 +546,11 @@ combine_pixels_screen (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w
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);
RD = 255 - (((255 - RD) * (255 - RS)) >> 8);
GD = 255 - (((255 - GD) * (255 - GS)) >> 8);
BD = 255 - (((255 - BD) * (255 - BS)) >> 8);
A_VAL(dest + d_idx) = A_VAL(src + s_idx);
AD = MIN(AD, AS);
}
}
@ -329,19 +571,104 @@ combine_pixels_overlay (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_
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 - RD) * (255 - RS)) >> 8);
tmp_mult = (RD * RS) >> 8;
RD = (RD * tmp_screen + (255 - RD) * 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 - GD) * (255 - GS)) >> 8);
tmp_mult = (GD * GS) >> 8;
GD = (GD * tmp_screen + (255 - GD) * 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;
tmp_screen = 255 - (((255 - BD) * (255 - BS)) >> 8);
tmp_mult = (BD * BS) >> 8;
BD = (BD * tmp_screen + (255 - BD) * tmp_mult) >> 8;
A_VAL(dest + d_idx) = A_VAL(src + s_idx);
AD = MIN(AD, AS);
}
}
void
combine_pixels_hsv (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y, int mode)
{
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);
rgb_to_hsv(&RS, &GS, &BS);
rgb_to_hsv(&RD, &GD, &BD);
switch (mode)
{
case 0: /* hue mode */
RD = RS;
break;
case 1: /* saturation mode */
GD = GS;
break;
case 2: /* value mode */
BD = BS;
break;
default:
break;
}
hsv_to_rgb(&RD, &GD, &BD);
AD = MIN(AD, AS);
}
}
void
combine_pixels_hue (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
{
combine_pixels_hsv(src, src_w, src_h, dest, dest_w, dest_h, dest_x, dest_y, 0);
}
void
combine_pixels_sat (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
{
combine_pixels_hsv(src, src_w, src_h, dest, dest_w, dest_h, dest_x, dest_y, 1);
}
void
combine_pixels_val (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
{
combine_pixels_hsv(src, src_w, src_h, dest, dest_w, dest_h, dest_x, dest_y, 2);
}
void
combine_pixels_col (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);
rgb_to_hls(&RS, &GS, &BS);
rgb_to_hls(&RD, &GD, &BD);
RD = RS;
BD = BS;
hls_to_rgb(&RD, &GD, &BD);
AD = MIN(AD, AS);
}
}