Commit 15f9913b authored by ellson's avatar ellson

- add internal support for alpha channel in HSV colors

- save both rgba and hsva color values in colortbl.h  - share 'a' value
- only "transparent" has an "a" value of 0  - couold be others one day
- -Tps generator does binary test on "a" value of color - skip rendering if "transparent"
parent 3e7162e9
......@@ -12,7 +12,7 @@
# * AT&T Research, Florham Park NJ *
# **********************************************************/
function rgb_to_hsb(r,g,b) {
function rgb_to_hsv(r,g,b) {
r = r / 255.0; g = g / 255.0; b = b / 255.0;
max = r; if (max < g) max = g; if (max < b) max = b;
min = r; if (min > g) min = g; if (min > b) min = b;
......@@ -38,11 +38,11 @@ function rgb_to_hsb(r,g,b) {
v = v * 255.0;
}
BEGIN { s = ARGV[1]; gsub("\\.","_",s); printf("hsbcolor_t %s[] = {\n",s); }
BEGIN { s = ARGV[1]; gsub("\\.","_",s); printf("hsvrgbacolor_t %s[] = {\n",s); }
/^$/ { next; }
/^#/ { next; }
{
rgb_to_hsb($2,$3,$4);
printf("{\"%s\",%d,%d,%d},\n",$1,h,s,v);
rgb_to_hsv($2,$3,$4);
printf("{\"%s\",%d,%d,%d,%d,%d,%d,%d},\n",$1,h,s,v,$2,$3,$4,$5);
}
END { printf("};\n"); }
......@@ -23,20 +23,21 @@
extern "C" {
#endif
typedef struct hsbcolor_t {
typedef struct hsvrgbacolor_t {
char *name;
unsigned char h, s, b;
} hsbcolor_t;
unsigned char h, s, v;
unsigned char r, g, b, a;
} hsvrgbacolor_t;
/* possible representations of color in gvcolor_t */
typedef enum { HSV_DOUBLE, RGBA_BYTE, RGBA_WORD, CMYK_BYTE,
typedef enum { HSVA_DOUBLE, RGBA_BYTE, RGBA_WORD, CMYK_BYTE,
RGBA_DOUBLE, COLOR_STRING, COLOR_INDEX } color_type_t;
/* gvcolor_t can hold a color spec in a choice or representations */
typedef struct color_s {
union {
double RGBA[4];
double HSV[3];
double HSVA[4];
unsigned char rgba[4];
unsigned char cmyk[4];
int rrggbbaa[4];
......
This diff is collapsed.
......@@ -129,10 +129,10 @@ static void rgb2cmyk(double r, double g, double b, double *c, double *m,
static int colorcmpf(const void *p0, const void *p1)
{
/* fast comparison of first character */
int i = (((hsbcolor_t *) p0)->name[0] - ((hsbcolor_t *) p1)->name[0]);
int i = (((hsvrgbacolor_t *) p0)->name[0] - ((hsvrgbacolor_t *) p1)->name[0]);
/* if first character matches then compare full color name */
return (i ? i :
strcmp(((hsbcolor_t *) p0)->name, ((hsbcolor_t *) p1)->name));
strcmp(((hsvrgbacolor_t *) p0)->name, ((hsvrgbacolor_t *) p1)->name));
}
char *canontoken(char *str)
......@@ -237,13 +237,13 @@ static char* resolveColor (char* str)
int colorxlate(char *str, gvcolor_t * color, color_type_t target_type)
{
static hsbcolor_t *last;
static hsvrgbacolor_t *last;
static unsigned char *canon;
static int allocated;
unsigned char *p, *q;
hsbcolor_t fake;
hsvrgbacolor_t fake;
unsigned char c;
double H, S, V, R, G, B;
double H, S, V, A, R, G, B;
double C, M, Y, K;
unsigned int r, g, b, a;
int len, rc;
......@@ -260,14 +260,16 @@ int colorxlate(char *str, gvcolor_t * color, color_type_t target_type)
if ((*p == '#')
&& (sscanf((char *) p, "#%2x%2x%2x%2x", &r, &g, &b, &a) >= 3)) {
switch (target_type) {
case HSV_DOUBLE:
case HSVA_DOUBLE:
R = (double) r / 255.0;
G = (double) g / 255.0;
B = (double) b / 255.0;
A = (double) a / 255.0;
rgb2hsv(R, G, B, &H, &S, &V);
color->u.HSV[0] = H;
color->u.HSV[1] = S;
color->u.HSV[2] = V;
color->u.HSVA[0] = H;
color->u.HSVA[1] = S;
color->u.HSVA[2] = V;
color->u.HSVA[3] = A;
break;
case RGBA_BYTE:
color->u.rgba[0] = r;
......@@ -330,10 +332,11 @@ int colorxlate(char *str, gvcolor_t * color, color_type_t target_type)
S = MAX(MIN(S, 1.0), 0.0);
V = MAX(MIN(V, 1.0), 0.0);
switch (target_type) {
case HSV_DOUBLE:
color->u.HSV[0] = H;
color->u.HSV[1] = S;
color->u.HSV[2] = V;
case HSVA_DOUBLE:
color->u.HSVA[0] = H;
color->u.HSVA[1] = S;
color->u.HSVA[2] = V;
color->u.HSVA[3] = 1.0; /* opaque */
break;
case RGBA_BYTE:
hsv2rgb(H, S, V, &R, &G, &B);
......@@ -380,59 +383,47 @@ int colorxlate(char *str, gvcolor_t * color, color_type_t target_type)
if ((last == NULL)
|| (last->name[0] != fake.name[0])
|| (strcmp(last->name, fake.name))) {
last = (hsbcolor_t *) bsearch((void *) &fake,
last = (hsvrgbacolor_t *) bsearch((void *) &fake,
(void *) color_lib,
sizeof(color_lib) /
sizeof(hsbcolor_t), sizeof(fake),
sizeof(hsvrgbacolor_t), sizeof(fake),
colorcmpf);
}
if (last != NULL) {
switch (target_type) {
case HSV_DOUBLE:
color->u.HSV[0] = ((double) last->h) / 255.0;
color->u.HSV[1] = ((double) last->s) / 255.0;
color->u.HSV[2] = ((double) last->b) / 255.0;
case HSVA_DOUBLE:
color->u.HSVA[0] = ((double) last->h) / 255.0;
color->u.HSVA[1] = ((double) last->s) / 255.0;
color->u.HSVA[2] = ((double) last->b) / 255.0;
color->u.HSVA[3] = ((double) last->a) / 255.0;
break;
case RGBA_BYTE:
H = (last->h) / 255.0;
S = (last->s) / 255.0;
V = (last->b) / 255.0;
hsv2rgb(H, S, V, &R, &G, &B);
color->u.rgba[0] = (int) (R * 255);
color->u.rgba[1] = (int) (G * 255);
color->u.rgba[2] = (int) (B * 255);
color->u.rgba[3] = 255; /* opaque */
color->u.rgba[0] = last->r;
color->u.rgba[1] = last->g;
color->u.rgba[2] = last->b;
color->u.rgba[3] = last->a;
break;
case CMYK_BYTE:
H = (last->h) / 255.0;
S = (last->s) / 255.0;
V = (last->b) / 255.0;
hsv2rgb(H, S, V, &R, &G, &B);
R = (last->r) / 255.0;
G = (last->g) / 255.0;
B = (last->b) / 255.0;
rgb2cmyk(R, G, B, &C, &M, &Y, &K);
color->u.cmyk[0] = (int) C *255;
color->u.cmyk[1] = (int) M *255;
color->u.cmyk[2] = (int) Y *255;
color->u.cmyk[3] = (int) K *255;
color->u.cmyk[0] = (int) C * 255;
color->u.cmyk[1] = (int) M * 255;
color->u.cmyk[2] = (int) Y * 255;
color->u.cmyk[3] = (int) K * 255;
break;
case RGBA_WORD:
H = (last->h) / 255.0;
S = (last->s) / 255.0;
V = (last->b) / 255.0;
hsv2rgb(H, S, V, &R, &G, &B);
color->u.rrggbbaa[0] = (int) (R * 65535);
color->u.rrggbbaa[1] = (int) (G * 65535);
color->u.rrggbbaa[2] = (int) (B * 65535);
color->u.rrggbbaa[3] = 65535; /* opaque */
color->u.rrggbbaa[0] = last->r * 65535 / 255;
color->u.rrggbbaa[1] = last->g * 65535 / 255;
color->u.rrggbbaa[2] = last->b * 65535 / 255;
color->u.rrggbbaa[3] = last->a * 65535 / 255;
break;
case RGBA_DOUBLE:
H = (last->h) / 255.0;
S = (last->s) / 255.0;
V = (last->b) / 255.0;
hsv2rgb(H, S, V, &R, &G, &B);
color->u.RGBA[0] = R;
color->u.RGBA[1] = G;
color->u.RGBA[2] = B;
color->u.RGBA[3] = 1.0; /* opaque */
color->u.RGBA[0] = last->r / 255.0;
color->u.RGBA[1] = last->g / 255.0;
color->u.RGBA[2] = last->b / 255.0;
color->u.RGBA[3] = last->a / 255.0;
break;
case COLOR_STRING:
break;
......@@ -445,8 +436,9 @@ int colorxlate(char *str, gvcolor_t * color, color_type_t target_type)
/* if we're still here then we failed to find a valid color spec */
rc = COLOR_UNKNOWN;
switch (target_type) {
case HSV_DOUBLE:
color->u.HSV[0] = color->u.HSV[1] = color->u.HSV[2] = 0.0;
case HSVA_DOUBLE:
color->u.HSVA[0] = color->u.HSVA[1] = color->u.HSVA[2] = 0.0;
color->u.HSVA[3] = 1.0; /* opaque */
break;
case RGBA_BYTE:
color->u.rgba[0] = color->u.rgba[1] = color->u.rgba[2] = 0;
......@@ -457,8 +449,7 @@ int colorxlate(char *str, gvcolor_t * color, color_type_t target_type)
color->u.cmyk[1] = color->u.cmyk[2] = color->u.cmyk[3] = 0;
break;
case RGBA_WORD:
color->u.rrggbbaa[0] =
color->u.rrggbbaa[1] = color->u.rrggbbaa[2] = 0;
color->u.rrggbbaa[0] = color->u.rrggbbaa[1] = color->u.rrggbbaa[2] = 0;
color->u.rrggbbaa[3] = 65535; /* opaque */
break;
case RGBA_DOUBLE:
......
......@@ -134,9 +134,9 @@ static void mp_set_color(char *name)
gvcolor_t color;
if (strcmp(name, S[SP].color)) {
colorxlate(name, &color, HSV_DOUBLE);
colorxlate(name, &color, HSVA_DOUBLE);
fprintf(Output_file, "%% GV set color: %.3f %.3f %.3f %scolor\n",
color.u.HSV[0], color.u.HSV[1], color.u.HSV[2], op[Obj]);
color.u.HSVA[0], color.u.HSVA[1], color.u.HSVA[2], op[Obj]);
}
S[SP].color = name;
}
......
......@@ -455,9 +455,9 @@ static void pic_set_color(char *name)
gvcolor_t color;
S[SP].color = name;
colorxlate(name, &color, HSV_DOUBLE);
colorxlate(name, &color, HSVA_DOUBLE);
/* just v used to set grayscale value */
fprintf(Output_file, "setfillval %f\n", color.u.HSV[2]);
fprintf(Output_file, "setfillval %f\n", color.u.HSVA[2]);
}
static void pic_set_style(char **s)
......@@ -535,8 +535,8 @@ static void pic_polygon(point * A, int n, int filled)
if (filled) {
gvcolor_t color;
colorxlate(S[SP].color, &color, HSV_DOUBLE);
fprintf(Output_file, "setfillval %f\n", color.u.HSV[2]);
colorxlate(S[SP].color, &color, HSVA_DOUBLE);
fprintf(Output_file, "setfillval %f\n", color.u.HSVA[2]);
}
fprintf(Output_file, "box attrs%d %swid %.5f ht %.5f at (%.5f,%.5f);\n", SP, filled ? "fill " : "", Scale * fabs(pf1.x - pf2.x), Scale * fabs(pf1.y - pf2.y), /* width, height */
Scale * (pf1.x + pf2.x) / 2.0, Scale * (pf1.y + pf2.y) / 2.0); /* center coordinates */
......
......@@ -60,9 +60,10 @@ static void psgen_begin_job(GVJ_t * job)
{
last_fontname = NULL;
last_fontsize = 0.0;
last_color.u.HSV[0] = 0;
last_color.u.HSV[1] = 0;
last_color.u.HSV[2] = 0;
last_color.u.HSVA[0] = 0.0;
last_color.u.HSVA[1] = 0.0;
last_color.u.HSVA[2] = 0.0;
last_color.u.HSVA[3] = 1.0; /* opaque */
fprintf(job->output_file, "%%!PS-Adobe-2.0\n");
fprintf(job->output_file, "%%%%Creator: %s version %s (%s)\n",
......@@ -117,6 +118,10 @@ static void psgen_begin_page(GVJ_t * job)
{
box pbr = job->pageBoundingBox;
// FIXME
point page = {0,0};
int N_pages = 0;
fprintf(job->output_file, "%%%%Page: %d %d\n",
job->common->viewNum + 1, job->common->viewNum + 1);
if (job->common->show_boxes == NULL)
......@@ -124,13 +129,19 @@ static void psgen_begin_page(GVJ_t * job)
pbr.LL.x, pbr.LL.y, pbr.UR.x, pbr.UR.y);
fprintf(job->output_file, "%%%%PageOrientation: %s\n",
(job->rotation ? "Landscape" : "Portrait"));
#if 0
if (Output_lang == PDF)
fprintf(Output_file, "<< /PageSize [%d %d] >> setpagedevice\n",
sz.x, sz.y);
#endif
if (job->common->show_boxes == NULL)
fprintf(job->output_file, "gsave\n%d %d %d %d boxprim clip newpath\n",
pbr.LL.x, pbr.LL.y, pbr.UR.x, pbr.UR.y);
fprintf(job->output_file, "gsave %g %g set_scale %d rotate %g %g translate\n",
job->scale.x, job->scale.y,
job->rotation,
job->translation.x, job->translation.y);
fprintf(job->output_file, "%d %d %d beginpage\n", page.x, page.y, N_pages);
fprintf(job->output_file, "%g %g set_scale %d rotate %g %g translate\n",
job->scale.x, job->scale.y,
job->rotation,
job->translation.x, job->translation.y);
/* Define the size of the PS canvas */
if (job->render.id == FORMAT_PS2) {
......@@ -145,8 +156,8 @@ static void psgen_begin_page(GVJ_t * job)
static void psgen_end_page(GVJ_t * job)
{
if (job->common->show_boxes)
cat_libfile(job->output_file, NULL, job->common->show_boxes + 1);
// if (job->common->show_boxes)
// cat_libfile(job->output_file, NULL, job->common->show_boxes + 1);
/* the showpage is really a no-op, but at least one PS processor
* out there needs to see this literal token. endpage does the real work.
*/
......@@ -281,21 +292,24 @@ static void ps_set_color(GVJ_t *job, gvcolor_t *color)
if (job->obj->g)
objtype = "graph";
else if (job->obj->sg)
objtype = "cluster";
objtype = "graph";
else if (job->obj->n)
objtype = "node";
else if (job->obj->e)
objtype = "edge";
else
objtype = "sethsb";
if ( last_color.u.HSV[0] != color->u.HSV[0]
|| last_color.u.HSV[1] != color->u.HSV[1]
|| last_color.u.HSV[2] != color->u.HSV[2]) {
if ( last_color.u.HSVA[0] != color->u.HSVA[0]
|| last_color.u.HSVA[1] != color->u.HSVA[1]
|| last_color.u.HSVA[2] != color->u.HSVA[2]
|| last_color.u.HSVA[3] != color->u.HSVA[3]
|| (job->obj->g && (job->obj->g == job->obj->g->root))) {
fprintf(job->output_file, "%.3f %.3f %.3f %scolor\n",
color->u.HSV[0], color->u.HSV[1], color->u.HSV[2], objtype);
last_color.u.HSV[0] = color->u.HSV[0];
last_color.u.HSV[1] = color->u.HSV[1];
last_color.u.HSV[2] = color->u.HSV[2];
color->u.HSVA[0], color->u.HSVA[1], color->u.HSVA[2], objtype);
last_color.u.HSVA[0] = color->u.HSVA[0];
last_color.u.HSVA[1] = color->u.HSVA[1];
last_color.u.HSVA[2] = color->u.HSVA[2];
last_color.u.HSVA[3] = color->u.HSVA[3];
}
}
}
......@@ -305,6 +319,9 @@ static void psgen_textpara(GVJ_t * job, pointf p, textpara_t * para)
double adj, sz;
char *str;
if (job->style->pencolor.u.HSVA[3] < .5)
return; /* skip transparent text */
ps_set_color(job, &(job->style->pencolor));
if (para->fontname) {
sz = para->fontsize;
......@@ -354,15 +371,17 @@ static void psgen_ellipse(GVJ_t * job, pointf * A, int filled)
{
/* A[] contains 2 points: the center and corner. */
if (filled) {
if (filled && job->style->fillcolor.u.HSVA[3] > .5) {
ps_set_color(job, &(job->style->fillcolor));
fprintf(job->output_file, "%g %g %g %g ellipse_path fill\n",
A[0].x, A[0].y, fabs(A[1].x - A[0].x), fabs(A[1].y - A[0].y));
}
ps_set_pen_style(job);
ps_set_color(job, &(job->style->pencolor));
fprintf(job->output_file, "%g %g %g %g ellipse_path stroke\n",
A[0].x, A[0].y, fabs(A[1].x - A[0].x), fabs(A[1].y - A[0].y));
if (job->style->pencolor.u.HSVA[3] > .5) {
ps_set_pen_style(job);
ps_set_color(job, &(job->style->pencolor));
fprintf(job->output_file, "%g %g %g %g ellipse_path stroke\n",
A[0].x, A[0].y, fabs(A[1].x - A[0].x), fabs(A[1].y - A[0].y));
}
}
static void
......@@ -371,7 +390,7 @@ psgen_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
{
int j;
if (filled) {
if (filled && job->style->fillcolor.u.HSVA[3] > .5) {
ps_set_color(job, &(job->style->fillcolor));
fprintf(job->output_file, "newpath %g %g moveto\n", A[0].x, A[0].y);
for (j = 1; j < n; j += 3)
......@@ -380,45 +399,51 @@ psgen_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
A[j + 2].y);
fprintf(job->output_file, "closepath fill\n");
}
ps_set_pen_style(job);
ps_set_color(job, &(job->style->pencolor));
fprintf(job->output_file, "newpath %g %g moveto\n", A[0].x, A[0].y);
for (j = 1; j < n; j += 3)
fprintf(job->output_file, "%g %g %g %g %g %g curveto\n",
A[j].x, A[j].y, A[j + 1].x, A[j + 1].y, A[j + 2].x,
A[j + 2].y);
fprintf(job->output_file, "stroke\n");
if (job->style->pencolor.u.HSVA[3] > .5) {
ps_set_pen_style(job);
ps_set_color(job, &(job->style->pencolor));
fprintf(job->output_file, "newpath %g %g moveto\n", A[0].x, A[0].y);
for (j = 1; j < n; j += 3)
fprintf(job->output_file, "%g %g %g %g %g %g curveto\n",
A[j].x, A[j].y, A[j + 1].x, A[j + 1].y, A[j + 2].x,
A[j + 2].y);
fprintf(job->output_file, "stroke\n");
}
}
static void psgen_polygon(GVJ_t * job, pointf * A, int n, int filled)
{
int j;
if (filled) {
if (filled && job->style->fillcolor.u.HSVA[3] > .5) {
ps_set_color(job, &(job->style->fillcolor));
fprintf(job->output_file, "newpath %g %g moveto\n", A[0].x, A[0].y);
for (j = 1; j < n; j++)
fprintf(job->output_file, "%g %g lineto\n", A[j].x, A[j].y);
fprintf(job->output_file, "closepath fill\n");
}
ps_set_pen_style(job);
ps_set_color(job, &(job->style->pencolor));
fprintf(job->output_file, "newpath %g %g moveto\n", A[0].x, A[0].y);
for (j = 1; j < n; j++)
fprintf(job->output_file, "%g %g lineto\n", A[j].x, A[j].y);
fprintf(job->output_file, "closepath stroke\n");
if (job->style->pencolor.u.HSVA[3] > .5) {
ps_set_pen_style(job);
ps_set_color(job, &(job->style->pencolor));
fprintf(job->output_file, "newpath %g %g moveto\n", A[0].x, A[0].y);
for (j = 1; j < n; j++)
fprintf(job->output_file, "%g %g lineto\n", A[j].x, A[j].y);
fprintf(job->output_file, "closepath stroke\n");
}
}
static void psgen_polyline(GVJ_t * job, pointf * A, int n)
{
int j;
ps_set_pen_style(job);
ps_set_color(job, &(job->style->pencolor));
fprintf(job->output_file, "newpath %g %g moveto\n", A[0].x, A[0].y);
for (j = 1; j < n; j++)
fprintf(job->output_file, "%g %g lineto\n", A[j].x, A[j].y);
fprintf(job->output_file, "stroke\n");
if (job->style->pencolor.u.HSVA[3] > .5) {
ps_set_pen_style(job);
ps_set_color(job, &(job->style->pencolor));
fprintf(job->output_file, "newpath %g %g moveto\n", A[0].x, A[0].y);
for (j = 1; j < n; j++)
fprintf(job->output_file, "%g %g lineto\n", A[j].x, A[j].y);
fprintf(job->output_file, "stroke\n");
}
}
static void psgen_comment(GVJ_t * job, char *str)
......@@ -465,7 +490,7 @@ static gvrender_features_t psgen_features = {
{72.,72.}, /* default dpi */
NULL, /* knowncolors */
0, /* sizeof knowncolors */
HSV_DOUBLE, /* color_type */
HSVA_DOUBLE, /* color_type */
NULL, /* device */
"ps", /* gvloadimage target for usershapes */
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment