3 This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
5 Copyright (C) 2007-2012 by Jin-Hwan Cho and Shunsaku Hirata,
6 the dvipdfmx project team.
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);