1 /* Hello, Emacs, this is -*-C-*-
2 * $Id: pdf.trm,v 1.68.2.9 2008/12/12 07:14:11 sfeam Exp $
5 /*------------------------------
8 This file is included by ../term.c.
10 This driver uses PDFlib from www.pdflib.com
15 broeker@physik.rwth-aachen.de
17 Licence: see the gnuplot copyright (to be merged into here...)
19 Options: can #define PDF_DONT_COMPRESS to avoid PDF output
20 generated being compressed (by the 'deflate' algorithm as used
21 in 'zip' or 'gzip'). That helps in debugging.
23 ------------------------------*/
25 /* CODEME: Add patterned lines (?). */
27 /* PM3D support by Johannes Zellner <johannes@zellner.org>, May-15-2002 */
28 /* set_color fixes by Petr Mikulik <mikulik@physics.muni.cz>, June-10-2002 */
29 /* image support by Ethan A Merritt <merritt@u.washington.edu>, March 2003 */
31 /* Text rotation 24-Jul-2002 Ethan A Merritt <merritt@u.washington.edu> */
32 /* Revised fill patterns 02-Apr-2003 Ethan A Merritt */
33 /* Enhanced text mode support November 2003 Ethan A Merritt */
42 TERM_PUBLIC void PDF_options __PROTO ((void));
43 TERM_PUBLIC void PDF_init __PROTO ((void));
44 TERM_PUBLIC void PDF_graphics __PROTO ((void));
45 TERM_PUBLIC void PDF_text __PROTO ((void));
46 TERM_PUBLIC void PDF_linetype __PROTO ((int linetype));
47 TERM_PUBLIC void PDF_move __PROTO ((unsigned int x, unsigned int y));
48 TERM_PUBLIC void PDF_vector __PROTO ((unsigned int x, unsigned int y));
49 TERM_PUBLIC void PDF_put_text __PROTO ((unsigned int x, unsigned int y, const char *str));
50 TERM_PUBLIC void PDF_reset __PROTO ((void));
51 TERM_PUBLIC int PDF_justify_text __PROTO ((enum JUSTIFY mode));
52 TERM_PUBLIC int PDF_text_angle __PROTO ((int ang));
53 TERM_PUBLIC void PDF_point __PROTO ((unsigned int x, unsigned int y, int pointstyle));
54 TERM_PUBLIC int PDF_set_font __PROTO ((const char *font));
55 TERM_PUBLIC void PDF_boxfill __PROTO((int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height));
56 TERM_PUBLIC void PDF_linewidth __PROTO ((double linewidth));
57 TERM_PUBLIC int PDF_make_palette __PROTO((t_sm_palette *));
58 TERM_PUBLIC void PDF_previous_palette __PROTO((void));
59 TERM_PUBLIC void PDF_set_color __PROTO((t_colorspec *));
61 TERM_PUBLIC void PDF_image __PROTO((unsigned, unsigned, coordval *, gpiPoint *, t_imagecolor));
64 TERM_PUBLIC void PDF_filled_polygon __PROTO((int, gpiPoint *));
66 /* To support "set term png enhanced" */
67 TERM_PUBLIC void ENHPDF_put_text __PROTO((unsigned int x, unsigned int y, const char *str));
68 TERM_PUBLIC void ENHPDF_OPEN __PROTO((char * fontname, double fontsize,
69 double base, TBOOLEAN widthflag, TBOOLEAN showflag,
71 TERM_PUBLIC void ENHPDF_FLUSH __PROTO((void));
73 #define PDF_NUM_POINTTYPES 75 /* number of point symbol types not counting the dot */
75 #define PDF_RESOLUTION (20) /* number of terminal pixels per pt */
76 #define PDF_XMAX (5*72*PDF_RESOLUTION) /* 5 inches, 72 pt/inch */
77 #define PDF_YMAX (3*72*PDF_RESOLUTION) /* 3 inches, 72 pt/inch */
79 static TBOOLEAN pdf_explicit_size = FALSE;
80 static size_units pdf_explicit_units = INCHES;
82 #endif /* TERM_PROTO */
84 #ifndef TERM_PROTO_ONLY
89 static PDF *myPDF = NULL;
91 static unsigned int PDF_xLast = UINT_MAX; /* current pen horizontal position*/
92 static unsigned int PDF_yLast = UINT_MAX; /* current pen vertical position*/
94 static int PDF_LineType = LT_UNDEFINED; /* current line type*/
95 static int PDF_LineCap = 0; /* Butt ends */
96 static double PDF_LineWidth = 1.0; /* current line width*/
97 static int PDF_TextAngle = 0; /* current text orientation*/
98 static enum JUSTIFY PDF_TextJust = LEFT; /* current text justification*/
99 static double PDF_linewidth_factor = 1.0; /* multiplier for line width */
100 static double PDF_dashlength_factor = 1.0; /* multiplier for dash length */
101 static TBOOLEAN PDF_dashedlines = FALSE; /* solid or dashed? */
102 static TBOOLEAN PDF_monochrome = FALSE; /* default all linetypes to black */
103 static rgb_color PDF_current_rgb = {0.,0.,0.}; /* Last color set */
104 static double PDF_current_gray = 0.0; /* Last color set (mono version) */
106 /* default text font family: */
107 static char PDF_fontNameDef[MAX_ID_LEN + 1] = "Helvetica";
108 static double PDF_fontSizeDef = 6; /* default text size*/
109 /* current text font family: */
110 static char PDF_fontNameCur[MAX_ID_LEN + 1] = "Helvetica";
111 static double PDF_fontSizeCur = 6; /* current text size*/
113 static TBOOLEAN PDF_pageIsOpen = FALSE; /* already started a page ?? */
114 static TBOOLEAN PDF_pathIsOpen = FALSE; /* open path flag*/
116 static int PDF_fontAscent = 0; /* estimated current font ascent*/
117 static int PDF_fontDescent = 0; /* estimated current font descent*/
118 static int PDF_fontLeading = 0; /* estimated current font leading*/
119 static int PDF_fontAvWidth = 0; /* estimated current font char average width*/
120 static int PDF_currentFontHandle; /* Needed for exhanced text mode */
122 static short PDF_Pen_RealID __PROTO ((int));
123 static void PDF_PathOpen __PROTO ((void));
124 static void PDF_PathClose __PROTO ((void));
125 static void PDF_SetFont __PROTO ((void));
126 static void PDF_DefinePatterns __PROTO((void));
127 enum { PDF_patterns = 7 };
128 static int PDF_patternHandles[PDF_patterns];
130 #ifndef HAVE_NODASH_LIBPDF
131 /* Description of dash patterns (same as those in post.trm) */
132 static int dash1[] = {8, 8};
133 static int dash2[] = {4, 6};
134 static int dash3[] = {2, 3};
135 static int dash4[] = {12, 4, 2, 4};
136 static int dash5[] = {6, 6, 2, 6};
137 static int dash6[] = {4, 4, 4, 12};
138 static int dash7[] = {1, 4, 12, 4, 1, 4};
141 /*------------------------ helper functions -------------------*/
144 PDF_Pen_RealID (int inPenCode)
147 inPenCode %= 12; /* normalize pen code*/
148 if (inPenCode <= LT_NODRAW)
149 inPenCode = LT_NODRAW;
151 return (inPenCode + 2);
154 /* Functions to ensure that as many move() and vector() calls as
155 * possible get converted into a single long 'path', before closing it
156 * with a stroke or similar command. */
160 PDF_pathIsOpen = TRUE;
166 if (PDF_pathIsOpen) {
169 PDF_pathIsOpen = FALSE;
173 /* Helper function to deal with switching over to a newly selected font.
174 * For now, this does not try to embed fonts into the PDF file.
175 * We would like to allow UTF-8 fonts via
176 font_handle = PDF_findfont(myPDF, PDF_fontNameCur, "unicode", 0);
177 * but this is not supported by the free-as-in-beer PDFlib Lite.
183 const char *pdfenc = "host";
185 /* Allow graceful failure */
186 PDF_set_parameter(myPDF, "fontwarning", "false");
188 /* LCB : Symbol and ZapfDingbats should use "builtin" encoding */
189 if ( (strcmp(PDF_fontNameCur,"Symbol") == 0) ||
190 (strcmp(PDF_fontNameCur,"ZapfDingbats") == 0) ) {
192 } else if (encoding == S_ENC_ISO8859_1) {
193 pdfenc = "iso8859-1";
194 } else if (encoding == S_ENC_ISO8859_2) {
195 pdfenc = "iso8859-2";
196 } else if (encoding == S_ENC_ISO8859_15) {
197 pdfenc = "iso8859-15";
198 } else if (encoding == S_ENC_CP1250) {
202 font_handle = PDF_findfont(myPDF, PDF_fontNameCur, pdfenc, 0);
204 if (font_handle == -1 && strcmp(pdfenc, "host")) {
205 fprintf(stderr,"Couldn't find font %s in encoding %s, trying \"host\"\n",
206 PDF_fontNameCur, pdfenc);
207 font_handle = PDF_findfont(myPDF, PDF_fontNameCur, "host", 0);
210 if (font_handle == -1) {
211 font_handle = PDF_findfont(myPDF, "Times-Roman", "host", 0);
212 fprintf(stderr,"Couldn't find font %s, falling back to Times-Roman\n", PDF_fontNameCur);
215 PDF_setfont(myPDF, font_handle, PDF_fontSizeCur * PDF_RESOLUTION);
217 /* Ask PDFlib for the actual numbers */
218 PDF_fontAscent = (int) (PDF_RESOLUTION * PDF_fontSizeCur * PDF_get_value(myPDF, "ascender", 0));
219 PDF_fontDescent = (int) (- PDF_RESOLUTION * PDF_fontSizeCur * PDF_get_value(myPDF, "descender", 0));
220 PDF_fontLeading = (int) (PDF_RESOLUTION * PDF_fontSizeCur * 0.25);
222 /* Assume this particular string is a somewhat reasonable typical
223 * output, for getting at the average character width */
224 PDF_fontAvWidth = (int)
225 (PDF_RESOLUTION * PDF_stringwidth(myPDF, "01234567890123456789",
226 font_handle, PDF_fontSizeCur)
228 PDF_currentFontHandle = font_handle;
238 /* EAM April 2003 - Rearrange patterns to maximize contrast in mono.
239 * Because of the finite linewidth, each pattern must include line
240 * fragments at the "empty" corners.
242 for (i=0; i<PDF_patterns; i++) {
243 PDF_patternHandles[i] = PDF_begin_pattern(myPDF, 8, 8, 8, 8, 2);
244 PDF_setlinewidth(myPDF, 0.25);
245 PDF_setlinecap(myPDF, 2); /* square ends */
247 case 0: PDF_moveto(myPDF, 0, 8);
248 PDF_lineto(myPDF, 8, 0);
249 PDF_moveto(myPDF, 0, 0);
250 PDF_lineto(myPDF, 8, 8);
253 case 1: PDF_moveto(myPDF, 0, 8);
254 PDF_lineto(myPDF, 8, 0);
255 PDF_moveto(myPDF, 0, 0);
256 PDF_lineto(myPDF, 8, 8);
257 PDF_moveto(myPDF, 4, 0);
258 PDF_lineto(myPDF, 8, 4);
259 PDF_lineto(myPDF, 4, 8);
260 PDF_lineto(myPDF, 0, 4);
261 PDF_lineto(myPDF, 4, 0);
264 case 2: PDF_moveto(myPDF, 0, 0);
265 PDF_lineto(myPDF, 0, 8);
266 PDF_lineto(myPDF, 8, 8);
267 PDF_lineto(myPDF, 8, 0);
268 PDF_lineto(myPDF, 0, 0);
271 case 3: PDF_moveto(myPDF, 0, 4);
272 PDF_lineto(myPDF, 4, 0);
273 PDF_moveto(myPDF, 4, 8);
274 PDF_lineto(myPDF, 8, 4);
277 case 4: PDF_moveto(myPDF, 0, 4);
278 PDF_lineto(myPDF, 4, 8);
279 PDF_moveto(myPDF, 4, 0);
280 PDF_lineto(myPDF, 8, 4);
283 case 5: PDF_moveto(myPDF, 0, 4);
284 PDF_lineto(myPDF, 2, 0);
285 PDF_moveto(myPDF, 2, 8);
286 PDF_lineto(myPDF, 6, 0);
287 PDF_moveto(myPDF, 6, 8);
288 PDF_lineto(myPDF, 8, 4);
291 case 6: PDF_moveto(myPDF, 0, 4);
292 PDF_lineto(myPDF, 2, 8);
293 PDF_moveto(myPDF, 2, 0);
294 PDF_lineto(myPDF, 6, 8);
295 PDF_moveto(myPDF, 6, 0);
296 PDF_lineto(myPDF, 8, 4);
299 case 7: /* not used */
300 PDF_moveto(myPDF, 4, 0);
301 PDF_lineto(myPDF, 0, 2);
302 PDF_moveto(myPDF, 8, 2);
303 PDF_lineto(myPDF, 0, 6);
304 PDF_moveto(myPDF, 8, 6);
305 PDF_lineto(myPDF, 4, 8);
308 case 8: /* not used */
309 PDF_moveto(myPDF, 4, 0);
310 PDF_lineto(myPDF, 8, 2);
311 PDF_moveto(myPDF, 0, 2);
312 PDF_lineto(myPDF, 8, 6);
313 PDF_moveto(myPDF, 0, 6);
314 PDF_lineto(myPDF, 4, 8);
318 PDF_end_pattern(myPDF);
323 /*------------------- the terminal entry functions --------------------*/
331 /* Annoying hack to handle the case of 'set termoption' after */
332 /* we have already initialized the terminal. */
334 pdf_explicit_size = FALSE;
336 while (!END_OF_COMMAND) {
338 if (almost_equals(c_token, "enh$anced")) {
340 term->put_text = ENHPDF_put_text;
341 term->flags |= TERM_ENHANCED_TEXT;
343 } else if (almost_equals(c_token, "noenh$anced")) {
345 term->put_text = PDF_put_text;
346 term->flags &= ~TERM_ENHANCED_TEXT;
350 if (almost_equals(c_token, "fn$ame") || almost_equals(c_token, "font")) {
354 if (!(s = try_to_get_string()))
355 int_error(c_token,"fname: expecting font name");
356 comma = strrchr(s,',');
357 if (comma && (1 == sscanf(comma+1,"%lf",&PDF_fontSizeDef)))
360 strncpy(PDF_fontNameDef, s, sizeof(PDF_fontNameDef));
365 if (almost_equals(c_token, "fs$ize")) {
369 int_error(c_token,"fsize: expecting font size");
370 PDF_fontSizeDef = real (const_express (&a));
374 if (equals(c_token, "lw") || almost_equals(c_token, "linew$idth")) {
378 int_error(c_token, "expecting line width");
379 PDF_linewidth_factor = real (const_express (&a));
380 if (PDF_linewidth_factor <= 0)
381 PDF_linewidth_factor = 0.1;
385 if (almost_equals(c_token, "rou$nded")) {
391 if (equals(c_token, "butt")) {
396 if (equals(c_token, "color") || almost_equals(c_token, "col$our")) {
398 PDF_monochrome = FALSE;
402 if (almost_equals(c_token, "mono$chrome")) {
404 PDF_monochrome = TRUE;
408 if (equals(c_token, "dl") || almost_equals(c_token, "dashl$ength")) {
411 int_error(c_token, "expecting dashlength multiplier");
412 PDF_dashlength_factor = real(const_express(&a));
413 if (PDF_dashlength_factor < 0.0)
414 PDF_dashlength_factor = 1.0;
418 if (equals(c_token, "solid")) {
420 PDF_dashedlines = FALSE;
424 if (equals(c_token, "size")) {
425 float xmax_t, ymax_t;
427 pdf_explicit_size = TRUE;
428 pdf_explicit_units = parse_term_size(&xmax_t, &ymax_t, INCHES);
429 term->xmax = xmax_t*PDF_RESOLUTION*72./gp_resolution;
430 term->ymax = ymax_t*PDF_RESOLUTION*72./gp_resolution;
434 #ifdef HAVE_NODASH_LIBPDF
435 int_warn(NO_CARET,"gnuplot was linked against a version of pdflib with no dash or pattern support");
437 if (almost_equals(c_token, "dash$ed")) {
439 PDF_dashedlines = TRUE;
444 int_error(c_token, "unexpected text at end of command");
448 /* Save options back into options string in normalized format */
449 sprintf(term_options, "%s%s fname '%s' fsize %g linewidth %3.1f %s ",
450 PDF_monochrome ? "monochrome " : " ",
451 term->put_text == ENHPDF_put_text ? "enhanced" : "noenhanced",
452 PDF_fontNameDef, PDF_fontSizeDef, PDF_linewidth_factor,
453 PDF_LineCap == 1 ? "rounded" : "");
455 sprintf(&(term_options[strlen(term_options)]), "dashed dl %3.1f",
456 PDF_dashlength_factor);
457 if (pdf_explicit_size) {
458 if (pdf_explicit_units == CM)
459 sprintf(&(term_options[strlen(term_options)]), "size %.2fcm, %.2fcm ",
460 2.54*(float)term->xmax/(72.*PDF_RESOLUTION),
461 2.54*(float)term->ymax/(72.*PDF_RESOLUTION));
463 sprintf(&(term_options[strlen(term_options)]), "size %.2fin, %.2fin ",
464 (float)term->xmax/(72.*PDF_RESOLUTION),
465 (float)term->ymax/(72.*PDF_RESOLUTION));
473 static TBOOLEAN PDFlib_booted = FALSE;
474 char *gpversionstring;
479 if (!PDFlib_booted) {
481 PDFlib_booted = TRUE;
487 /*open new PDF file */
488 #ifdef HAVE_LIBPDF_OPEN_FILE
489 if (PDF_open_file(myPDF, outstr) == -1)
491 if (PDF_begin_document(myPDF, outstr?outstr:"-", 0,
492 "compatibility=1.4") == -1)
493 #endif /* HAVE_LIBPDF_OPEN_FILE */
494 int_error(NO_CARET, "Error:cannot open PDF file .\n");
496 #ifdef PDF_DONT_COMPRESS
497 /* for easier debugging of the output, turn off PDF stream
499 PDF_set_value(myPDF, "compress", 0);
502 gpversionstring = gp_alloc(20 + strlen(gnuplot_version) +
503 strlen(gnuplot_patchlevel) + 1, "PDF_init");
504 sprintf(gpversionstring,"gnuplot %s patchlevel %s",
505 gnuplot_version, gnuplot_patchlevel);
508 timedate=asctime(localtime(&now));
509 timedate[strlen(timedate)-1]='\0';
511 PDF_set_info(myPDF,"Creator",gpversionstring);
513 username=getusername();
515 PDF_set_info(myPDF,"Author",username);
520 PDF_set_info(myPDF,"Title",outstr); /* FIXME: use 'set title', if any? */
521 PDF_set_info(myPDF,"Subject","gnuplot plot");
524 free(gpversionstring);
526 PDF_LineType = LT_UNDEFINED;
528 /* set current font to default */
529 strcpy(PDF_fontNameCur, PDF_fontNameDef);
530 PDF_fontSizeCur = PDF_fontSizeDef;
533 PDF_DefinePatterns();
536 /* Have to start the first page now, in order to know the actual
537 * size of the selected font */
540 /* set h_char, v_char*/
541 term->h_char = PDF_fontAvWidth;
542 term->v_char = (PDF_fontAscent + PDF_fontDescent + PDF_fontLeading);
544 /* set h_tic, v_tic*/
545 term->h_tic = term->v_tic = 3 * PDF_RESOLUTION;
547 /* initialize terminal's pointsize from "set pointsize" value */
548 term_pointsize = pointsize;
550 /* Initialize other default settings */
551 PDF_setlinecap(myPDF, PDF_LineCap);
552 PDF_setlinejoin(myPDF, PDF_LineCap); /* round+round or butt+mitre */
560 return; /* already open --> nothing to do */
562 PDF_pathIsOpen = FALSE;
563 PDF_xLast = PDF_yLast = UINT_MAX;
565 /* set size of canvas */
566 if (!pdf_explicit_size) {
567 term->xmax = PDF_XMAX;
568 term->ymax = PDF_YMAX;
571 PDF_begin_page(myPDF, (double)term->xmax / PDF_RESOLUTION,
572 (double)term->ymax / PDF_RESOLUTION);
573 PDF_scale(myPDF, 1.0/PDF_RESOLUTION, 1.0/PDF_RESOLUTION);
574 if (title.text && title.text[0])
575 /* a title has been set --> use it as the bookmark name, too */
576 PDF_add_bookmark(myPDF, title.text, 0, 1);
577 PDF_pageIsOpen = TRUE;
588 PDF_pageIsOpen = FALSE;
595 assert(PDF_pageIsOpen == FALSE);
596 #ifdef HAVE_LIBPDF_OPEN_FILE
599 PDF_end_document(myPDF, "");
600 #endif /* HAVE_LIBPDF_OPEN_FILE */
607 PDF_linetype (int linetype)
609 int dash = linetype % 8;
611 linetype = PDF_Pen_RealID(linetype);
612 if (linetype == PDF_LineType)
616 PDF_LineType = linetype;
618 if (PDF_monochrome) {
619 PDF_current_gray = 0.0;
620 PDF_setgray(myPDF, PDF_current_gray);
622 struct rgb *this_color = web_color_rgbs + 1 + linetype;
623 PDF_current_rgb.r = this_color->r / 255.0;
624 PDF_current_rgb.g = this_color->g / 255.0;
625 PDF_current_rgb.b = this_color->b / 255.0;
626 PDF_setrgbcolor(myPDF, PDF_current_rgb.r, PDF_current_rgb.g, PDF_current_rgb.b);
629 #ifndef HAVE_NODASH_LIBPDF
630 if (PDF_dashedlines) {
632 float dl = 8.0 * PDF_dashlength_factor;
636 case 0: PDF_setdash(myPDF, 0.0, 0.0);
638 case 1: sprintf(dashtype,"dasharray={%4.1f %4.1f}",
639 dl*dash1[0],dl*dash1[1]);
641 case 2: sprintf(dashtype,"dasharray={%4.1f %4.1f}",
642 dl*dash2[0],dl*dash2[1]);
644 case 3: sprintf(dashtype,"dasharray={%4.1f %4.1f}",
645 dl*dash3[0],dl*dash3[1]);
647 case 4: sprintf(dashtype,"dasharray={%4.1f %4.1f %4.1f %4.1f}",
648 dl*dash4[0],dl*dash4[1],dl*dash4[2],dl*dash4[3]);
650 case 5: sprintf(dashtype,"dasharray={%4.1f %4.1f %4.1f %4.1f}",
651 dl*dash5[0],dl*dash5[1],dl*dash5[2],dl*dash5[3]);
653 case 6: sprintf(dashtype,"dasharray={%4.1f %4.1f %4.1f %4.1f}",
654 dl*dash6[0],dl*dash6[1],dl*dash6[2],dl*dash6[3]);
656 case 7: sprintf(dashtype,"dasharray={%4.1f %4.1f %4.1f %4.1f %4.1f %4.1f}",
657 dl*dash7[0],dl*dash7[1],dl*dash7[2],dl*dash7[3],dl*dash7[4],dl*dash7[5]);
660 PDF_setdashpattern(myPDF,dashtype);
668 PDF_linewidth (double linewidth)
671 PDF_LineWidth = PDF_RESOLUTION * PDF_linewidth_factor * linewidth / 4.0;
672 if (PDF_LineWidth < 0.1)
674 PDF_setlinewidth(myPDF, PDF_LineWidth);
679 PDF_move (unsigned int x, unsigned int y)
681 if (PDF_pathIsOpen && x == PDF_xLast && y == PDF_yLast)
685 PDF_moveto(myPDF, x, y);
693 PDF_vector (unsigned int x, unsigned int y)
695 if (PDF_pathIsOpen && x == PDF_xLast && y == PDF_yLast)
699 PDF_lineto(myPDF, x, y);
705 /* Helper function. Many symbols have an additional dot in their
706 * center, so isolate its drawing into a separate function. */
707 static GP_INLINE void
708 PDF_dot (unsigned int x, unsigned int y)
710 /* Imitate PS's way of creating a small dot by a zero-length line
711 * segment with rounded endpoints */
712 PDF_setlinecap(myPDF, 1); /* rounded ends */
713 PDF_moveto(myPDF, x, y);
714 PDF_lineto(myPDF, x, y);
716 PDF_setlinecap(myPDF, PDF_LineCap); /* restore ends */
721 PDF_point (unsigned int x, unsigned int y, int number)
727 /* Treat all negative point sizes as dots */
730 /* Change coordinate system so the point symbols themselves
731 * can be drawn without depending on position or size (-->
732 * better compression and less coding for gnuplot) */
733 /* NB: I use the do_pointsize() default implementation, which
734 * just stores the last set pointsize into `term_pointsize',
735 * to avoid introducing another static driver-local variable
737 PDF_translate(myPDF, x, y);
738 PDF_scale(myPDF, term->h_tic / 2.0 * term_pointsize,
739 term->v_tic / 2.0 * term_pointsize);
740 /* Correct linewidth to counter the scaling effect --- assume
741 * h_tic is usable, to avoid having to average h_ and v_tic */
742 PDF_setlinewidth(myPDF,
743 PDF_LineWidth / (term->h_tic / 2.0 * term_pointsize));
744 switch (number %= PDF_NUM_POINTTYPES) {
746 PDF_moveto(myPDF, -1, 0);
747 PDF_lineto(myPDF, 1, 0);
748 PDF_moveto(myPDF, 0, -1);
749 PDF_lineto(myPDF, 0, 1);
753 PDF_moveto(myPDF, -1, 0);
754 PDF_lineto(myPDF, 1, 0);
755 PDF_moveto(myPDF, 0, -1);
756 PDF_lineto(myPDF, 0, 1);
759 PDF_moveto(myPDF, -1, -1);
760 PDF_lineto(myPDF, 1, 1);
761 PDF_moveto(myPDF, 1, -1);
762 PDF_lineto(myPDF, -1, 1);
766 /* For each x = 0..5, 4 shapes are defined:
767 * 3 + 2*x --> hollow symbol with a dot at its center
768 * 4 + 2*x --> solid symbol filled in linetype's color
769 * 63 + x --> hollow symbol without the center dot
770 * 69 + x --> symbol filled with white --> opaque symbol */
772 case 63+0: /* BoxEmpty */
773 case 3+2*0: /* Box */
774 PDF_moveto(myPDF, -1, -1);
775 PDF_lineto(myPDF, 1, -1);
776 PDF_lineto(myPDF, 1, 1);
777 PDF_lineto(myPDF, -1, 1);
778 PDF_closepath_stroke(myPDF);
779 if (number == 3) PDF_dot(0,0);
781 case 69+0: /* BoxWhitefilled */
782 PDF_setgray_fill(myPDF, 1);
784 case 4+2*0: /* BoxFilled */
785 PDF_moveto(myPDF, -1, -1);
786 PDF_lineto(myPDF, 1, -1);
787 PDF_lineto(myPDF, 1, 1);
788 PDF_lineto(myPDF, -1, 1);
789 PDF_closepath_fill_stroke(myPDF);
792 case 63+1: /* CircleEmpty */
793 case 3+2*1: /* Circle */
794 PDF_circle(myPDF, 0, 0, 1);
796 if (number == 5) PDF_dot(0,0);
798 case 69+1: /* CircleWhitefilled */
799 PDF_setgray_fill(myPDF, 1);
801 case 4+2*1: /* CircleFilled */
802 PDF_circle(myPDF, 0, 0, 1);
803 PDF_fill_stroke(myPDF);
806 case 63+2: /* TriangleUpEmpty */
807 case 3+2*2: /* TriangleUp */
808 PDF_moveto(myPDF, 0, 1.12);
809 PDF_lineto(myPDF, -1, -0.5);
810 PDF_lineto(myPDF, 1, -0.5);
811 PDF_closepath_stroke(myPDF);
812 if (number == 7) PDF_dot(0,0);
814 case 69+2: /* TriangleUpWhitefilled */
815 PDF_setgray_fill(myPDF, 1);
817 case 4+2*2: /* TriangleUpFilled */
818 PDF_moveto(myPDF, 0, 1.12);
819 PDF_lineto(myPDF, -1, -0.5);
820 PDF_lineto(myPDF, 1, -0.5);
821 PDF_closepath_fill_stroke(myPDF);
824 case 63+3: /* TriangleDownEmpty */
825 case 3+2*3: /* TriangleDown */
826 PDF_moveto(myPDF, 0, -1.12);
827 PDF_lineto(myPDF, -1, 0.5);
828 PDF_lineto(myPDF, 1, 0.5);
829 PDF_closepath_stroke(myPDF);
830 if (number == 9) PDF_dot(0,0);
832 case 69+3: /* TriangleDownWhitefilled */
833 PDF_setgray_fill(myPDF, 1);
835 case 4+2*3: /* TriangleDownFilled */
836 PDF_moveto(myPDF, 0, -1.12);
837 PDF_lineto(myPDF, -1, 0.5);
838 PDF_lineto(myPDF, 1, 0.5);
839 PDF_closepath_fill_stroke(myPDF);
842 case 63+4: /* DiamondEmpty */
843 case 3+2*4: /* Diamond */
844 PDF_moveto(myPDF, 0, -1);
845 PDF_lineto(myPDF, 1, 0);
846 PDF_lineto(myPDF, 0, 1);
847 PDF_lineto(myPDF, -1, 0);
848 PDF_closepath_stroke(myPDF);
849 if (number == 11) PDF_dot(0,0);
851 case 69+4: /* DiamondWhitefilled */
852 PDF_setgray_fill(myPDF, 1);
854 case 4+2*4: /* DiamondFilled */
855 PDF_moveto(myPDF, 0, -1);
856 PDF_lineto(myPDF, 1, 0);
857 PDF_lineto(myPDF, 0, 1);
858 PDF_lineto(myPDF, -1, 0);
859 PDF_closepath_fill_stroke(myPDF);
862 case 63+5: /* PentagonEmpty */
863 case 3+2*5: /* Pentagon */
864 PDF_moveto(myPDF, 0, 1);
865 PDF_lineto(myPDF, -0.95, 0.31);
866 PDF_lineto(myPDF, -0.58, -0.81);
867 PDF_lineto(myPDF, +0.58, -0.81);
868 PDF_lineto(myPDF, +0.95, 0.31);
869 PDF_closepath_stroke(myPDF);
870 if (number == 13) PDF_dot(0,0);
872 case 69+5: /* PentagonWhitefilled */
873 PDF_setgray_fill(myPDF, 1);
875 case 4+2*5: /* PentagonFilled */
876 PDF_moveto(myPDF, 0, 1);
877 PDF_lineto(myPDF, -0.95, 0.31);
878 PDF_lineto(myPDF, -0.58, -0.81);
879 PDF_lineto(myPDF, +0.58, -0.81);
880 PDF_lineto(myPDF, +0.95, 0.31);
881 PDF_closepath_fill_stroke(myPDF);
884 /* 15 + (0..15): circles with varying parts of'em filled. The added
885 * number is a bit-pattern of the 4 quadrants: 1 signals a quadrant
888 PDF_moveto(myPDF, 0, 0);
889 PDF_lineto(myPDF, 0, 1);
890 PDF_arc(myPDF, 0, 0, 1, 90, 360+90);
891 PDF_closepath_stroke(myPDF);
894 /* Generalize common code into a macro... */
895 #define CIRCLE_SINGLE_PIESLICE(x, y, angle1, angle2) \
896 PDF_moveto(myPDF, 0, 0); \
897 PDF_lineto(myPDF, (x), (y)); \
898 PDF_arc(myPDF, 0, 0, 1, (angle1), (angle2)); \
899 PDF_lineto(myPDF, 0, 0); \
900 PDF_closepath(myPDF); \
901 PDF_fill_stroke(myPDF); \
902 PDF_arc(myPDF, 0, 0, 1, (angle2), (angle1) + 360); \
906 #define CIRCLE_SINGLE_QUADRANT(x, y, angle) \
907 CIRCLE_SINGLE_PIESLICE(x, y, angle, angle+90);
909 CIRCLE_SINGLE_QUADRANT(1, 0, 0);
911 CIRCLE_SINGLE_QUADRANT(0, 1, 90);
913 CIRCLE_SINGLE_QUADRANT(-1, 0, 180);
915 CIRCLE_SINGLE_QUADRANT(0, -1, 270);
916 #undef CIRCLE_SINGLE_QUADRANT
918 #define CIRCLE_TWO_NEIGHBOR_QUADRANTS(x, y, angle) \
919 CIRCLE_SINGLE_PIESLICE(x, y, angle, angle+180)
921 CIRCLE_TWO_NEIGHBOR_QUADRANTS(1, 0, 0);
923 CIRCLE_TWO_NEIGHBOR_QUADRANTS(0, 1, 90);
925 CIRCLE_TWO_NEIGHBOR_QUADRANTS(-1, 0, 180);
927 CIRCLE_TWO_NEIGHBOR_QUADRANTS(0, -1, 270);
928 #undef CIRCLE_TWO_NEIGHBOR_QUADRANTS
930 #define CIRCLE_TWO_OPPOSING_QUADRANTS(x, y, angle) \
931 PDF_moveto(myPDF, 0, 0); \
932 PDF_lineto(myPDF, x, y); \
933 PDF_arc(myPDF, 0, 0, 1, angle, angle + 90); \
934 PDF_lineto(myPDF, 0, 0); \
935 PDF_fill_stroke(myPDF); \
936 PDF_moveto(myPDF, 0, 0); \
937 PDF_lineto(myPDF, -x, -y); \
938 PDF_arc(myPDF, 0, 0, 1, angle + 180, angle + 270); \
939 PDF_lineto(myPDF, 0, 0); \
940 PDF_fill_stroke(myPDF); \
941 PDF_arc(myPDF, 0, 0, 1, angle + 90, angle + 360); \
945 CIRCLE_TWO_OPPOSING_QUADRANTS(1, 0, 0);
947 CIRCLE_TWO_OPPOSING_QUADRANTS(0, 1, 90);
948 #undef CIRCLE_TWO_OPPOSING_QUADRANTS
950 #define CIRCLE_THREE_QUADRANTS(x, y, angle) \
951 CIRCLE_SINGLE_PIESLICE(x, y, angle, angle+270)
953 CIRCLE_THREE_QUADRANTS(1, 0, 0);
955 CIRCLE_THREE_QUADRANTS(0, 1, 90);
957 CIRCLE_THREE_QUADRANTS(-1, 0, 180);
959 CIRCLE_THREE_QUADRANTS(0, -1, 270);
960 #undef CIRCLE_THREE_QUADRANTS
961 #undef CIRCLE_SINGLE_PIESLICE
964 PDF_circle(myPDF, 0, 0, 1);
965 PDF_closepath_fill_stroke(myPDF);
969 /*************************************************************************/
970 /* 31 + (0..15): squares with different quadrants of them filled in. */
971 /*************************************************************************/
972 /*************************************************************************/
973 /* 47 + (0..15): diamonds with filled quadrants as given by bit pattern */
974 /* Diamonds are drawn as squares rotated by 45 degrees, so can use
975 * fall-through from diamond to squares, and re-use some macros. */
976 /*************************************************************************/
978 PDF_rotate(myPDF, 45);
981 PDF_moveto(myPDF, 0, 0);
982 PDF_lineto(myPDF, 0, 1);
983 PDF_lineto(myPDF, -1, 1);
984 PDF_lineto(myPDF, -1, -1);
985 PDF_lineto(myPDF, 1, -1);
986 PDF_lineto(myPDF, 1, 1);
987 PDF_lineto(myPDF, 0, 1);
992 PDF_rotate(myPDF, 45);
995 PDF_moveto(myPDF, -1, 1);
996 PDF_lineto(myPDF, -1, -1);
997 PDF_lineto(myPDF, 1, -1);
998 PDF_lineto(myPDF, 1, 1);
999 PDF_closepath_fill_stroke(myPDF);
1002 /* macros defining shapes of the partly filled symbols. Done by
1003 * rotating the starting point (x0, y0) by 90 degrees or 45 degrees
1004 * (with length adjustment). The rotations can be done without
1005 * trigonometric function calls, since their values are known:
1006 * cos(90)=0, sin(90)=1, cos(45)=sin(45)=1/sqrt(2). A good compiler
1007 * should be able to optimize away all the local variables and
1010 #define SQUARE_SINGLE_PIESLICE(x0, y0, quadrants) \
1014 PDF_moveto(myPDF, 0, 0); \
1015 PDF_lineto(myPDF, x, y); \
1016 /* poor man's rotation by 45 and 90 degrees around the \
1017 * square's outline. */ \
1018 while (quadrant++ < quadrants) { \
1020 PDF_lineto(myPDF, x-y, x+y); \
1021 dummy = x; x = -y; y = dummy; \
1023 PDF_lineto(myPDF, x, y); \
1024 PDF_closepath_fill_stroke(myPDF); \
1025 PDF_moveto(myPDF, x, y); \
1026 while (quadrant++ <= 4) { \
1028 PDF_lineto(myPDF, x-y, x+y); \
1029 dummy = x; x = -y; y = dummy; \
1031 PDF_lineto(myPDF, x, y); \
1032 PDF_stroke(myPDF); \
1036 #define SQUARE_TWO_OPPOSING_QUADRANTS(x0, y0, angle) \
1038 int x = x0, y = y0, dummy; \
1041 while (counter++ < 2) { \
1042 PDF_moveto(myPDF, 0, 0); \
1043 PDF_lineto(myPDF, x, y); \
1044 PDF_lineto(myPDF, x-y, x+y); \
1045 dummy = x; x = -y; y = dummy; \
1046 PDF_lineto(myPDF, x, y); \
1047 PDF_closepath_fill_stroke(myPDF); \
1049 PDF_moveto(myPDF, x, y); \
1050 PDF_lineto(myPDF, x-y, x+y); \
1051 dummy = x; x = -y; y = dummy; \
1052 PDF_lineto(myPDF, x, y); \
1053 PDF_stroke(myPDF); \
1058 /* Macros for diamonds just prepend the rotation and then call those
1060 #define DIAMOND_SINGLE_PIESLICE(x, y, quadrants) \
1061 PDF_rotate(myPDF, 45); \
1062 SQUARE_SINGLE_PIESLICE(x, y, quadrants);
1063 #define DIAMOND_TWO_OPPOSING_QUADRANTS(x, y, angle) \
1064 PDF_rotate(myPDF, 45); \
1065 SQUARE_TWO_OPPOSING_QUADRANTS(x, y, angle);
1067 /* ... and now all the individual cases. The 'angle' arguments' are
1068 * purely for the sake of easing cut'n'paste with the circle case */
1069 #define SQUARE_SINGLE_QUADRANT(x, y, angle) \
1070 SQUARE_SINGLE_PIESLICE(x, y, 1);
1072 SQUARE_SINGLE_QUADRANT(1, 0, 0);
1074 SQUARE_SINGLE_QUADRANT(0, 1, 90);
1076 SQUARE_SINGLE_QUADRANT(-1, 0, 180);
1078 SQUARE_SINGLE_QUADRANT(0, -1, 270);
1079 #undef SQUARE_SINGLE_QUADRANT
1081 #define SQUARE_TWO_NEIGHBOR_QUADRANTS(x, y, angle) \
1082 SQUARE_SINGLE_PIESLICE(x, y, 2)
1084 SQUARE_TWO_NEIGHBOR_QUADRANTS(1, 0, 0);
1086 SQUARE_TWO_NEIGHBOR_QUADRANTS(0, 1, 90);
1088 SQUARE_TWO_NEIGHBOR_QUADRANTS(-1, 0, 180);
1090 SQUARE_TWO_NEIGHBOR_QUADRANTS(0, -1, 270);
1091 #undef SQUARE_TWO_NEIGHBOR_QUADRANTS
1094 SQUARE_TWO_OPPOSING_QUADRANTS(1, 0, 0);
1096 SQUARE_TWO_OPPOSING_QUADRANTS(0, 1, 90);
1098 #define SQUARE_THREE_QUADRANTS(x, y, angle) \
1099 SQUARE_SINGLE_PIESLICE(x, y, 3)
1101 SQUARE_THREE_QUADRANTS(1, 0, 0);
1103 SQUARE_THREE_QUADRANTS(0, 1, 90);
1105 SQUARE_THREE_QUADRANTS(-1, 0, 180);
1107 SQUARE_THREE_QUADRANTS(0, -1, 270);
1108 #undef SQUARE_THREE_QUADRANTS
1110 #define DIAMOND_SINGLE_QUADRANT(x, y, angle) \
1111 DIAMOND_SINGLE_PIESLICE(x, y, 1)
1113 DIAMOND_SINGLE_QUADRANT(1, 0, 0);
1115 DIAMOND_SINGLE_QUADRANT(0, 1, 90);
1117 DIAMOND_SINGLE_QUADRANT(-1, 0, 180);
1119 DIAMOND_SINGLE_QUADRANT(0, -1, 270);
1120 #undef DIAMOND_SINGLE_QUADRANT
1122 #define DIAMOND_TWO_NEIGHBOR_QUADRANTS(x, y, angle) \
1123 DIAMOND_SINGLE_PIESLICE(x, y, 2)
1125 DIAMOND_TWO_NEIGHBOR_QUADRANTS(1, 0, 0);
1127 DIAMOND_TWO_NEIGHBOR_QUADRANTS(0, 1, 90);
1129 DIAMOND_TWO_NEIGHBOR_QUADRANTS(-1, 0, 180);
1131 DIAMOND_TWO_NEIGHBOR_QUADRANTS(0, -1, 270);
1132 #undef DIAMOND_TWO_NEIGHBOR_QUADRANTS
1136 DIAMOND_TWO_OPPOSING_QUADRANTS(1, 0, 0);
1138 DIAMOND_TWO_OPPOSING_QUADRANTS(0, 1, 90);
1139 #undef DIAMOND_TWO_OPPOSING_QUADRANTS
1140 #undef SQUARE_TWO_OPPOSING_QUADRANTS
1142 #define DIAMOND_THREE_QUADRANTS(x, y, angle) \
1143 DIAMOND_SINGLE_PIESLICE(x, y, 3)
1145 DIAMOND_THREE_QUADRANTS(1, 0, 0);
1147 DIAMOND_THREE_QUADRANTS(0, 1, 90);
1149 DIAMOND_THREE_QUADRANTS(-1, 0, 180);
1151 DIAMOND_THREE_QUADRANTS(0, -1, 270);
1152 #undef DIAMOND_THREE_QUADRANTS
1153 #undef DIAMOND_SINGLE_PIESLICE
1154 #undef SQUARE_SINGLE_PIESLICE
1157 int_warn(NO_CARET, "PDF: unknown point type number %d", number);
1168 PDF_justify_text (enum JUSTIFY mode)
1170 PDF_TextJust = mode;
1176 PDF_text_angle (int ang)
1178 PDF_TextAngle = ang;
1184 PDF_put_text (unsigned int x, unsigned int y, const char *str)
1186 char *alignment = NULL;
1187 double h = x, v = y;
1191 /* horizontal justification*/
1192 switch (PDF_TextJust) {
1197 alignment = "center";
1200 alignment = "right";
1204 if (PDF_TextAngle) {
1206 PDF_translate(myPDF, h, v);
1207 PDF_rotate(myPDF, PDF_TextAngle);
1208 /* vertical justification*/
1209 PDF_translate(myPDF, 0, -(PDF_fontAscent-PDF_fontDescent)/2);
1210 PDF_show_boxed(myPDF, str, 0,0, 0, 0, alignment, NULL);
1213 /* vertical justification*/
1214 v -= (PDF_fontAscent - PDF_fontDescent) / 2;
1215 PDF_show_boxed(myPDF, str, h , v, 0, 0, alignment, NULL);
1222 PDF_set_font (const char *font)
1225 if (!font || !(*font)) {
1226 strcpy (PDF_fontNameCur, PDF_fontNameDef);
1227 PDF_fontSizeCur = PDF_fontSizeDef;
1229 int sep = strcspn(font,",");
1231 strncpy(PDF_fontNameCur,font,sep);
1232 PDF_fontNameCur[sep] = NUL;
1234 if (font[sep] == ',')
1235 sscanf(&(font[sep+1]), "%lf", &PDF_fontSizeCur);
1241 term->h_char = PDF_fontAvWidth;
1242 term->v_char = (PDF_fontAscent + PDF_fontDescent + PDF_fontLeading);
1248 PDF_boxfill(int style, unsigned int x1, unsigned int y1,
1249 unsigned int width, unsigned int height)
1253 corner[0].x = x1; corner[0].y = y1;
1254 corner[1].x = x1+width; corner[1].y = y1;
1255 corner[2].x = x1+width; corner[2].y = y1+height;
1256 corner[3].x = x1; corner[3].y = y1+height;
1258 corner->style = style;
1259 PDF_filled_polygon(4, corner);
1263 PDF_filled_polygon(int points, gpiPoint* corners)
1266 int fillpar = corners->style >> 4;
1267 int style = corners->style &= 0xf;
1273 case FS_EMPTY: /* fill with white */
1274 PDF_setgray(myPDF, 1);
1278 double fact = (double)fillpar * 0.01;
1279 double _fact = (double)(100-fillpar) * 0.01;
1280 double red = PDF_current_rgb.r * fact + _fact;
1281 double green = PDF_current_rgb.g * fact + _fact;
1282 double blue = PDF_current_rgb.b * fact + _fact;
1284 PDF_setgray_fill(myPDF, PDF_current_gray);
1286 PDF_setrgbcolor_fill(myPDF, red, green, blue);
1289 #if !HAVE_OLD_LIBPDF
1291 fillpar = fillpar % (PDF_patterns + 1) /* 0 == white */;
1294 /* fill with white */
1295 PDF_setcolor(myPDF, "fill", "rgb", 1, 1, 1, 0 /* unused */);
1298 PDF_setcolor(myPDF, "fill", "pattern", PDF_patternHandles[fillpar - 1], 0, 0, 0);
1306 PDF_moveto(myPDF, corners[0].x, corners[0].y);
1307 for (i=1; i<points; i++)
1308 PDF_lineto(myPDF, corners[i].x, corners[i].y);
1309 PDF_lineto(myPDF, corners[0].x, corners[0].y);
1315 PDF_make_palette(t_sm_palette *palette)
1317 if (palette == NULL) {
1318 /* pdf can do continuous colors */
1326 PDF_set_color(t_colorspec *colorspec)
1328 if (colorspec->type == TC_LT) {
1329 struct rgb *this_color = web_color_rgbs + 1 + PDF_Pen_RealID(colorspec->lt);
1330 PDF_current_rgb.r = this_color->r / 255.0;
1331 PDF_current_rgb.g = this_color->g / 255.0;
1332 PDF_current_rgb.b = this_color->b / 255.0;
1333 PDF_current_gray = 0.0; /* monochrome mode only */
1334 } else if (colorspec->type == TC_FRAC) {
1335 rgb1maxcolors_from_gray( colorspec->value, &PDF_current_rgb);
1336 PDF_current_gray = colorspec->value; /* monochrome mode only */
1337 } else if (colorspec->type == TC_RGB) {
1338 PDF_current_rgb.r = (double)((colorspec->lt >> 16 ) & 255) / 255.;
1339 PDF_current_rgb.g = (double)((colorspec->lt >> 8 ) & 255) / 255.;
1340 PDF_current_rgb.b = (double)(colorspec->lt & 255) / 255.;
1344 /* make sure that the path is stroked with the current color
1345 * before changing the color */
1348 if (PDF_monochrome && colorspec->type != TC_RGB)
1349 PDF_setgray(myPDF, PDF_current_gray); /* FIXME - Should this be NTSC(current_rgb)? */
1351 PDF_setrgbcolor(myPDF, PDF_current_rgb.r, PDF_current_rgb.g, PDF_current_rgb.b);
1353 /* mark linetype invalid so that the color will be
1354 * set when PDF_linetype() is called next */
1355 PDF_LineType = LT_UNDEFINED;
1359 PDF_previous_palette()
1365 PDF_image (unsigned M, unsigned N, coordval * image, gpiPoint * corner, t_imagecolor color_mode)
1367 unsigned char *pixel;
1368 float xscale, yscale;
1371 /* Allocate memory to hold a copy of the entire image in raw RGB format */
1372 unsigned char *rawrgb = gp_alloc( M*N*3, "Raw RGB image");
1374 /* Convert the input image into raw RGB 24-bit color representation */
1375 if (color_mode == IC_RGB) {
1376 for (i=0, pixel=rawrgb; i<N*M*3;) {
1378 rgb255_color rgb255;
1379 rgb1.r = image[i++];
1380 rgb1.g = image[i++];
1381 rgb1.b = image[i++];
1382 rgb255_from_rgb1( rgb1, &rgb255 );
1383 *pixel++ = rgb255.r;
1384 *pixel++ = rgb255.g;
1385 *pixel++ = rgb255.b;
1388 for (i=0, pixel=rawrgb; i< N*M; i++) {
1390 rgb255maxcolors_from_gray(image[i], &rgb);
1397 /* Describe this image to PDF library */
1398 im = PDF_open_image( myPDF, "raw", "memory", (char *)rawrgb,
1399 (long)(M*N*3), (int)M, (int)N,
1400 3, 8, /* 3 colors, 8 bits each */
1403 /* Clip to bounding box requested */
1405 PDF_moveto(myPDF, corner[2].x, corner[2].y);
1406 PDF_lineto(myPDF, corner[2].x, corner[3].y);
1407 PDF_lineto(myPDF, corner[3].x, corner[3].y);
1408 PDF_lineto(myPDF, corner[3].x, corner[2].y);
1409 PDF_closepath(myPDF);
1412 /* Scale and copy into the main PDF image */
1413 xscale = fabs((float)corner[1].x - (float)corner[0].x) / (float)M;
1414 yscale = fabs((float)corner[1].y - (float)corner[0].y) / (float)N;
1415 PDF_translate(myPDF, corner[0].x, corner[0].y);
1416 PDF_scale(myPDF, xscale, yscale);
1417 PDF_translate(myPDF, 0, -(float)N);
1418 PDF_place_image(myPDF, im, 0.0, 0.0, 1.0 );
1422 PDF_close_image(myPDF, im);
1430 * Ethan A Merritt November 2003
1431 * - support for enhanced text mode
1433 * - The baseline is not consistent if font size changes within a string.
1434 * - Placement of overprinted characters is not correct.
1435 * - libpdf exits if the requested font is not recognized.
1436 * - I implement text-rotation by hand, but it may be possible to use
1437 * a gsave/translate/rotate/.../grestore sequence instead.
1440 static TBOOLEAN ENHpdf_opened_string;
1442 /* used in determining height of processed text */
1443 static float ENHpdf_base;
1445 /* use these so that we don't over-write the current font settings in pdf_state */
1446 static double ENHpdf_fontsize;
1447 static char *ENHpdf_font;
1449 /* A global flag that tells us this run is just to determine text size */
1450 static TBOOLEAN ENHpdf_sizeonly = FALSE;
1452 static TBOOLEAN ENHpdf_show = TRUE;
1453 static int ENHpdf_overprint = 0;
1454 static TBOOLEAN ENHpdf_widthflag = FALSE;
1455 static unsigned int ENHpdf_xsave, ENHpdf_ysave;
1457 /* Start a new string fragment */
1461 double fontsize, double base,
1462 TBOOLEAN widthflag, TBOOLEAN showflag,
1465 /* If the overprint code requests a save or request, that's all we do */
1466 if (overprint == 3) {
1467 ENHpdf_xsave = PDF_xLast;
1468 ENHpdf_ysave = PDF_yLast;
1470 } else if (overprint == 4) {
1471 PDF_move(ENHpdf_xsave, ENHpdf_ysave);
1475 if (!ENHpdf_opened_string) {
1476 ENHpdf_opened_string = TRUE;
1477 enhanced_cur_text = &enhanced_text[0];
1478 ENHpdf_font = fontname;
1479 ENHpdf_fontsize = fontsize;
1480 ENHpdf_base = base * PDF_RESOLUTION;
1481 ENHpdf_show = showflag;
1482 ENHpdf_overprint = overprint;
1483 ENHpdf_widthflag = widthflag;
1487 /* Write a string fragment and update the current position */
1494 if (ENHpdf_opened_string) {
1495 ENHpdf_opened_string = FALSE;
1496 *enhanced_cur_text = '\0';
1499 x -= sin((double)PDF_TextAngle * M_PI_2/90.) * ENHpdf_base;
1500 y += cos((double)PDF_TextAngle * M_PI_2/90.) * ENHpdf_base;
1501 x += sin((double)PDF_TextAngle * M_PI_2/90.) * (double)PDF_fontAvWidth/2.;
1502 y -= cos((double)PDF_TextAngle * M_PI_2/90.) * (double)PDF_fontAvWidth/2.;
1504 /* Select current font for enhanced text fragment, then restore context */
1506 char save_fontname[MAX_ID_LEN + 1];
1507 double save_fontsize = PDF_fontSizeCur;
1508 strcpy(save_fontname,PDF_fontNameCur);
1509 PDF_fontSizeCur = ENHpdf_fontsize;
1510 PDF_set_font(ENHpdf_font);
1511 strcpy(PDF_fontNameCur,save_fontname);
1512 PDF_fontSizeCur = save_fontsize;
1515 /* Find length of string in current font */
1516 stringlength = PDF_stringwidth(myPDF, enhanced_text,
1517 PDF_currentFontHandle, ENHpdf_fontsize);
1518 stringlength *= PDF_RESOLUTION;
1520 if (ENHpdf_show && !ENHpdf_sizeonly) {
1521 if (PDF_TextAngle == 0 ) {
1522 /* PDF_show(myPDF, enhanced_text); */
1523 PDF_show_boxed(myPDF, enhanced_text, x, y, 0, 0, "left", NULL);
1526 PDF_translate(myPDF, x, y);
1527 PDF_rotate(myPDF, PDF_TextAngle);
1528 /* vertical justification*/
1529 PDF_translate(myPDF, 0, -(PDF_fontAscent-PDF_fontDescent)/2);
1530 PDF_show_boxed(myPDF, enhanced_text, 0, 0, 0, 0, "left", NULL);
1534 if (ENHpdf_overprint == 1) {
1535 PDF_xLast += stringlength * cos((double)PDF_TextAngle * M_PI_2/90.) / 2.;
1536 PDF_yLast += stringlength * sin((double)PDF_TextAngle * M_PI_2/90.);
1537 } else if (ENHpdf_widthflag) {
1538 PDF_xLast += stringlength * cos((double)PDF_TextAngle * M_PI_2/90.);
1539 PDF_yLast += stringlength * sin((double)PDF_TextAngle * M_PI_2/90.);
1545 ENHPDF_put_text(unsigned int x, unsigned int y, const char *str)
1547 char *original_string = (char *)str;
1549 if (ignore_enhanced_text) {
1550 PDF_put_text(x,y,str);
1554 if (!str || !strlen(str))
1557 /* if there are no magic characters, we should just be able
1558 * punt the string to PDF_put_text()
1560 if (!strpbrk(str, "{}^_@&~")) {
1561 /* do something to ensure default font is selected */
1562 PDF_put_text(x,y,str);
1570 /* FIXME - Is this the way to do it?????
1571 if (PDF_TextAngle != 0)
1572 ENHPDF_DEBUG(("currentpoint gsave translate %d rotate 0 0 moveto\n", PDF_TextAngle));
1575 /* set up the global variables needed by enhanced_recursion() */
1576 enhanced_max_height = -1000;
1577 enhanced_min_height = 1000;
1578 enhanced_fontscale = 1.0;
1579 strncpy(enhanced_escape_format,"%c",sizeof(enhanced_escape_format));
1581 ENHpdf_opened_string = FALSE;
1583 /* EAM - Software text justification requires two passes */
1584 if (PDF_TextJust == RIGHT || PDF_TextJust == CENTRE)
1585 ENHpdf_sizeonly = TRUE;
1587 /* Set the recursion going. We say to keep going until a
1588 * closing brace, but we don't really expect to find one.
1589 * If the return value is not the nul-terminator of the
1590 * string, that can only mean that we did find an unmatched
1591 * closing brace in the string. We increment past it (else
1592 * we get stuck in an infinite loop) and try again.
1594 while (*(str = enhanced_recursion((char *)str, TRUE,
1595 PDF_fontNameCur, PDF_fontSizeCur,
1596 0.0, TRUE, TRUE, 0))) {
1597 (term->enhanced_flush)();
1599 /* I think we can only get here if *str == '}' */
1603 break; /* end of string */
1605 /* else carry on and process the rest of the string */
1610 enhanced_max_height += enhanced_min_height;
1612 /* We can do text justification by running the entire top level string */
1613 /* through 2 times, with the ENHpdf_sizeonly flag set the first time. */
1614 /* After seeing where the final position is, we then offset the start */
1615 /* point accordingly and run it again. */
1616 if (PDF_TextJust == RIGHT || PDF_TextJust == CENTRE) {
1617 int justification = PDF_TextJust;
1618 int x_offset = PDF_xLast - x;
1621 if (PDF_TextAngle != 0)
1622 y_offset = PDF_yLast - y;
1623 PDF_TextJust = LEFT;
1624 ENHpdf_sizeonly = FALSE;
1626 if (justification == RIGHT) {
1627 ENHPDF_put_text(x - x_offset, y - y_offset, original_string);
1628 } else if (justification == CENTRE) {
1629 ENHPDF_put_text(x - x_offset/2, y - y_offset/2, original_string);
1631 PDF_TextJust = justification;
1636 #endif /* TERM_BODY */
1639 TERM_TABLE_START (pdf_driver)
1640 "pdf", "PDF (Portable Document File) file driver",
1641 0 /* xmax */ , 0 /* ymax */ , 0 /* vchar */ , 0 /* hchar */ ,
1642 0 /* vtic */ , 0 /* htic */ ,
1643 PDF_options, PDF_init, PDF_reset, PDF_text, null_scale, PDF_graphics,
1644 PDF_move, PDF_vector, PDF_linetype, PDF_put_text, PDF_text_angle,
1645 PDF_justify_text, PDF_point, do_arrow, PDF_set_font, do_pointsize,
1647 0 /* suspend */, 0 /* resume */ , PDF_boxfill, PDF_linewidth
1649 , 0, 0, 0, 0, 0 /* no mouse support for pdf */
1652 PDF_previous_palette,
1658 , ENHPDF_OPEN, ENHPDF_FLUSH, do_enh_writec
1659 TERM_TABLE_END (pdf_driver)
1661 #define LAST_TERM pdf_driver
1662 #endif /* TERM_TABLE */
1664 #endif /* TERM_PROTO_ONLY */
1669 "?commands set terminal pdf",
1670 "?set terminal pdf",
1675 " This terminal produces files in the Adobe Portable Document Format",
1676 " (PDF), useable for printing or display with tools like Acrobat Reader",
1679 " set terminal pdf {monochrome|color|colour}",
1681 " {fname \"<font>\"} {fsize <fontsize>}",
1682 " {font \"<fontname>{,<fontsize>}\"}",
1683 " {linewidth <lw>} {rounded|butt}",
1684 " {solid|dashed} {dl <dashlength>}}",
1685 " {size <XX>{unit},<YY>{unit}}",
1687 " The default is to use a different color for each line type. Selecting",
1688 " `monochome` will use black for all linetypes, in which case you probably",
1689 " want to select `dashed` to distinguish line types. Even in in mono mode",
1690 " you can still use explicit colors for filled areas or linestyles.",
1692 " where <font> is the name of the default font to use (default Helvetica)",
1693 " and <fontsize> is the font size (in points, default 12).",
1694 " For help on which fonts are available or how to install new ones, please",
1695 " see the documentation for your local installation of pdflib.",
1697 " The `enhanced` option enables enhanced text processing features",
1698 " (subscripts, superscripts and mixed fonts). See `enhanced`.",
1700 " The width of all lines in the plot can be increased by the factor <n>",
1701 " specified in `linewidth`. Similarly `dashlength` is a multiplier for the",
1702 " default dash spacing.",
1704 " `rounded` sets line caps and line joins to be rounded; `butt` is the",
1705 " default, butt caps and mitered joins.",
1707 " The default size for PDF output is 5 inches by 3 inches. The `size` option",
1708 " changes this to whatever the user requests. By default the X and Y sizes",
1709 " are taken to be in inches, but other units are possible (currently only cm).",