1
/* $Header: /home/cvsroot/dvipdfmx/src/spc_util.c,v 1.17 2011/03/06 03:14:15 chofchof Exp $
3
This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
5
Copyright (C) 2007 by Jin-Hwan Cho and Shunsaku Hirata,
6
the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
8
Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
10
This program is free software; you can redistribute it and/or modify
11
it under the terms of the GNU General Public License as published by
12
the Free Software Foundation; either version 2 of the License, or
13
(at your option) any later version.
15
This program is distributed in the hope that it will be useful,
16
but WITHOUT ANY WARRANTY; without even the implied warranty of
17
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
GNU General Public License for more details.
20
You should have received a copy of the GNU General Public License
21
along with this program; if not, write to the Free Software
22
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
45
#define ISBLANK(c) ((c) == ' ' || (c) == '\t')
48
skip_blank (const char **pp, const char *endptr)
51
for ( ; p < endptr && ISBLANK(*p); p++);
57
static int pdf_color_namedcolor (pdf_color *color, const char *colorname);
60
spc_util_read_numbers (double *values, int num_values,
61
struct spc_env *spe, struct spc_arg *args)
66
skip_blank(&args->curptr, args->endptr);
69
args->curptr < args->endptr; ) {
70
q = parse_float_decimal(&args->curptr, args->endptr);
74
values[count] = atof(q);
76
skip_blank(&args->curptr, args->endptr);
85
rgb_color_from_hsv (pdf_color *color, double h, double s, double v)
91
double h6, f, v1, v2, v3;
93
h6 = h * 6; /* 360 / 60 */
98
v3 = v * (1 - s * (1 - f));
100
case 0: r = v ; g = v3; b = v1; break;
101
case 1: r = v2; g = v ; b = v1; break;
102
case 2: r = v1; g = v ; b = v3; break;
103
case 3: r = v1; g = v2; b = v ; break;
104
case 4: r = v3; g = v1; b = v ; break;
105
case 5: r = v ; g = v1; b = v2; break;
106
case 6: r = v ; g = v1; b = v2; break;
109
pdf_color_rgbcolor(color, r, g, b);
113
spc_read_color_color (struct spc_env *spe, pdf_color *colorspec, struct spc_arg *ap)
120
q = parse_c_ident(&ap->curptr, ap->endptr);
122
spc_warn(spe, "No valid color specified?");
125
skip_blank(&ap->curptr, ap->endptr);
127
if (!strcmp(q, "rgb")) { /* Handle rgb color */
128
nc = spc_util_read_numbers(cv, 3, spe, ap);
130
spc_warn(spe, "Invalid value for RGB color specification.");
133
pdf_color_rgbcolor(colorspec, cv[0], cv[1], cv[2]);
135
} else if (!strcmp(q, "cmyk")) { /* Handle cmyk color */
136
nc = spc_util_read_numbers(cv, 4, spe, ap);
138
spc_warn(spe, "Invalid value for CMYK color specification.");
141
pdf_color_cmykcolor(colorspec, cv[0], cv[1], cv[2], cv[3]);
143
} else if (!strcmp(q, "gray")) { /* Handle gray */
144
nc = spc_util_read_numbers(cv, 1, spe, ap);
146
spc_warn(spe, "Invalid value for gray color specification.");
149
pdf_color_graycolor(colorspec, cv[0]);
151
} else if (!strcmp(q, "hsb")) {
152
nc = spc_util_read_numbers(cv, 3, spe, ap);
154
spc_warn(spe, "Invalid value for HSB color specification.");
157
rgb_color_from_hsv(colorspec, cv[0], cv[1], cv[2]);
158
spc_warn(spe, "HSB color converted to RGB: hsb: <%g, %g, %g> ==> rgb: <%g, %g, %g>",
160
colorspec->values[0], colorspec->values[1], colorspec->values[2]);
162
} else { /* Must be a "named" color */
163
error = pdf_color_namedcolor(colorspec, q);
165
spc_warn(spe, "Unrecognized color name: %s", q);
172
/* Argumaent for this is PDF_Number or PDF_Array.
173
* But we ignore that since we don't want to add
174
* dependency to pdfxxx and @foo can not be
175
* allowed for color specification. "pdf" here
176
* means pdf: special syntax.
179
spc_read_color_pdf (struct spc_env *spe, pdf_color *colorspec, struct spc_arg *ap)
181
double cv[4]; /* at most four */
186
skip_blank(&ap->curptr, ap->endptr);
188
if (ap->curptr[0] == '[') {
189
ap->curptr++; skip_blank(&ap->curptr, ap->endptr);
193
nc = spc_util_read_numbers(cv, 4, spe, ap);
196
pdf_color_graycolor(colorspec, cv[0]);
199
pdf_color_rgbcolor (colorspec, cv[0], cv[1], cv[2]);
202
pdf_color_cmykcolor(colorspec, cv[0], cv[1], cv[2], cv[3]);
205
/* Try to read the color names defined in dvipsname.def */
206
q = parse_c_ident(&ap->curptr, ap->endptr);
208
error = pdf_color_namedcolor(colorspec, q);
210
spc_warn(spe, "Unrecognized color name: %s, keep the current color", q);
219
skip_blank(&ap->curptr, ap->endptr);
220
if (ap->curptr >= ap->endptr || ap->curptr[0] != ']') {
221
spc_warn(spe, "Unbalanced '[' and ']' in color specification.");
232
/* This is for reading *single* color specification. */
234
spc_util_read_colorspec (struct spc_env *spe, pdf_color *colorspec, struct spc_arg *ap)
236
ASSERT(colorspec && spe && ap);
238
skip_blank(&ap->curptr, ap->endptr);
239
if (ap->curptr >= ap->endptr) {
242
return spc_read_color_color(spe, colorspec, ap);
246
spc_util_read_pdfcolor (struct spc_env *spe, pdf_color *colorspec, struct spc_arg *ap, pdf_color *defaultcolor)
250
ASSERT(colorspec && spe && ap);
252
skip_blank(&ap->curptr, ap->endptr);
253
if (ap->curptr >= ap->endptr) {
256
error = spc_read_color_pdf(spe, colorspec, ap);
257
if (error < 0 && defaultcolor) {
258
pdf_color_copycolor(colorspec, defaultcolor);
264
/* This need to allow 'true' prefix for unit and
265
* length value must be divided by current magnification.
268
spc_util_read_length (struct spc_env *spe, double *vp /* ret. */, struct spc_arg *ap)
272
const char *ukeys[] = {
278
"pt", "in", "cm", "mm", "bp", NULL
282
q = parse_float_decimal(&ap->curptr, ap->endptr);
289
q = parse_c_ident(&ap->curptr, ap->endptr);
291
if (strlen(q) > strlen("true") &&
292
!memcmp(q, "true", strlen("true"))) {
293
u /= spe->mag != 0.0 ? spe->mag : 1.0; /* inverse magnify */
296
for (k = 0; ukeys[k] && strcmp(ukeys[k], q); k++);
298
case K_UNIT__PT: u *= 72.0 / 72.27; break;
299
case K_UNIT__IN: u *= 72.0; break;
300
case K_UNIT__CM: u *= 72.0 / 2.54 ; break;
301
case K_UNIT__MM: u *= 72.0 / 25.4 ; break;
302
case K_UNIT__BP: u *= 1.0 ; break;
304
spc_warn(spe, "Unknown unit of measure: %s", q);
317
* Compute a transformation matrix
318
* transformations are applied in the following
319
* order: scaling, rotate, displacement.
322
make_transmatrix (pdf_tmatrix *M,
323
double xoffset, double yoffset,
324
double xscale, double yscale,
332
M->a = xscale * c; M->b = xscale * s;
333
M->c = -yscale * s; M->d = yscale * c;
334
M->e = xoffset; M->f = yoffset;
338
spc_read_dimtrns_dvips (struct spc_env *spe, transform_info *t, struct spc_arg *ap)
340
static const char *_dtkeys[] = {
341
#define K_TRN__HOFFSET 0
342
#define K_TRN__VOFFSET 1
343
"hoffset", "voffset",
344
#define K_DIM__HSIZE 2
345
#define K_DIM__VSIZE 3
347
#define K_TRN__HSCALE 4
348
#define K_TRN__VSCALE 5
350
#define K_TRN__ANGLE 6
356
#define K_DIM__URX 10
357
#define K_DIM__URY 11
358
"llx", "lly", "urx", "ury",
359
#define K_DIM__RWI 12
360
#define K_DIM__RHI 13
364
double xoffset, yoffset, xscale, yscale, rotate;
367
xoffset = yoffset = rotate = 0.0; xscale = yscale = 1.0;
369
skip_blank(&ap->curptr, ap->endptr);
370
while (!error && ap->curptr < ap->endptr) {
374
kp = parse_c_ident(&ap->curptr, ap->endptr);
378
for (k = 0; _dtkeys[k] && strcmp(kp, _dtkeys[k]); k++);
380
spc_warn(spe, "Unrecognized dimension/transformation key: %s", kp);
386
skip_blank(&ap->curptr, ap->endptr);
388
t->flags |= INFO_DO_CLIP;
390
continue; /* not key-value */
393
if (ap->curptr < ap->endptr && ap->curptr[0] == '=') {
395
skip_blank(&ap->curptr, ap->endptr);
399
if (ap->curptr[0] == '\'' || ap->curptr[0] == '\"') {
400
char qchr = ap->curptr[0];
402
skip_blank(&ap->curptr, ap->endptr);
403
vp = parse_float_decimal(&ap->curptr, ap->endptr);
404
skip_blank(&ap->curptr, ap->endptr);
405
if (vp && qchr != ap->curptr[0]) {
406
spc_warn(spe, "Syntax error in dimension/transformation specification.");
408
RELEASE(vp); vp = NULL;
412
vp = parse_float_decimal(&ap->curptr, ap->endptr);
415
spc_warn(spe, "Missing value for dimension/transformation: %s", kp);
432
t->flags |= INFO_HAS_WIDTH;
435
t->height = atof(vp);
436
t->flags |= INFO_HAS_HEIGHT;
439
xscale = atof(vp) / 100.0;
442
yscale = atof(vp) / 100.0;
445
rotate = M_PI * atof(vp) / 180.0;
448
t->bbox.llx = atof(vp);
449
t->flags |= INFO_HAS_USER_BBOX;
452
t->bbox.lly = atof(vp);
453
t->flags |= INFO_HAS_USER_BBOX;
456
t->bbox.urx = atof(vp);
457
t->flags |= INFO_HAS_USER_BBOX;
460
t->bbox.ury = atof(vp);
461
t->flags |= INFO_HAS_USER_BBOX;
464
t->width = atof(vp) / 10.0;
465
t->flags |= INFO_HAS_WIDTH;
468
t->height = atof(vp) / 10.0;
469
t->flags |= INFO_HAS_HEIGHT;
472
skip_blank(&ap->curptr, ap->endptr);
475
make_transmatrix(&(t->matrix), xoffset, yoffset, xscale, yscale, rotate);
482
spc_read_dimtrns_pdfm (struct spc_env *spe, transform_info *p, struct spc_arg *ap, long *page_no)
484
int has_scale, has_xscale, has_yscale, has_rotate, has_matrix;
485
const char *_dtkeys[] = {
486
#define K_DIM__WIDTH 0
487
#define K_DIM__HEIGHT 1
488
#define K_DIM__DEPTH 2
489
"width", "height", "depth",
490
#define K_TRN__SCALE 3
491
#define K_TRN__XSCALE 4
492
#define K_TRN__YSCALE 5
493
#define K_TRN__ROTATE 6
494
"scale", "xscale", "yscale", "rotate", /* See "Dvipdfmx User's Manual", p.5 */
495
#define K_TRN__BBOX 7
497
#define K_TRN__MATRIX 8
508
double xscale, yscale, rotate;
511
has_xscale = has_yscale = has_scale = has_rotate = has_matrix = 0;
512
xscale = yscale = 1.0; rotate = 0.0;
513
p->flags |= INFO_DO_CLIP; /* default: do clipping */
514
p->flags &= ~INFO_DO_HIDE; /* default: do clipping */
516
skip_blank(&ap->curptr, ap->endptr);
518
while (!error && ap->curptr < ap->endptr) {
522
kp = parse_c_ident(&ap->curptr, ap->endptr);
526
skip_blank(&ap->curptr, ap->endptr);
527
for (k = 0; _dtkeys[k] && strcmp(_dtkeys[k], kp); k++);
530
error = spc_util_read_length(spe, &p->width , ap);
531
p->flags |= INFO_HAS_WIDTH;
534
error = spc_util_read_length(spe, &p->height, ap);
535
p->flags |= INFO_HAS_HEIGHT;
538
error = spc_util_read_length(spe, &p->depth , ap);
539
p->flags |= INFO_HAS_HEIGHT;
542
vp = parse_float_decimal(&ap->curptr, ap->endptr);
546
xscale = yscale = atof(vp);
552
vp = parse_float_decimal(&ap->curptr, ap->endptr);
562
vp = parse_float_decimal(&ap->curptr, ap->endptr);
572
vp = parse_float_decimal(&ap->curptr, ap->endptr);
576
rotate = M_PI * atof(vp) / 180.0;
584
if (spc_util_read_numbers(v, 4, spe, ap) != 4)
591
p->flags |= INFO_HAS_USER_BBOX;
598
if (spc_util_read_numbers(v, 6, spe, ap) != 6)
601
pdf_setmatrix(&(p->matrix), v[0], v[1], v[2], v[3], v[4], v[5]);
607
vp = parse_float_decimal(&ap->curptr, ap->endptr);
612
p->flags |= INFO_DO_CLIP;
614
p->flags &= ~INFO_DO_CLIP;
621
if (page_no && spc_util_read_numbers(&page, 1, spe, ap) == 1)
622
*page_no = (long) page;
628
p->flags |= INFO_DO_HIDE;
635
spc_warn(spe, "Unrecognized key or invalid value for dimension/transformation: %s", kp);
637
skip_blank(&ap->curptr, ap->endptr);
642
/* Check consistency */
643
if (has_xscale && (p->flags & INFO_HAS_WIDTH)) {
644
spc_warn(spe, "Can't supply both width and xscale. Ignore xscale.");
646
} else if (has_yscale &&
647
(p->flags & INFO_HAS_HEIGHT)) {
648
spc_warn(spe, "Can't supply both height/depth and yscale. Ignore yscale.");
650
} else if (has_scale &&
651
(has_xscale || has_yscale)) {
652
spc_warn(spe, "Can't supply overall scale along with axis scales.");
654
} else if (has_matrix &&
655
(has_scale || has_xscale || has_yscale || has_rotate)) {
656
spc_warn(spe, "Can't supply transform matrix along with scales or rotate. Ignore scales and rotate.");
661
make_transmatrix(&(p->matrix), 0.0, 0.0, xscale, yscale, rotate);
664
if (!(p->flags & INFO_HAS_USER_BBOX)) {
665
p->flags &= ~INFO_DO_CLIP; /* no clipping needed */
672
spc_util_read_dimtrns (struct spc_env *spe, transform_info *ti, struct spc_arg *args, long *page_no, int syntax)
674
ASSERT(ti && spe && args);
678
return spc_read_dimtrns_dvips(spe, ti, args);
680
return spc_read_dimtrns_pdfm (spe, ti, args, page_no);
694
#define gray(g) {1, {g}}
695
#define rgb8(r,g,b) {3, {((r)/255.0), ((g)/255.0), ((b)/255.0), 0.0}}
696
#define cmyk(c,m,y,k) {4, {(c), (m), (y), (k)}}
698
static struct colordef_
703
{"GreenYellow", cmyk(0.15, 0.00, 0.69, 0.00)},
704
{"Yellow", cmyk(0.00, 0.00, 1.00, 0.00)},
705
{"Goldenrod", cmyk(0.00, 0.10, 0.84, 0.00)},
706
{"Dandelion", cmyk(0.00, 0.29, 0.84, 0.00)},
707
{"Apricot", cmyk(0.00, 0.32, 0.52, 0.00)},
708
{"Peach", cmyk(0.00, 0.50, 0.70, 0.00)},
709
{"Melon", cmyk(0.00, 0.46, 0.50, 0.00)},
710
{"YellowOrange", cmyk(0.00, 0.42, 1.00, 0.00)},
711
{"Orange", cmyk(0.00, 0.61, 0.87, 0.00)},
712
{"BurntOrange", cmyk(0.00, 0.51, 1.00, 0.00)},
713
{"Bittersweet", cmyk(0.00, 0.75, 1.00, 0.24)},
714
{"RedOrange", cmyk(0.00, 0.77, 0.87, 0.00)},
715
{"Mahogany", cmyk(0.00, 0.85, 0.87, 0.35)},
716
{"Maroon", cmyk(0.00, 0.87, 0.68, 0.32)},
717
{"BrickRed", cmyk(0.00, 0.89, 0.94, 0.28)},
718
{"Red", cmyk(0.00, 1.00, 1.00, 0.00)},
719
{"OrangeRed", cmyk(0.00, 1.00, 0.50, 0.00)},
720
{"RubineRed", cmyk(0.00, 1.00, 0.13, 0.00)},
721
{"WildStrawberry", cmyk(0.00, 0.96, 0.39, 0.00)},
722
{"Salmon", cmyk(0.00, 0.53, 0.38, 0.00)},
723
{"CarnationPink", cmyk(0.00, 0.63, 0.00, 0.00)},
724
{"Magenta", cmyk(0.00, 1.00, 0.00, 0.00)},
725
{"VioletRed", cmyk(0.00, 0.81, 0.00, 0.00)},
726
{"Rhodamine", cmyk(0.00, 0.82, 0.00, 0.00)},
727
{"Mulberry", cmyk(0.34, 0.90, 0.00, 0.02)},
728
{"RedViolet", cmyk(0.07, 0.90, 0.00, 0.34)},
729
{"Fuchsia", cmyk(0.47, 0.91, 0.00, 0.08)},
730
{"Lavender", cmyk(0.00, 0.48, 0.00, 0.00)},
731
{"Thistle", cmyk(0.12, 0.59, 0.00, 0.00)},
732
{"Orchid", cmyk(0.32, 0.64, 0.00, 0.00)},
733
{"DarkOrchid", cmyk(0.40, 0.80, 0.20, 0.00)},
734
{"Purple", cmyk(0.45, 0.86, 0.00, 0.00)},
735
{"Plum", cmyk(0.50, 1.00, 0.00, 0.00)},
736
{"Violet", cmyk(0.79, 0.88, 0.00, 0.00)},
737
{"RoyalPurple", cmyk(0.75, 0.90, 0.00, 0.00)},
738
{"BlueViolet", cmyk(0.86, 0.91, 0.00, 0.04)},
739
{"Periwinkle", cmyk(0.57, 0.55, 0.00, 0.00)},
740
{"CadetBlue", cmyk(0.62, 0.57, 0.23, 0.00)},
741
{"CornflowerBlue", cmyk(0.65, 0.13, 0.00, 0.00)},
742
{"MidnightBlue", cmyk(0.98, 0.13, 0.00, 0.43)},
743
{"NavyBlue", cmyk(0.94, 0.54, 0.00, 0.00)},
744
{"RoyalBlue", cmyk(1.00, 0.50, 0.00, 0.00)},
745
{"Blue", cmyk(1.00, 1.00, 0.00, 0.00)},
746
{"Cerulean", cmyk(0.94, 0.11, 0.00, 0.00)},
747
{"Cyan", cmyk(1.00, 0.00, 0.00, 0.00)},
748
{"ProcessBlue", cmyk(0.96, 0.00, 0.00, 0.00)},
749
{"SkyBlue", cmyk(0.62, 0.00, 0.12, 0.00)},
750
{"Turquoise", cmyk(0.85, 0.00, 0.20, 0.00)},
751
{"TealBlue", cmyk(0.86, 0.00, 0.34, 0.02)},
752
{"Aquamarine", cmyk(0.82, 0.00, 0.30, 0.00)},
753
{"BlueGreen", cmyk(0.85, 0.00, 0.33, 0.00)},
754
{"Emerald", cmyk(1.00, 0.00, 0.50, 0.00)},
755
{"JungleGreen", cmyk(0.99, 0.00, 0.52, 0.00)},
756
{"SeaGreen", cmyk(0.69, 0.00, 0.50, 0.00)},
757
{"Green", cmyk(1.00, 0.00, 1.00, 0.00)},
758
{"ForestGreen", cmyk(0.91, 0.00, 0.88, 0.12)},
759
{"PineGreen", cmyk(0.92, 0.00, 0.59, 0.25)},
760
{"LimeGreen", cmyk(0.50, 0.00, 1.00, 0.00)},
761
{"YellowGreen", cmyk(0.44, 0.00, 0.74, 0.00)},
762
{"SpringGreen", cmyk(0.26, 0.00, 0.76, 0.00)},
763
{"OliveGreen", cmyk(0.64, 0.00, 0.95, 0.40)},
764
{"RawSienna", cmyk(0.00, 0.72, 1.00, 0.45)},
765
{"Sepia", cmyk(0.00, 0.83, 1.00, 0.70)},
766
{"Brown", cmyk(0.00, 0.81, 1.00, 0.60)},
767
{"Tan", cmyk(0.14, 0.42, 0.56, 0.00)},
768
/* Adobe Reader 7 and 8 had problem when gray and cmyk black colors
769
* are mixed. No problem with Previewer.app.
770
* It happens when \usepackage[dvipdfm]{graphicx} and then called
771
* \usepackage{color} without dvipdfm option. */
773
{"Black", gray(0.0)},
774
{"White", gray(1.0)},
780
pdf_color_namedcolor (pdf_color *color, const char *name)
783
for (i = 0; colordefs[i].key; i++) {
784
if (!strcmp(colordefs[i].key, name)) {
785
pdf_color_copycolor(color, &colordefs[i].color);