1/* Hello, Emacs, this is -*-C-*- */
2
3/*------------------------------
4	GNUPLOT - pdf.trm
5
6	This file is included by ../term.c.
7
8	This driver uses PDFlib from www.pdflib.com
9
10	Author:
11
12		Hans-Bernhard Br"oker
13		broeker@physik.rwth-aachen.de
14
15	Licence: see the gnuplot copyright (to be merged into here...)
16
17	Options: can #define PDF_DONT_COMPRESS to avoid PDF output
18	generated being compressed (by the 'deflate' algorithm as used
19	in 'zip' or 'gzip'). That helps in debugging.
20
21------------------------------*/
22
23/* CODEME: Add patterned lines (?). */
24
25/* PM3D support by Johannes Zellner <johannes@zellner.org>, May-15-2002 */
26/* set_color fixes by Petr Mikulik <mikulik@physics.muni.cz>, June-10-2002 */
27/* image support by Ethan A Merritt <merritt@u.washington.edu>, March 2003 */
28
29/* Text rotation 24-Jul-2002 Ethan A Merritt <merritt@u.washington.edu> */
30/* Revised fill patterns 02-Apr-2003 Ethan A Merritt */
31/* Enhanced text mode support November 2003 Ethan A Merritt */
32
33#include "driver.h"
34
35#ifdef TERM_REGISTER
36register_term(pdf)
37#endif
38
39#ifdef TERM_PROTO
40TERM_PUBLIC void PDF_options(void);
41TERM_PUBLIC void PDF_init(void);
42TERM_PUBLIC void PDF_graphics(void);
43TERM_PUBLIC void PDF_text(void);
44TERM_PUBLIC void PDF_linetype(int linetype);
45TERM_PUBLIC void PDF_move(unsigned int x, unsigned int y);
46TERM_PUBLIC void PDF_vector(unsigned int x, unsigned int y);
47TERM_PUBLIC void PDF_put_text(unsigned int x, unsigned int y, const char *str);
48TERM_PUBLIC void PDF_reset(void);
49TERM_PUBLIC int PDF_justify_text(enum JUSTIFY mode);
50TERM_PUBLIC int PDF_text_angle(int ang);
51TERM_PUBLIC void PDF_point(unsigned int x, unsigned int y, int pointstyle);
52TERM_PUBLIC int PDF_set_font(const char *font);
53TERM_PUBLIC void PDF_boxfill(int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height);
54TERM_PUBLIC void PDF_linewidth(double linewidth);
55TERM_PUBLIC int PDF_make_palette(t_sm_palette *);
56TERM_PUBLIC void PDF_previous_palette(void);
57TERM_PUBLIC void PDF_set_color(t_colorspec *);
58TERM_PUBLIC void PDF_image(unsigned int, unsigned int, coordval *, gpiPoint *, t_imagecolor);
59
60TERM_PUBLIC void PDF_filled_polygon(int, gpiPoint *);
61
62/* To support "set term png enhanced" */
63TERM_PUBLIC void ENHPDF_put_text(unsigned int x, unsigned int y, const char *str);
64TERM_PUBLIC void ENHPDF_OPEN(char * fontname, double fontsize,
65			double base, TBOOLEAN widthflag, TBOOLEAN showflag,
66			int overprint);
67TERM_PUBLIC void ENHPDF_FLUSH(void);
68
69#define PDF_NUM_POINTTYPES 75	/* number of point symbol types not counting the dot */
70
71#define PDF_RESOLUTION  (20)	/* number of terminal pixels per pt */
72#define PDF_XMAX	(5*72*PDF_RESOLUTION) /* 5 inches, 72 pt/inch */
73#define PDF_YMAX	(3*72*PDF_RESOLUTION) /* 3 inches, 72 pt/inch */
74
75static TBOOLEAN pdf_explicit_size = FALSE;
76static size_units pdf_explicit_units = INCHES;
77
78#endif /* TERM_PROTO */
79
80#ifndef TERM_PROTO_ONLY
81#ifdef TERM_BODY
82
83#include <pdflib.h>
84
85static PDF *myPDF = NULL;
86
87static unsigned int PDF_xLast = UINT_MAX; /* current pen horizontal position*/
88static unsigned int PDF_yLast = UINT_MAX; /* current pen vertical position*/
89
90static int PDF_LineType = LT_UNDEFINED;		/* current line type*/
91static int PDF_LineCap = 0;			/* Butt ends */
92static double PDF_LineWidth = 1.0;		/* current line width*/
93static int PDF_TextAngle = 0;			/* current text orientation*/
94static enum JUSTIFY PDF_TextJust = LEFT;	/* current text justification*/
95static double PDF_linewidth_factor = 1.0;	/* multiplier for line width */
96static double PDF_dashlength_factor = 1.0;	/* multiplier for dash length */
97static TBOOLEAN PDF_monochrome = FALSE;		/* default all linetypes to black */
98static rgb_color PDF_current_rgb = {0.,0.,0.};	/* Last color set */
99static double PDF_current_gray = 0.0;		/* Last color set (mono version) */
100
101#ifdef HAVE_NODASH_LIBPDF
102static TBOOLEAN PDF_dashedlines = FALSE;	/* solid or dashed? */
103#else
104static TBOOLEAN PDF_dashedlines = TRUE;		/* solid or dashed? */
105#endif
106
107/* default text font family: */
108static char PDF_fontNameDef[MAX_ID_LEN + 1] = "Helvetica";
109static double PDF_fontSizeDef = 6;	/* default text size*/
110/* current text font family: */
111static char PDF_fontNameCur[MAX_ID_LEN + 1] = "Helvetica";
112static double PDF_fontSizeCur = 6; /* current text size*/
113static double PDF_fontscale = 1.0;
114
115static TBOOLEAN PDF_pageIsOpen = FALSE; /* already started a page ?? */
116static TBOOLEAN PDF_pathIsOpen = FALSE; /* open path flag*/
117
118static int PDF_fontAscent = 0;	/* estimated current font ascent*/
119static int PDF_fontDescent = 0;	/* estimated current font descent*/
120static int PDF_fontLeading = 0;	/* estimated current font leading*/
121static int PDF_fontAvWidth = 0;	/* estimated current font char average width*/
122static int PDF_currentFontHandle; /* Needed for exhanced text mode */
123
124static short PDF_Pen_RealID(int);
125static void PDF_PathOpen(void);
126static void PDF_PathClose(void);
127static void PDF_SetFont(void);
128static void PDF_DefinePatterns(void);
129enum { PDF_patterns = 7 };
130static int PDF_patternHandles[PDF_patterns];
131
132#ifndef HAVE_NODASH_LIBPDF
133/* Description of dash patterns (same as those in post.trm) */
134static int dash1[] = {8, 8};
135static int dash2[] = {4, 6};
136static int dash3[] = {2, 3};
137static int dash4[] = {12, 4, 2, 4};
138static int dash5[] = {6, 6, 2, 6};
139static int dash6[] = {4, 4, 4, 12};
140static int dash7[] = {1, 4, 12, 4, 1, 4};
141#endif
142
143/*------------------------ helper functions -------------------*/
144
145static short
146PDF_Pen_RealID (int inPenCode)
147{
148    if (inPenCode >= 12)
149	inPenCode %= 12;	/* normalize pen code*/
150    if (inPenCode <= LT_NODRAW)
151	inPenCode = LT_NODRAW;
152
153    return (inPenCode + 2);
154}
155
156/* Functions to ensure that as many move() and vector() calls as
157 * possible get converted into a single long 'path', before closing it
158 * with a stroke or similar command. */
159static void
160PDF_PathOpen ()
161{
162    PDF_pathIsOpen = TRUE;
163}
164
165static void
166PDF_PathClose ()
167{
168    if (PDF_pathIsOpen) {
169	PDF_stroke(myPDF);
170
171	PDF_pathIsOpen = FALSE;
172    }
173}
174
175/* Helper function to deal with switching over to a newly selected font.
176 * For now, this does not try to embed fonts into the PDF file.
177 * We would like to allow UTF-8 fonts via
178	font_handle = PDF_findfont(myPDF, PDF_fontNameCur, "unicode", 0);
179 * but this is not supported by the free-as-in-beer PDFlib Lite.
180 */
181static void
182PDF_SetFont ()
183{
184    int font_handle;
185    const char *pdfenc = "host";
186
187    /* Allow graceful failure */
188    PDF_set_parameter(myPDF, "fontwarning", "false");
189
190    /* LCB : Symbol and ZapfDingbats should use "builtin" encoding */
191    if ( (strcmp(PDF_fontNameCur,"Symbol") == 0) ||
192	 (strcmp(PDF_fontNameCur,"ZapfDingbats") == 0) ) {
193	pdfenc = "builtin";
194    } else if (encoding == S_ENC_ISO8859_1) {
195        pdfenc = "iso8859-1";
196    } else if (encoding == S_ENC_ISO8859_2) {
197        pdfenc = "iso8859-2";
198    } else if (encoding == S_ENC_ISO8859_9) {
199        pdfenc = "iso8859-9";
200    } else if (encoding == S_ENC_ISO8859_15) {
201        pdfenc = "iso8859-15";
202    } else if (encoding == S_ENC_CP1250) {
203        pdfenc = "cp1250";
204    } else if (encoding == S_ENC_CP1252) {
205        pdfenc = "cp1252";
206    }
207
208    font_handle = PDF_findfont(myPDF, PDF_fontNameCur, pdfenc, 0);
209
210    if (font_handle == -1 && strcmp(pdfenc, "host")) {
211        fprintf(stderr,"Couldn't find font %s in encoding %s, trying \"host\"\n",
212	        PDF_fontNameCur, pdfenc);
213	font_handle = PDF_findfont(myPDF, PDF_fontNameCur, "host", 0);
214    }
215
216    if (font_handle == -1) {
217	font_handle = PDF_findfont(myPDF, "Times-Roman", "host", 0);
218	fprintf(stderr,"Couldn't find font %s, falling back to Times-Roman\n", PDF_fontNameCur);
219    }
220
221    PDF_setfont(myPDF, font_handle, PDF_fontSizeCur * PDF_RESOLUTION * PDF_fontscale);
222
223    /* Ask PDFlib for the actual numbers */
224    PDF_fontAscent = (int) (PDF_RESOLUTION * PDF_fontSizeCur * PDF_fontscale * PDF_get_value(myPDF, "ascender", 0));
225    PDF_fontDescent = (int) (- PDF_RESOLUTION * PDF_fontSizeCur * PDF_fontscale * PDF_get_value(myPDF, "descender", 0));
226    PDF_fontLeading = (int) (PDF_RESOLUTION * PDF_fontSizeCur * PDF_fontscale * 0.25);
227
228    /* Assume this particular string is a somewhat reasonable typical
229     * output, for getting at the average character width */
230    PDF_fontAvWidth = (int)
231	(PDF_RESOLUTION * PDF_stringwidth(myPDF, "01234567890123456789",
232					  font_handle, PDF_fontSizeCur * PDF_fontscale )
233	 / 20.0);
234    PDF_currentFontHandle = font_handle;
235
236}
237
238#if !HAVE_OLD_LIBPDF
239static void
240PDF_DefinePatterns()
241{
242    int i;
243
244    /* EAM April 2003 - Rearrange patterns to maximize contrast in mono.
245     * Because of the finite linewidth, each pattern must include line
246     * fragments at the "empty" corners.
247     */
248    for (i=0; i<PDF_patterns; i++) {
249	PDF_patternHandles[i] = PDF_begin_pattern(myPDF, 8, 8, 8, 8, 2);
250	PDF_setlinewidth(myPDF, 0.25);
251	PDF_setlinecap(myPDF, 2); /* square ends */
252	switch (i) {
253	case 0:	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_stroke(myPDF);
258		break;
259	case 1:	PDF_moveto(myPDF, 0, 8);
260		PDF_lineto(myPDF, 8, 0);
261		PDF_moveto(myPDF, 0, 0);
262		PDF_lineto(myPDF, 8, 8);
263		PDF_moveto(myPDF, 4, 0);
264		PDF_lineto(myPDF, 8, 4);
265		PDF_lineto(myPDF, 4, 8);
266		PDF_lineto(myPDF, 0, 4);
267		PDF_lineto(myPDF, 4, 0);
268		PDF_stroke(myPDF);
269		break;
270	case 2:	PDF_moveto(myPDF, 0, 0);
271		PDF_lineto(myPDF, 0, 8);
272		PDF_lineto(myPDF, 8, 8);
273		PDF_lineto(myPDF, 8, 0);
274		PDF_lineto(myPDF, 0, 0);
275		PDF_fill(myPDF);
276		break;
277	case 3:	PDF_moveto(myPDF, 0, 4);
278		PDF_lineto(myPDF, 4, 0);
279		PDF_moveto(myPDF, 4, 8);
280		PDF_lineto(myPDF, 8, 4);
281		PDF_stroke(myPDF);
282		break;
283	case 4:	PDF_moveto(myPDF, 0, 4);
284		PDF_lineto(myPDF, 4, 8);
285		PDF_moveto(myPDF, 4, 0);
286		PDF_lineto(myPDF, 8, 4);
287		PDF_stroke(myPDF);
288		break;
289	case 5:	PDF_moveto(myPDF, 0, 4);
290		PDF_lineto(myPDF, 2, 0);
291		PDF_moveto(myPDF, 2, 8);
292		PDF_lineto(myPDF, 6, 0);
293		PDF_moveto(myPDF, 6, 8);
294		PDF_lineto(myPDF, 8, 4);
295		PDF_stroke(myPDF);
296		break;
297	case 6:	PDF_moveto(myPDF, 0, 4);
298		PDF_lineto(myPDF, 2, 8);
299		PDF_moveto(myPDF, 2, 0);
300		PDF_lineto(myPDF, 6, 8);
301		PDF_moveto(myPDF, 6, 0);
302		PDF_lineto(myPDF, 8, 4);
303		PDF_stroke(myPDF);
304		break;
305	case 7:	/* not used */
306		PDF_moveto(myPDF, 4, 0);
307		PDF_lineto(myPDF, 0, 2);
308		PDF_moveto(myPDF, 8, 2);
309		PDF_lineto(myPDF, 0, 6);
310		PDF_moveto(myPDF, 8, 6);
311		PDF_lineto(myPDF, 4, 8);
312		PDF_stroke(myPDF);
313		break;
314	case 8:	/* not used */
315		PDF_moveto(myPDF, 4, 0);
316		PDF_lineto(myPDF, 8, 2);
317		PDF_moveto(myPDF, 0, 2);
318		PDF_lineto(myPDF, 8, 6);
319		PDF_moveto(myPDF, 0, 6);
320		PDF_lineto(myPDF, 4, 8);
321		PDF_stroke(myPDF);
322		break;
323	}
324	PDF_end_pattern(myPDF);
325    }
326}
327#endif
328
329/*------------------- the terminal entry functions --------------------*/
330
331
332TERM_PUBLIC void
333PDF_options ()
334{
335    /* Annoying hack to handle the case of 'set termoption' after */
336    /* we have already initialized the terminal.                  */
337    if (!almost_equals(c_token-1, "termopt$ion")) {
338	pdf_explicit_size = FALSE;
339	/* Default to enhanced text */
340	term->put_text = ENHPDF_put_text;
341	term->flags |= TERM_ENHANCED_TEXT;
342    }
343
344    while (!END_OF_COMMAND) {
345
346	if (almost_equals(c_token, "enh$anced")) {
347	    c_token++;
348	    term->put_text = ENHPDF_put_text;
349	    term->flags |= TERM_ENHANCED_TEXT;
350	    continue;
351	} else if (almost_equals(c_token, "noenh$anced")) {
352	    c_token++;
353	    term->put_text = PDF_put_text;
354	    term->flags &= ~TERM_ENHANCED_TEXT;
355	    continue;
356	}
357
358	if (almost_equals(c_token, "fn$ame") || almost_equals(c_token, "font"))  {
359	    char *s, *comma;
360	    c_token++;
361
362	    if (!(s = try_to_get_string()))
363		int_error(c_token,"fname: expecting font name");
364	    comma = strrchr(s,',');
365	    if (comma && (1 == sscanf(comma+1,"%lf",&PDF_fontSizeDef)))
366		*comma = '\0';
367	    if (*s)
368		strncpy(PDF_fontNameDef, s, sizeof(PDF_fontNameDef));
369	    free(s);
370	    continue;
371	}
372
373	if (almost_equals(c_token, "fs$ize")) {
374	    c_token++;
375
376	    if (END_OF_COMMAND)
377		int_error(c_token,"fsize: expecting font size");
378	    PDF_fontSizeDef = real_expression();
379	    continue;
380	}
381
382	if (equals(c_token, "lw") || almost_equals(c_token, "linew$idth")) {
383	    c_token++;
384
385	    if (END_OF_COMMAND)
386		int_error(c_token, "expecting line width");
387	    PDF_linewidth_factor = real_expression();
388	    if (PDF_linewidth_factor <= 0)
389		PDF_linewidth_factor = 0.1;
390	    continue;
391	}
392
393	if (almost_equals(c_token, "rou$nded")) {
394	    c_token++;
395	    PDF_LineCap = 1;
396	    continue;
397	}
398
399	if (equals(c_token, "butt")) {
400	    PDF_LineCap = 0;
401	    continue;
402	}
403
404	if (equals(c_token, "color") || almost_equals(c_token, "col$our")) {
405	    c_token++;
406	    PDF_monochrome = FALSE;
407	    term->flags &= ~TERM_MONOCHROME;
408	    continue;
409	}
410
411	if (almost_equals(c_token, "mono$chrome")) {
412	    c_token++;
413	    PDF_monochrome = TRUE;
414	    term->flags |= TERM_MONOCHROME;
415	    continue;
416	}
417
418	if (equals(c_token, "dl") || almost_equals(c_token, "dashl$ength")) {
419	    c_token++;
420	    if (END_OF_COMMAND)
421		int_error(c_token, "expecting dashlength multiplier");
422	    PDF_dashlength_factor = real_expression();
423	    if (PDF_dashlength_factor < 0.0)
424		PDF_dashlength_factor = 1.0;
425	    continue;
426	}
427
428	if (almost_equals(c_token, "dash$ed") || equals(c_token, "solid")) {
429	    /* Version 5 always enables dashed lines */
430	    c_token++;
431	    continue;
432	}
433
434	if (equals(c_token, "size")) {
435	    float xmax_t, ymax_t;
436	    c_token++;
437	    pdf_explicit_size = TRUE;
438	    pdf_explicit_units = parse_term_size(&xmax_t, &ymax_t, INCHES);
439	    term->xmax = xmax_t*PDF_RESOLUTION*72./gp_resolution;
440	    term->ymax = ymax_t*PDF_RESOLUTION*72./gp_resolution;
441	    continue;
442	}
443
444	if (equals(c_token, "fontscale")) {
445	    c_token++;
446	    PDF_fontscale = END_OF_COMMAND ? -1 : real_expression();
447	    if (PDF_fontscale < 0)
448		PDF_fontscale = 1.0;
449	    continue;
450	}
451
452	int_error(c_token, "unexpected text at end of command");
453    }
454
455    /* Save options back into options string in normalized format */
456    sprintf(term_options, "%s%s fname '%s'  fsize %g fontscale %3.1f linewidth %3.1f %s ",
457	    PDF_monochrome ? "monochrome " : " ",
458	    term->put_text == ENHPDF_put_text ? "enhanced" : "noenhanced",
459	    PDF_fontNameDef, PDF_fontSizeDef, PDF_fontscale, PDF_linewidth_factor,
460	    PDF_LineCap == 1 ? "rounded" : "");
461    if (PDF_dashedlines)
462	sprintf(&(term_options[strlen(term_options)]), "dl %3.1f",
463		PDF_dashlength_factor);
464    if (pdf_explicit_size) {
465	if (pdf_explicit_units == CM)
466	    sprintf(&(term_options[strlen(term_options)]), "size %.2fcm, %.2fcm ",
467		2.54*(float)term->xmax/(72.*PDF_RESOLUTION),
468		2.54*(float)term->ymax/(72.*PDF_RESOLUTION));
469	else
470	    sprintf(&(term_options[strlen(term_options)]), "size %.2fin, %.2fin ",
471		(float)term->xmax/(72.*PDF_RESOLUTION),
472		(float)term->ymax/(72.*PDF_RESOLUTION));
473    }
474}
475
476
477TERM_PUBLIC void
478PDF_init ()
479{
480    static TBOOLEAN PDFlib_booted = FALSE;
481    char *gpversionstring;
482    char *username;
483    char *timedate;
484    time_t now;
485
486    if (!PDFlib_booted) {
487	PDF_boot();
488	PDFlib_booted = TRUE;
489    }
490
491    if (!myPDF)
492	myPDF = PDF_new();
493
494    /*open new PDF file */
495#ifdef HAVE_LIBPDF_OPEN_FILE
496    if (PDF_open_file(myPDF, outstr) == -1)
497#else
498    if (PDF_begin_document(myPDF, outstr?outstr:"-", 0,
499			   "compatibility=1.4") == -1)
500#endif /* HAVE_LIBPDF_OPEN_FILE */
501	int_error(NO_CARET, "Error:cannot open PDF file .\n");
502
503#ifdef PDF_DONT_COMPRESS
504    /* for easier debugging of the output, turn off PDF stream
505     * compression */
506    PDF_set_value(myPDF, "compress", 0);
507#endif
508
509    gpversionstring = gp_alloc(20 + strlen(gnuplot_version) +
510			       strlen(gnuplot_patchlevel) + 1, "PDF_init");
511    sprintf(gpversionstring,"gnuplot %s patchlevel %s",
512	    gnuplot_version, gnuplot_patchlevel);
513
514    time(&now);
515    timedate=asctime(localtime(&now));
516    timedate[strlen(timedate)-1]='\0';
517
518    PDF_set_info(myPDF,"Creator",gpversionstring);
519
520    username=getusername();
521    if (username) {
522	PDF_set_info(myPDF,"Author",username);
523	free(username);
524    }
525
526    if (outstr)
527	PDF_set_info(myPDF,"Title",outstr); /* FIXME: use 'set title', if any? */
528    PDF_set_info(myPDF,"Subject","gnuplot plot");
529
530    if (gpversionstring)
531	free(gpversionstring);
532
533    PDF_LineType = LT_UNDEFINED;
534
535    /* set current font to default */
536    strcpy(PDF_fontNameCur, PDF_fontNameDef);
537    PDF_fontSizeCur = PDF_fontSizeDef;
538
539#if !HAVE_OLD_LIBPDF
540    PDF_DefinePatterns();
541#endif
542
543    /* Have to start the first page now, in order to know the actual
544     * size of the selected font */
545    PDF_graphics();
546
547    /* set h_char, v_char*/
548    term->h_char = PDF_fontAvWidth;
549    term->v_char = (PDF_fontAscent + PDF_fontDescent + PDF_fontLeading);
550
551    /* set h_tic, v_tic*/
552    term->h_tic = term->v_tic = 3 * PDF_RESOLUTION;
553
554    /* initialize terminal's pointsize from "set pointsize" value */
555    term_pointsize = pointsize;
556
557    /* Initialize other default settings */
558    PDF_setlinecap(myPDF, PDF_LineCap);
559    PDF_setlinejoin(myPDF, PDF_LineCap);	/* round+round or butt+mitre */
560}
561
562
563TERM_PUBLIC void
564PDF_graphics ()
565{
566    if (PDF_pageIsOpen)
567	return;			/* already open --> nothing to do */
568
569    PDF_pathIsOpen = FALSE;
570    PDF_xLast = PDF_yLast = UINT_MAX;
571
572    /* set size of canvas */
573    if (!pdf_explicit_size) {
574	term->xmax = PDF_XMAX;
575	term->ymax = PDF_YMAX;
576    }
577
578    PDF_begin_page(myPDF, (double)term->xmax / PDF_RESOLUTION,
579		   (double)term->ymax / PDF_RESOLUTION);
580    PDF_scale(myPDF, 1.0/PDF_RESOLUTION, 1.0/PDF_RESOLUTION);
581    if (title.text && title.text[0])
582	/* a title has been set --> use it as the bookmark name, too */
583	PDF_add_bookmark(myPDF, title.text, 0, 1);
584    PDF_pageIsOpen = TRUE;
585
586    PDF_SetFont();
587}
588
589
590TERM_PUBLIC void
591PDF_text ()
592{
593    PDF_PathClose();
594    PDF_end_page(myPDF);
595    PDF_pageIsOpen = FALSE;
596}
597
598
599TERM_PUBLIC void
600PDF_reset ()
601{
602    assert(PDF_pageIsOpen == FALSE);
603#ifdef HAVE_LIBPDF_OPEN_FILE
604    PDF_close(myPDF);
605#else
606    PDF_end_document(myPDF, "");
607#endif /* HAVE_LIBPDF_OPEN_FILE */
608    PDF_delete(myPDF);
609    myPDF = NULL;
610}
611
612
613TERM_PUBLIC void
614PDF_linetype (int linetype)
615{
616    int dash = linetype % 8;
617
618    linetype = PDF_Pen_RealID(linetype);
619    if (linetype == PDF_LineType)
620	return;
621
622    PDF_PathClose ();
623    PDF_LineType = linetype;
624
625    if (PDF_monochrome) {
626	PDF_current_gray = 0.0;
627	PDF_setgray(myPDF, PDF_current_gray);
628    } else {
629	unsigned int irgb = pm3d_color_names_tbl[1+linetype].value;
630	PDF_current_rgb.r = (double)((irgb >> 16) & 0xff) / 255.;
631	PDF_current_rgb.g = (double)((irgb >>  8) & 0xff) / 255.;
632	PDF_current_rgb.b = (double)((irgb      ) & 0xff) / 255.;
633	PDF_setrgbcolor(myPDF, PDF_current_rgb.r, PDF_current_rgb.g, PDF_current_rgb.b);
634    }
635
636#ifndef HAVE_NODASH_LIBPDF
637	if (PDF_dashedlines) {
638	    char dashtype[64];
639	    float dl = 8.0 * PDF_dashlength_factor;
640
641	    switch (dash) {
642	    default:
643	    case 0:	PDF_setdash(myPDF, 0.0, 0.0);
644			return;
645	    case 1:	sprintf(dashtype,"dasharray={%4.1f %4.1f}",
646			dl*dash1[0],dl*dash1[1]);
647			break;
648	    case 2:	sprintf(dashtype,"dasharray={%4.1f %4.1f}",
649			dl*dash2[0],dl*dash2[1]);
650			break;
651	    case 3:	sprintf(dashtype,"dasharray={%4.1f %4.1f}",
652			dl*dash3[0],dl*dash3[1]);
653			break;
654	    case 4:	sprintf(dashtype,"dasharray={%4.1f %4.1f %4.1f %4.1f}",
655			dl*dash4[0],dl*dash4[1],dl*dash4[2],dl*dash4[3]);
656			break;
657	    case 5:	sprintf(dashtype,"dasharray={%4.1f %4.1f %4.1f %4.1f}",
658			dl*dash5[0],dl*dash5[1],dl*dash5[2],dl*dash5[3]);
659			break;
660	    case 6:	sprintf(dashtype,"dasharray={%4.1f %4.1f %4.1f %4.1f}",
661			dl*dash6[0],dl*dash6[1],dl*dash6[2],dl*dash6[3]);
662			break;
663	    case 7:	sprintf(dashtype,"dasharray={%4.1f %4.1f %4.1f %4.1f %4.1f %4.1f}",
664			dl*dash7[0],dl*dash7[1],dl*dash7[2],dl*dash7[3],dl*dash7[4],dl*dash7[5]);
665			break;
666	    }
667	    PDF_setdashpattern(myPDF,dashtype);
668	}
669#endif
670
671}
672
673
674TERM_PUBLIC void
675PDF_linewidth (double linewidth)
676{
677    PDF_PathClose();
678    PDF_LineWidth = PDF_RESOLUTION * PDF_linewidth_factor * linewidth / 4.0;
679    if (PDF_LineWidth < 0.1)
680	PDF_LineWidth = 0.1;
681    PDF_setlinewidth(myPDF, PDF_LineWidth);
682}
683
684
685TERM_PUBLIC void
686PDF_move (unsigned int x, unsigned int y)
687{
688    if (PDF_pathIsOpen && x == PDF_xLast && y == PDF_yLast)
689	return;
690
691    PDF_PathOpen ();
692    PDF_moveto(myPDF, x, y);
693
694    PDF_xLast = x;
695    PDF_yLast = y;
696}
697
698
699TERM_PUBLIC void
700PDF_vector (unsigned int x, unsigned int y)
701{
702    if (PDF_pathIsOpen && x == PDF_xLast && y == PDF_yLast)
703	return;
704
705    if (!PDF_pathIsOpen) {
706	PDF_PathOpen ();
707	PDF_moveto(myPDF, PDF_xLast, PDF_yLast);
708    }
709
710    PDF_lineto(myPDF, x, y);
711
712    PDF_xLast = x;
713    PDF_yLast = y;
714}
715
716/* Helper function. Many symbols have an additional dot in their
717 * center, so isolate its drawing into a separate function. */
718static GP_INLINE void
719PDF_dot (unsigned int x, unsigned int y)
720{
721    /* Imitate PS's way of creating a small dot by a zero-length line
722     * segment with rounded endpoints */
723    PDF_setlinecap(myPDF, 1); /* rounded ends */
724    PDF_moveto(myPDF, x, y);
725    PDF_lineto(myPDF, x, y);
726    PDF_stroke(myPDF);
727    PDF_setlinecap(myPDF, PDF_LineCap); /* restore ends */
728}
729
730
731TERM_PUBLIC void
732PDF_point (unsigned int x, unsigned int y, int number)
733{
734    PDF_PathClose ();
735    PDF_save(myPDF);
736
737    if (number < 0 || term_pointsize <= 0) {
738	/* Treat all negative point sizes as  dots */
739	PDF_dot(x, y);
740    } else {
741	/* Change coordinate system so the point symbols themselves
742	 * can be drawn without depending on position or size (-->
743	 * better compression and less coding for gnuplot) */
744	/* NB: I use the do_pointsize() default implementation, which
745	 * just stores the last set pointsize into `term_pointsize',
746	 * to avoid introducing another static driver-local variable
747	 * */
748	PDF_translate(myPDF, x, y);
749	PDF_scale(myPDF, term->h_tic / 2.0 * term_pointsize,
750		  term->v_tic / 2.0 * term_pointsize);
751	/* Correct linewidth to counter the scaling effect --- assume
752	 * h_tic is usable, to avoid having to average h_ and v_tic */
753	PDF_setlinewidth(myPDF,
754			 PDF_LineWidth / (term->h_tic / 2.0 * term_pointsize));
755	switch (number %= PDF_NUM_POINTTYPES) {
756	case 0:			/* Plus */
757	    PDF_moveto(myPDF, -1, 0);
758	    PDF_lineto(myPDF, 1, 0);
759	    PDF_moveto(myPDF, 0, -1);
760	    PDF_lineto(myPDF, 0, 1);
761	    PDF_stroke(myPDF);
762	    break;
763	case 2:			/* Star */
764	    PDF_moveto(myPDF, -1, 0);
765	    PDF_lineto(myPDF, 1, 0);
766	    PDF_moveto(myPDF, 0, -1);
767	    PDF_lineto(myPDF, 0, 1);
768	    /* FALLTHROUGH */
769	case 1:			/* Cross */
770	    PDF_moveto(myPDF, -1, -1);
771	    PDF_lineto(myPDF, 1, 1);
772	    PDF_moveto(myPDF, 1, -1);
773	    PDF_lineto(myPDF, -1, 1);
774	    PDF_stroke(myPDF);
775	    break;
776
777/* For each x = 0..5, 4 shapes are defined:
778 * 3 + 2*x --> hollow symbol with a dot at its center
779 * 4 + 2*x --> solid symbol filled in linetype's color
780 * 63 + x  --> hollow symbol without the center dot
781 * 69 + x  --> symbol filled with white --> opaque symbol */
782
783	case 63+0:		/* BoxEmpty */
784	case 3+2*0:		/* Box */
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_stroke(myPDF);
790	    if (number == 3) PDF_dot(0,0);
791	    break;
792	case 69+0:		/* BoxWhitefilled */
793	    PDF_setgray_fill(myPDF, 1);
794	    /* FALLTHROUGH */
795	case 4+2*0:		/* BoxFilled */
796	    PDF_moveto(myPDF, -1, -1);
797	    PDF_lineto(myPDF, 1, -1);
798	    PDF_lineto(myPDF, 1, 1);
799	    PDF_lineto(myPDF, -1, 1);
800	    PDF_closepath_fill_stroke(myPDF);
801	    break;
802
803	case 63+1:		/* CircleEmpty */
804	case 3+2*1:		/* Circle */
805	    PDF_circle(myPDF, 0, 0, 1);
806	    PDF_stroke(myPDF);
807	    if (number == 5) PDF_dot(0,0);
808	    break;
809	case 69+1:		/* CircleWhitefilled */
810	    PDF_setgray_fill(myPDF, 1);
811	    /* FALLTHROUGH */
812	case 4+2*1:		/* CircleFilled */
813	    PDF_circle(myPDF, 0, 0, 1);
814	    PDF_fill_stroke(myPDF);
815	    break;
816
817	case 63+2:		/* TriangleUpEmpty */
818	case 3+2*2:		/* TriangleUp */
819	    PDF_moveto(myPDF, 0, 1.12);
820	    PDF_lineto(myPDF, -1, -0.5);
821	    PDF_lineto(myPDF, 1, -0.5);
822	    PDF_closepath_stroke(myPDF);
823	    if (number == 7) PDF_dot(0,0);
824	    break;
825	case 69+2:		/* TriangleUpWhitefilled */
826	    PDF_setgray_fill(myPDF, 1);
827	    /* FALLTHROUGH */
828	case 4+2*2:			/* TriangleUpFilled */
829	    PDF_moveto(myPDF, 0, 1.12);
830	    PDF_lineto(myPDF, -1, -0.5);
831	    PDF_lineto(myPDF, 1, -0.5);
832	    PDF_closepath_fill_stroke(myPDF);
833	    break;
834
835	case 63+3:		/* TriangleDownEmpty */
836	case 3+2*3:		/* TriangleDown */
837	    PDF_moveto(myPDF, 0, -1.12);
838	    PDF_lineto(myPDF, -1, 0.5);
839	    PDF_lineto(myPDF, 1, 0.5);
840	    PDF_closepath_stroke(myPDF);
841	    if (number == 9) PDF_dot(0,0);
842	    break;
843	case 69+3:		/* TriangleDownWhitefilled */
844	    PDF_setgray_fill(myPDF, 1);
845	    /* FALLTHROUGH */
846	case 4+2*3:		/* TriangleDownFilled */
847	    PDF_moveto(myPDF, 0, -1.12);
848	    PDF_lineto(myPDF, -1, 0.5);
849	    PDF_lineto(myPDF, 1, 0.5);
850	    PDF_closepath_fill_stroke(myPDF);
851	    break;
852
853	case 63+4:		/* DiamondEmpty */
854	case 3+2*4:		/* Diamond */
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_stroke(myPDF);
860	    if (number == 11) PDF_dot(0,0);
861	    break;
862	case 69+4:		/* DiamondWhitefilled */
863	    PDF_setgray_fill(myPDF, 1);
864	    /* FALLTHROUGH */
865	case 4+2*4:		/* DiamondFilled */
866	    PDF_moveto(myPDF, 0, -1);
867	    PDF_lineto(myPDF, 1, 0);
868	    PDF_lineto(myPDF, 0, 1);
869	    PDF_lineto(myPDF, -1, 0);
870	    PDF_closepath_fill_stroke(myPDF);
871	    break;
872
873	case 63+5:		/* PentagonEmpty */
874	case 3+2*5:		/* Pentagon */
875	    PDF_moveto(myPDF, 0, 1);
876	    PDF_lineto(myPDF, -0.95, 0.31);
877	    PDF_lineto(myPDF, -0.58, -0.81);
878	    PDF_lineto(myPDF, +0.58, -0.81);
879	    PDF_lineto(myPDF, +0.95, 0.31);
880	    PDF_closepath_stroke(myPDF);
881	    if (number == 13) PDF_dot(0,0);
882	    break;
883	case 69+5:		/* PentagonWhitefilled */
884	    PDF_setgray_fill(myPDF, 1);
885	    /* FALLTHROUGH */
886	case 4+2*5:		/* PentagonFilled */
887	    PDF_moveto(myPDF, 0, 1);
888	    PDF_lineto(myPDF, -0.95, 0.31);
889	    PDF_lineto(myPDF, -0.58, -0.81);
890	    PDF_lineto(myPDF, +0.58, -0.81);
891	    PDF_lineto(myPDF, +0.95, 0.31);
892	    PDF_closepath_fill_stroke(myPDF);
893	    break;
894
895/* 15 + (0..15): circles with varying parts of'em filled. The added
896 * number is a bit-pattern of the 4 quadrants: 1 signals a quadrant
897 * filled */
898	case 15+0:
899	    PDF_moveto(myPDF, 0, 0);
900	    PDF_lineto(myPDF, 0, 1);
901	    PDF_arc(myPDF, 0, 0, 1, 90, 360+90);
902	    PDF_closepath_stroke(myPDF);
903	    break;
904
905/* Generalize common code into a macro... */
906#define CIRCLE_SINGLE_PIESLICE(x, y, angle1, angle2)		\
907	    PDF_moveto(myPDF, 0, 0);				\
908	    PDF_lineto(myPDF, (x), (y));			\
909	    PDF_arc(myPDF, 0, 0, 1, (angle1), (angle2));	\
910	    PDF_lineto(myPDF, 0, 0);				\
911	    PDF_closepath(myPDF);				\
912	    PDF_fill_stroke(myPDF);				\
913	    PDF_arc(myPDF, 0, 0, 1, (angle2), (angle1) + 360);	\
914	    PDF_stroke(myPDF);					\
915	    break;
916
917#define CIRCLE_SINGLE_QUADRANT(x, y, angle)			\
918	    CIRCLE_SINGLE_PIESLICE(x, y, angle, angle+90);
919	case 15+1:
920	    CIRCLE_SINGLE_QUADRANT(1, 0, 0);
921	case 15+2:
922	    CIRCLE_SINGLE_QUADRANT(0, 1, 90);
923	case 15+4:
924	    CIRCLE_SINGLE_QUADRANT(-1, 0, 180);
925	case 15+8:
926	    CIRCLE_SINGLE_QUADRANT(0, -1, 270);
927#undef CIRCLE_SINGLE_QUADRANT
928
929#define CIRCLE_TWO_NEIGHBOR_QUADRANTS(x, y, angle)		\
930	    CIRCLE_SINGLE_PIESLICE(x, y, angle, angle+180)
931	case 15+3:
932	    CIRCLE_TWO_NEIGHBOR_QUADRANTS(1, 0, 0);
933	case 15+6:
934	    CIRCLE_TWO_NEIGHBOR_QUADRANTS(0, 1, 90);
935	case 15+12:
936	    CIRCLE_TWO_NEIGHBOR_QUADRANTS(-1, 0, 180);
937	case 15+9:
938	    CIRCLE_TWO_NEIGHBOR_QUADRANTS(0, -1, 270);
939#undef CIRCLE_TWO_NEIGHBOR_QUADRANTS
940
941#define CIRCLE_TWO_OPPOSING_QUADRANTS(x, y, angle)		\
942	    PDF_moveto(myPDF, 0, 0);				\
943	    PDF_lineto(myPDF, x, y);				\
944	    PDF_arc(myPDF, 0, 0, 1, angle, angle + 90);		\
945	    PDF_lineto(myPDF, 0, 0);				\
946	    PDF_fill_stroke(myPDF);				\
947	    PDF_moveto(myPDF, 0, 0);				\
948	    PDF_lineto(myPDF, -x, -y);				\
949	    PDF_arc(myPDF, 0, 0, 1, angle + 180, angle + 270);	\
950	    PDF_lineto(myPDF, 0, 0);				\
951	    PDF_fill_stroke(myPDF);				\
952	    PDF_arc(myPDF, 0, 0, 1, angle + 90, angle + 360);	\
953	    PDF_stroke(myPDF);					\
954	    break;
955	case 15+5:
956	    CIRCLE_TWO_OPPOSING_QUADRANTS(1, 0, 0);
957	case 15+10:
958	    CIRCLE_TWO_OPPOSING_QUADRANTS(0, 1, 90);
959#undef CIRCLE_TWO_OPPOSING_QUADRANTS
960
961#define CIRCLE_THREE_QUADRANTS(x, y, angle)			\
962	    CIRCLE_SINGLE_PIESLICE(x, y, angle, angle+270)
963	case 15+7:
964	    CIRCLE_THREE_QUADRANTS(1, 0, 0);
965	case 15+14:
966	    CIRCLE_THREE_QUADRANTS(0, 1, 90);
967	case 15+13:
968	    CIRCLE_THREE_QUADRANTS(-1, 0, 180);
969	case 15+11:
970	    CIRCLE_THREE_QUADRANTS(0, -1, 270);
971#undef CIRCLE_THREE_QUADRANTS
972#undef CIRCLE_SINGLE_PIESLICE
973
974	case 15+15:
975	    PDF_circle(myPDF, 0, 0, 1);
976	    PDF_closepath_fill_stroke(myPDF);
977	    break;
978
979
980/*************************************************************************/
981/* 31 + (0..15): squares with different quadrants of them filled in. */
982/*************************************************************************/
983/*************************************************************************/
984/* 47 + (0..15): diamonds with filled quadrants as given by bit pattern  */
985/*   Diamonds are drawn as squares rotated by 45 degrees, so can use
986 * fall-through from diamond to squares, and re-use some macros. */
987/*************************************************************************/
988	case 47+0:
989	    PDF_rotate(myPDF, 45);
990	    /* FALLTHROUGH */
991	case 31+0:
992	    PDF_moveto(myPDF, 0, 0);
993	    PDF_lineto(myPDF, 0, 1);
994	    PDF_lineto(myPDF, -1, 1);
995	    PDF_lineto(myPDF, -1, -1);
996	    PDF_lineto(myPDF, 1, -1);
997	    PDF_lineto(myPDF, 1, 1);
998	    PDF_lineto(myPDF, 0, 1);
999	    PDF_stroke(myPDF);
1000	    break;
1001
1002	case 47+15:
1003	    PDF_rotate(myPDF, 45);
1004	    /* FALLTHROUGH */
1005	case 31+15:
1006	    PDF_moveto(myPDF, -1, 1);
1007	    PDF_lineto(myPDF, -1, -1);
1008	    PDF_lineto(myPDF, 1, -1);
1009	    PDF_lineto(myPDF, 1, 1);
1010	    PDF_closepath_fill_stroke(myPDF);
1011	    break;
1012
1013/* macros defining shapes of the partly filled symbols. Done by
1014 * rotating the starting point (x0, y0) by 90 degrees or 45 degrees
1015 * (with length adjustment).  The rotations can be done without
1016 * trigonometric function calls, since their values are known:
1017 * cos(90)=0, sin(90)=1, cos(45)=sin(45)=1/sqrt(2).  A good compiler
1018 * should be able to optimize away all the local variables and
1019 * loops...  */
1020
1021#define SQUARE_SINGLE_PIESLICE(x0, y0, quadrants)			\
1022	    {								\
1023		int quadrant = 0;					\
1024		int x= x0, y=y0;					\
1025		PDF_moveto(myPDF, 0, 0);				\
1026		PDF_lineto(myPDF, x, y);				\
1027		/* poor man's rotation by 45 and 90 degrees around the	\
1028		 * square's outline. */					\
1029		while (quadrant++ < quadrants) {			\
1030		    int dummy;						\
1031		    PDF_lineto(myPDF, x-y, x+y);			\
1032		    dummy = x; x = -y; y = dummy;			\
1033		}							\
1034		PDF_lineto(myPDF, x, y);				\
1035		PDF_closepath_fill_stroke(myPDF);			\
1036		PDF_moveto(myPDF, x, y);				\
1037		while (quadrant++ <= 4) {				\
1038		    int dummy;						\
1039		    PDF_lineto(myPDF, x-y, x+y);			\
1040		    dummy = x; x = -y; y = dummy;			\
1041		}							\
1042		PDF_lineto(myPDF, x, y);				\
1043		PDF_stroke(myPDF);					\
1044	    }								\
1045	    break;
1046
1047#define SQUARE_TWO_OPPOSING_QUADRANTS(x0, y0, angle)	\
1048	    {						\
1049		int x = x0, y = y0, dummy;		\
1050		int counter = 0;			\
1051							\
1052		while (counter++ < 2) {			\
1053		    PDF_moveto(myPDF, 0, 0);		\
1054		    PDF_lineto(myPDF, x, y);		\
1055		    PDF_lineto(myPDF, x-y, x+y);	\
1056		    dummy = x; x = -y; y = dummy;	\
1057		    PDF_lineto(myPDF, x, y);		\
1058		    PDF_closepath_fill_stroke(myPDF);	\
1059							\
1060		    PDF_moveto(myPDF, x, y);		\
1061		    PDF_lineto(myPDF, x-y, x+y);	\
1062		    dummy = x; x = -y; y = dummy;	\
1063		    PDF_lineto(myPDF, x, y);		\
1064		    PDF_stroke(myPDF);			\
1065		}					\
1066		break;					\
1067	    }
1068
1069/* Macros for diamonds just prepend the rotation and then call those
1070 * for squares: */
1071#define DIAMOND_SINGLE_PIESLICE(x, y, quadrants)	\
1072	    PDF_rotate(myPDF, 45);			\
1073	    SQUARE_SINGLE_PIESLICE(x, y, quadrants);
1074#define DIAMOND_TWO_OPPOSING_QUADRANTS(x, y, angle)	\
1075	    PDF_rotate(myPDF, 45);			\
1076	    SQUARE_TWO_OPPOSING_QUADRANTS(x, y, angle);
1077
1078/* ... and now all the individual cases. The 'angle' arguments' are
1079 * purely for the sake of easing cut'n'paste with the circle case */
1080#define SQUARE_SINGLE_QUADRANT(x, y, angle)			\
1081	    SQUARE_SINGLE_PIESLICE(x, y, 1);
1082	case 31+1:
1083	    SQUARE_SINGLE_QUADRANT(1, 0, 0);
1084	case 31+2:
1085	    SQUARE_SINGLE_QUADRANT(0, 1, 90);
1086	case 31+4:
1087	    SQUARE_SINGLE_QUADRANT(-1, 0, 180);
1088	case 31+8:
1089	    SQUARE_SINGLE_QUADRANT(0, -1, 270);
1090#undef SQUARE_SINGLE_QUADRANT
1091
1092#define SQUARE_TWO_NEIGHBOR_QUADRANTS(x, y, angle)		\
1093	    SQUARE_SINGLE_PIESLICE(x, y, 2)
1094	case 31+3:
1095	    SQUARE_TWO_NEIGHBOR_QUADRANTS(1, 0, 0);
1096	case 31+6:
1097	    SQUARE_TWO_NEIGHBOR_QUADRANTS(0, 1, 90);
1098	case 31+12:
1099	    SQUARE_TWO_NEIGHBOR_QUADRANTS(-1, 0, 180);
1100	case 31+9:
1101	    SQUARE_TWO_NEIGHBOR_QUADRANTS(0, -1, 270);
1102#undef SQUARE_TWO_NEIGHBOR_QUADRANTS
1103
1104	case 31+5:
1105	    SQUARE_TWO_OPPOSING_QUADRANTS(1, 0, 0);
1106	case 31+10:
1107	    SQUARE_TWO_OPPOSING_QUADRANTS(0, 1, 90);
1108
1109#define SQUARE_THREE_QUADRANTS(x, y, angle)			\
1110	    SQUARE_SINGLE_PIESLICE(x, y, 3)
1111	case 31+7:
1112	    SQUARE_THREE_QUADRANTS(1, 0, 0);
1113	case 31+14:
1114	    SQUARE_THREE_QUADRANTS(0, 1, 90);
1115	case 31+13:
1116	    SQUARE_THREE_QUADRANTS(-1, 0, 180);
1117	case 31+11:
1118	    SQUARE_THREE_QUADRANTS(0, -1, 270);
1119#undef SQUARE_THREE_QUADRANTS
1120
1121#define DIAMOND_SINGLE_QUADRANT(x, y, angle)			\
1122	    DIAMOND_SINGLE_PIESLICE(x, y, 1)
1123	case 47+1:
1124	    DIAMOND_SINGLE_QUADRANT(1, 0, 0);
1125	case 47+2:
1126	    DIAMOND_SINGLE_QUADRANT(0, 1, 90);
1127	case 47+4:
1128	    DIAMOND_SINGLE_QUADRANT(-1, 0, 180);
1129	case 47+8:
1130	    DIAMOND_SINGLE_QUADRANT(0, -1, 270);
1131#undef DIAMOND_SINGLE_QUADRANT
1132
1133#define DIAMOND_TWO_NEIGHBOR_QUADRANTS(x, y, angle)		\
1134	    DIAMOND_SINGLE_PIESLICE(x, y, 2)
1135	case 47+3:
1136	    DIAMOND_TWO_NEIGHBOR_QUADRANTS(1, 0, 0);
1137	case 47+6:
1138	    DIAMOND_TWO_NEIGHBOR_QUADRANTS(0, 1, 90);
1139	case 47+12:
1140	    DIAMOND_TWO_NEIGHBOR_QUADRANTS(-1, 0, 180);
1141	case 47+9:
1142	    DIAMOND_TWO_NEIGHBOR_QUADRANTS(0, -1, 270);
1143#undef DIAMOND_TWO_NEIGHBOR_QUADRANTS
1144
1145
1146	case 47+5:
1147	    DIAMOND_TWO_OPPOSING_QUADRANTS(1, 0, 0);
1148	case 47+10:
1149	    DIAMOND_TWO_OPPOSING_QUADRANTS(0, 1, 90);
1150#undef DIAMOND_TWO_OPPOSING_QUADRANTS
1151#undef SQUARE_TWO_OPPOSING_QUADRANTS
1152
1153#define DIAMOND_THREE_QUADRANTS(x, y, angle)			\
1154	    DIAMOND_SINGLE_PIESLICE(x, y, 3)
1155	case 47+7:
1156	    DIAMOND_THREE_QUADRANTS(1, 0, 0);
1157	case 47+14:
1158	    DIAMOND_THREE_QUADRANTS(0, 1, 90);
1159	case 47+13:
1160	    DIAMOND_THREE_QUADRANTS(-1, 0, 180);
1161	case 47+11:
1162	    DIAMOND_THREE_QUADRANTS(0, -1, 270);
1163#undef DIAMOND_THREE_QUADRANTS
1164#undef DIAMOND_SINGLE_PIESLICE
1165#undef SQUARE_SINGLE_PIESLICE
1166
1167	default:
1168	    int_warn(NO_CARET, "PDF: unknown point type number %d", number);
1169	}
1170    }
1171
1172    PDF_restore(myPDF);
1173    PDF_xLast = x;
1174    PDF_yLast = y;
1175}
1176
1177
1178TERM_PUBLIC int
1179PDF_justify_text (enum JUSTIFY mode)
1180{
1181    PDF_TextJust = mode;
1182    return (TRUE);
1183}
1184
1185
1186TERM_PUBLIC int
1187PDF_text_angle (int ang)
1188{
1189    PDF_TextAngle = ang;
1190    return (TRUE);
1191}
1192
1193
1194TERM_PUBLIC void
1195PDF_put_text (unsigned int x, unsigned int y, const char *str)
1196{
1197    char *alignment = NULL;
1198    double h = x, v = y;
1199
1200    PDF_PathClose ();
1201
1202    /* horizontal justification*/
1203    switch (PDF_TextJust) {
1204    case LEFT:
1205	alignment = "left";
1206	break;
1207    case CENTRE:
1208	alignment = "center";
1209	break;
1210    case RIGHT:
1211	alignment = "right";
1212	break;
1213    }
1214
1215    if (PDF_TextAngle) {
1216	PDF_save(myPDF);
1217	PDF_translate(myPDF, h, v);
1218	PDF_rotate(myPDF, PDF_TextAngle);
1219	/* vertical justification*/
1220	PDF_translate(myPDF, 0, -(PDF_fontAscent-PDF_fontDescent)/2);
1221	PDF_show_boxed(myPDF, str, 0,0, 0, 0, alignment, NULL);
1222	PDF_restore(myPDF);
1223    } else {
1224	/* vertical justification*/
1225	v -= (PDF_fontAscent - PDF_fontDescent) / 2;
1226	PDF_show_boxed(myPDF, str, h , v, 0, 0, alignment, NULL);
1227    }
1228
1229}
1230
1231
1232TERM_PUBLIC int
1233PDF_set_font (const char *font)
1234{
1235    /* FIXME: This condition is somehow triggered by enhanced_recursion */
1236    if (font == PDF_fontNameCur)
1237	;
1238
1239    else if (!font || !(*font)) {
1240	strcpy (PDF_fontNameCur, PDF_fontNameDef);
1241	PDF_fontSizeCur = PDF_fontSizeDef;
1242    } else {
1243	int sep = strcspn(font,",");
1244	if (sep > 0) {
1245	    strncpy(PDF_fontNameCur,font,sep);
1246	    PDF_fontNameCur[sep] = NUL;
1247	}
1248	if (font[sep] == ',')
1249	    sscanf(&(font[sep+1]), "%lf", &PDF_fontSizeCur);
1250    }
1251
1252    PDF_PathClose();
1253    PDF_SetFont();
1254
1255    term->h_char = PDF_fontAvWidth;
1256    term->v_char = (PDF_fontAscent + PDF_fontDescent + PDF_fontLeading);
1257
1258    return (TRUE);
1259}
1260
1261TERM_PUBLIC void
1262PDF_boxfill(int style, unsigned int x1, unsigned int y1,
1263	    unsigned int width, unsigned int height)
1264{
1265    gpiPoint corner[4];
1266
1267	corner[0].x = x1;        corner[0].y = y1;
1268	corner[1].x = x1+width;  corner[1].y = y1;
1269	corner[2].x = x1+width;  corner[2].y = y1+height;
1270	corner[3].x = x1;        corner[3].y = y1+height;
1271
1272	corner->style = style;
1273	PDF_filled_polygon(4, corner);
1274}
1275
1276TERM_PUBLIC void
1277PDF_filled_polygon(int points, gpiPoint* corners)
1278{
1279    int i;
1280    int fillpar = corners->style >> 4;
1281    int style = corners->style &= 0xf;
1282
1283    PDF_PathClose();
1284    PDF_save(myPDF);
1285
1286    switch (style) {
1287	case FS_EMPTY: /* fill with white */
1288	    PDF_setgray(myPDF, 1);
1289	    break;
1290	case FS_TRANSPARENT_SOLID:
1291#if !HAVE_OLD_LIBPDF
1292	    {
1293		/* FIXME: This attribute will be in effect until the end of   */
1294		/* the current page. We should explicitly reset it to restore */
1295		/* opaque fill areas as the default. But when should it be?   */
1296		char density[18];
1297		double red   = PDF_current_rgb.r;
1298		double green = PDF_current_rgb.g;
1299		double blue  = PDF_current_rgb.b;
1300		sprintf(density,"opacityfill=%4.2f", (double)fillpar*0.01);
1301		i = PDF_create_gstate(myPDF, density);
1302		PDF_set_gstate(myPDF, i);
1303		if (PDF_monochrome)
1304		    PDF_setgray_fill(myPDF, PDF_current_gray);
1305		else
1306		    PDF_setrgbcolor_fill(myPDF, red, green, blue);
1307		break;
1308	    }
1309#endif
1310	case FS_SOLID:
1311	    {
1312		double fact = (double)fillpar * 0.01;
1313		double _fact = (double)(100-fillpar) * 0.01;
1314		double red   = PDF_current_rgb.r * fact + _fact;
1315		double green = PDF_current_rgb.g * fact + _fact;
1316		double blue  = PDF_current_rgb.b * fact + _fact;
1317		if (PDF_monochrome)
1318		    PDF_setgray_fill(myPDF, PDF_current_gray);
1319		else
1320		    PDF_setrgbcolor_fill(myPDF, red, green, blue);
1321	    }
1322	    break;
1323
1324#if !HAVE_OLD_LIBPDF
1325	case FS_PATTERN:
1326	    fillpar = fillpar % (PDF_patterns + 1) /* 0 == white */;
1327	    /* Fill in solid background before drawing pattern */
1328	    /* NOTE:  kpdf/xpdf would accept this as part of the pattern definition */
1329	    /*        but acroread does not. So for compatibility we do the fill in */
1330	    /*        a separate step, despite its inefficiency.                    */
1331	    if (fillpar != 0) {
1332		PDF_setcolor(myPDF, "fill", "rgb", 1, 1, 1, 0 /* unused */);
1333		PDF_moveto(myPDF, corners[0].x, corners[0].y);
1334		for (i=1; i<points; i++)
1335		    PDF_lineto(myPDF, corners[i].x, corners[i].y);
1336		PDF_lineto(myPDF, corners[0].x, corners[0].y);
1337		PDF_fill(myPDF);
1338		PDF_restore(myPDF);
1339		PDF_save(myPDF);
1340	    }
1341	    /* NOTE: Fall through to the actual pattern code */
1342	case FS_TRANSPARENT_PATTERN:
1343	    fillpar = fillpar % (PDF_patterns + 1) /* 0 == white */;
1344	    switch (fillpar) {
1345		case 0:
1346		    /* fill with white */
1347		    PDF_setcolor(myPDF, "fill", "rgb", 1, 1, 1, 0 /* unused */);
1348		    break;
1349		default:
1350		    PDF_setcolor(myPDF, "fill", "pattern", PDF_patternHandles[fillpar - 1], 0, 0, 0);
1351	    }
1352	    break;
1353#endif
1354
1355	default:
1356	    break;
1357    }
1358
1359    PDF_moveto(myPDF, corners[0].x, corners[0].y);
1360    for (i=1; i<points; i++)
1361	PDF_lineto(myPDF, corners[i].x, corners[i].y);
1362    PDF_lineto(myPDF, corners[0].x, corners[0].y);
1363    PDF_fill(myPDF);
1364    PDF_restore(myPDF);
1365}
1366
1367TERM_PUBLIC int
1368PDF_make_palette(t_sm_palette *palette)
1369{
1370    if (palette == NULL) {
1371	/* pdf can do continuous colors */
1372	return 0;
1373    }
1374
1375    return 0;
1376}
1377
1378TERM_PUBLIC void
1379PDF_set_color(t_colorspec *colorspec)
1380{
1381    if (colorspec->type == TC_LT) {
1382	unsigned int irgb = pm3d_color_names_tbl[ 1 + PDF_Pen_RealID(colorspec->lt) ].value;
1383	PDF_current_rgb.r = (double)((irgb >> 16) & 0xff) / 255.;
1384	PDF_current_rgb.g = (double)((irgb >>  8) & 0xff) / 255.;
1385	PDF_current_rgb.b = (double)((irgb      ) & 0xff) / 255.;
1386	PDF_current_gray = 0.0; /* monochrome mode only */
1387    } else if (colorspec->type == TC_FRAC) {
1388	rgb1maxcolors_from_gray( colorspec->value, &PDF_current_rgb);
1389	PDF_current_gray = colorspec->value; /* monochrome mode only */
1390    } else if (colorspec->type == TC_RGB) {
1391	PDF_current_rgb.r = (double)((colorspec->lt >> 16 ) & 255) / 255.;
1392	PDF_current_rgb.g = (double)((colorspec->lt >> 8 ) & 255) / 255.;
1393	PDF_current_rgb.b = (double)(colorspec->lt & 255) / 255.;
1394    } else
1395	return;
1396
1397    /* make sure that the path is stroked with the current color
1398     * before changing the color */
1399    PDF_PathClose();
1400
1401    if (PDF_monochrome && colorspec->type != TC_RGB)
1402	PDF_setgray(myPDF, PDF_current_gray);  /* FIXME - Should this be NTSC(current_rgb)? */
1403    else
1404	PDF_setrgbcolor(myPDF, PDF_current_rgb.r, PDF_current_rgb.g, PDF_current_rgb.b);
1405
1406    /* mark linetype invalid so that the color will be
1407     * set when PDF_linetype() is called next */
1408    PDF_LineType = LT_UNDEFINED;
1409}
1410
1411TERM_PUBLIC void
1412PDF_previous_palette()
1413{
1414}
1415
1416TERM_PUBLIC void
1417PDF_image (unsigned int M, unsigned int N, coordval * image, gpiPoint * corner, t_imagecolor color_mode)
1418{
1419    unsigned char *pixel;
1420    float xscale, yscale;
1421    int i, im;
1422
1423    /* Allocate memory to hold a copy of the entire image in raw RGB format */
1424    unsigned char *rawrgb = gp_alloc( M*N*3, "Raw RGB image");
1425
1426    /* Convert the input image into raw RGB 24-bit color representation */
1427    if (color_mode == IC_RGB) {
1428	for (i=0, pixel=rawrgb; i<N*M*3;) {
1429	    rgb_color rgb1;
1430	    rgb255_color rgb255;
1431	    rgb1.r = image[i++];
1432	    rgb1.g = image[i++];
1433	    rgb1.b = image[i++];
1434	    rgb255_from_rgb1( rgb1, &rgb255 );
1435	    *pixel++ = rgb255.r;
1436	    *pixel++ = rgb255.g;
1437	    *pixel++ = rgb255.b;
1438	}
1439    } else {
1440        for (i=0, pixel=rawrgb; i< N*M; i++) {
1441	    if (isnan(image[i])) {
1442		/* Transparent would be better! */
1443		*pixel++ = 255;
1444		*pixel++ = 255;
1445		*pixel++ = 255;
1446	    } else {
1447		rgb255_color rgb;
1448		rgb255maxcolors_from_gray(image[i], &rgb);
1449		*pixel++ = rgb.r;
1450		*pixel++ = rgb.g;
1451		*pixel++ = rgb.b;
1452	    }
1453	}
1454    }
1455
1456    /* Describe this image to PDF library */
1457    im = PDF_open_image( myPDF, "raw", "memory", (char *)rawrgb,
1458			 (long)(M*N*3), (int)M, (int)N,
1459			 3, 8,				/* 3 colors, 8 bits each */
1460			 "");
1461
1462    /* Clip to bounding box requested */
1463	PDF_save(myPDF);
1464	PDF_moveto(myPDF, corner[2].x, corner[2].y);
1465	PDF_lineto(myPDF, corner[2].x, corner[3].y);
1466	PDF_lineto(myPDF, corner[3].x, corner[3].y);
1467	PDF_lineto(myPDF, corner[3].x, corner[2].y);
1468	PDF_closepath(myPDF);
1469	PDF_clip(myPDF);
1470
1471/* Scale and copy into the main PDF image */
1472	xscale = fabs((float)corner[1].x - (float)corner[0].x) / (float)M;
1473	yscale = fabs((float)corner[1].y - (float)corner[0].y) / (float)N;
1474	PDF_translate(myPDF, corner[0].x, corner[0].y);
1475	PDF_scale(myPDF, xscale, yscale);
1476	PDF_translate(myPDF, 0, -(float)N);
1477	PDF_place_image(myPDF, im, 0.0, 0.0, 1.0 );
1478	PDF_restore(myPDF);
1479
1480    /* Clean up */
1481	PDF_close_image(myPDF, im);
1482	free(rawrgb);
1483
1484}
1485
1486/*
1487 * Ethan A Merritt November 2003
1488 *	- support for enhanced text mode
1489 * BUGS:
1490 *	- The baseline is not consistent if font size changes within a string.
1491 *	- Placement of overprinted characters is not correct.
1492 *	- libpdf exits if the requested font is not recognized.
1493 *	- I implement text-rotation by hand, but it may be possible to use
1494 *	  a gsave/translate/rotate/.../grestore sequence instead.
1495 */
1496
1497static TBOOLEAN ENHpdf_opened_string;
1498
1499/* used in determining height of processed text */
1500static float ENHpdf_base;
1501
1502/* use these so that we don't over-write the current font settings in pdf_state */
1503static double  ENHpdf_fontsize;
1504static char   *ENHpdf_font;
1505
1506/* A global flag that tells us this run is just to determine text size */
1507static TBOOLEAN ENHpdf_sizeonly = FALSE;
1508
1509static TBOOLEAN ENHpdf_show = TRUE;
1510static int ENHpdf_overprint = 0;
1511static TBOOLEAN ENHpdf_widthflag = FALSE;
1512static unsigned int ENHpdf_xsave, ENHpdf_ysave;
1513
1514/* Start a new string fragment */
1515TERM_PUBLIC void
1516ENHPDF_OPEN(
1517    char *fontname,
1518    double fontsize, double base,
1519    TBOOLEAN widthflag, TBOOLEAN showflag,
1520    int overprint)
1521{
1522    /* If the overprint code requests a save or request, that's all we do */
1523    if (overprint == 3) {
1524	ENHpdf_xsave = PDF_xLast;
1525	ENHpdf_ysave = PDF_yLast;
1526	return;
1527    } else if (overprint == 4) {
1528	PDF_move(ENHpdf_xsave, ENHpdf_ysave);
1529	return;
1530    }
1531
1532    if (!ENHpdf_opened_string) {
1533	ENHpdf_opened_string = TRUE;
1534	enhanced_cur_text = &enhanced_text[0];
1535	ENHpdf_font = fontname;
1536	ENHpdf_fontsize = fontsize;
1537	ENHpdf_base = base * PDF_RESOLUTION;
1538	ENHpdf_show = showflag;
1539	ENHpdf_overprint = overprint;
1540	ENHpdf_widthflag = widthflag;
1541    }
1542}
1543
1544/* Write a string fragment and update the current position */
1545TERM_PUBLIC void
1546ENHPDF_FLUSH()
1547{
1548    int x, y;
1549    float stringlength;
1550
1551	if (ENHpdf_opened_string) {
1552	    ENHpdf_opened_string = FALSE;
1553	    *enhanced_cur_text = '\0';
1554	    x = PDF_xLast;
1555	    y = PDF_yLast;
1556	    x -= sin((double)PDF_TextAngle * M_PI_2/90.) * ENHpdf_base;
1557	    y += cos((double)PDF_TextAngle * M_PI_2/90.) * ENHpdf_base;
1558	    x += sin((double)PDF_TextAngle * M_PI_2/90.) * (double)PDF_fontAvWidth/2.;
1559	    y -= cos((double)PDF_TextAngle * M_PI_2/90.) * (double)PDF_fontAvWidth/2.;
1560
1561	    /* Select current font for enhanced text fragment, then restore context */
1562	    if (1) {
1563		char save_fontname[MAX_ID_LEN + 1];
1564		double save_fontsize = PDF_fontSizeCur;
1565		    strcpy(save_fontname,PDF_fontNameCur);
1566		    PDF_fontSizeCur = ENHpdf_fontsize / PDF_fontscale;
1567		    PDF_set_font(ENHpdf_font);
1568		    strcpy(PDF_fontNameCur,save_fontname);
1569		    PDF_fontSizeCur = save_fontsize;
1570	    }
1571
1572	    /* Find length of string in current font */
1573	    stringlength = PDF_stringwidth(myPDF, enhanced_text,
1574		PDF_currentFontHandle, ENHpdf_fontsize);
1575	    stringlength *= PDF_RESOLUTION;
1576
1577	    if (ENHpdf_show && !ENHpdf_sizeonly) {
1578		if (PDF_TextAngle == 0 ) {
1579		    /* PDF_show(myPDF, enhanced_text); */
1580		    PDF_show_boxed(myPDF, enhanced_text, x, y, 0, 0, "left", NULL);
1581		} else {
1582		    PDF_save(myPDF);
1583		    PDF_translate(myPDF, x, y);
1584		    PDF_rotate(myPDF, PDF_TextAngle);
1585		    /* vertical justification*/
1586		    PDF_translate(myPDF, 0, -(PDF_fontAscent-PDF_fontDescent)/2);
1587		    PDF_show_boxed(myPDF, enhanced_text, 0, 0, 0, 0, "left", NULL);
1588		    PDF_restore(myPDF);
1589		}
1590	    }
1591	    if (ENHpdf_overprint == 1) {
1592		PDF_xLast += stringlength * cos((double)PDF_TextAngle * M_PI_2/90.) / 2.;
1593		PDF_yLast += stringlength * sin((double)PDF_TextAngle * M_PI_2/90.);
1594	    } else if (ENHpdf_widthflag) {
1595		PDF_xLast += stringlength * cos((double)PDF_TextAngle * M_PI_2/90.);
1596		PDF_yLast += stringlength * sin((double)PDF_TextAngle * M_PI_2/90.);
1597	    }
1598	}
1599}
1600
1601TERM_PUBLIC void
1602ENHPDF_put_text(unsigned int x, unsigned int y, const char *str)
1603{
1604    char *original_string = (char *)str;
1605
1606    if (ignore_enhanced_text) {
1607	PDF_put_text(x,y,str);
1608	return;
1609    }
1610
1611    if (!str || !strlen(str))
1612	return;
1613
1614    /* if there are no magic characters, we should just be able
1615     * punt the string to PDF_put_text()
1616     */
1617    if (!strpbrk(str, "{}^_@&~")) {
1618	/* do something to ensure default font is selected */
1619	PDF_put_text(x,y,str);
1620	return;
1621    }
1622
1623    PDF_move(x, y);
1624    PDF_PathClose();
1625    PDF_save(myPDF);
1626
1627    /* FIXME - Is this the way to do it?????
1628    if (PDF_TextAngle != 0)
1629	ENHPDF_DEBUG(("currentpoint gsave translate %d rotate 0 0 moveto\n", PDF_TextAngle));
1630     */
1631
1632    /* set up the global variables needed by enhanced_recursion() */
1633    enhanced_fontscale = PDF_fontscale;
1634    strncpy(enhanced_escape_format,"%c",sizeof(enhanced_escape_format));
1635
1636    ENHpdf_opened_string = FALSE;
1637
1638    /* EAM - Software text justification requires two passes */
1639    if (PDF_TextJust == RIGHT || PDF_TextJust == CENTRE)
1640	ENHpdf_sizeonly = TRUE;
1641
1642    /* Set the recursion going. We say to keep going until a
1643     * closing brace, but we don't really expect to find one.
1644     * If the return value is not the nul-terminator of the
1645     * string, that can only mean that we did find an unmatched
1646     * closing brace in the string. We increment past it (else
1647     * we get stuck in an infinite loop) and try again.
1648     */
1649    while (*(str = enhanced_recursion((char *)str, TRUE,
1650			PDF_fontNameCur, PDF_fontSizeCur * PDF_fontscale,
1651			0.0, TRUE, TRUE, 0))) {
1652	(term->enhanced_flush)();
1653
1654	/* I think we can only get here if *str == '}' */
1655	    enh_err_check(str);
1656
1657	if (!*++str)
1658	    break; /* end of string */
1659
1660	/* else carry on and process the rest of the string */
1661    }
1662
1663    PDF_restore(myPDF);
1664
1665    /* We can do text justification by running the entire top level string */
1666    /* through 2 times, with the ENHpdf_sizeonly flag set the first time.   */
1667    /* After seeing where the final position is, we then offset the start  */
1668    /* point accordingly and run it again.                                 */
1669    if (PDF_TextJust == RIGHT || PDF_TextJust == CENTRE) {
1670	int justification = PDF_TextJust;
1671	int x_offset = PDF_xLast - x;
1672	int y_offset = 0;
1673
1674	if (PDF_TextAngle != 0)
1675	    y_offset = PDF_yLast - y;
1676	PDF_TextJust = LEFT;
1677	ENHpdf_sizeonly = FALSE;
1678
1679	if (justification == RIGHT) {
1680	    ENHPDF_put_text(x - x_offset, y - y_offset, original_string);
1681	} else if (justification == CENTRE) {
1682	    ENHPDF_put_text(x - x_offset/2, y - y_offset/2, original_string);
1683	}
1684	PDF_TextJust = justification;
1685    }
1686
1687}
1688
1689#endif /* TERM_BODY */
1690
1691#ifdef TERM_TABLE
1692TERM_TABLE_START (pdf_driver)
1693    "pdf", "PDF (Portable Document File) file driver",
1694    0 /* xmax */ , 0 /* ymax */ , 0 /* vchar */ , 0 /* hchar */ ,
1695    0 /* vtic */ , 0 /* htic */ ,
1696    PDF_options, PDF_init, PDF_reset, PDF_text, null_scale, PDF_graphics,
1697    PDF_move, PDF_vector, PDF_linetype, PDF_put_text, PDF_text_angle,
1698    PDF_justify_text, PDF_point, do_arrow, PDF_set_font, do_pointsize,
1699    TERM_BINARY|TERM_CAN_DASH|TERM_LINEWIDTH|TERM_FONTSCALE,
1700    0 /* suspend */, 0 /* resume */ , PDF_boxfill, PDF_linewidth
1701#   ifdef USE_MOUSE
1702   , 0, 0, 0, 0, 0 /* no mouse support for pdf */
1703#   endif
1704   , PDF_make_palette,
1705   PDF_previous_palette,
1706   PDF_set_color,
1707   PDF_filled_polygon
1708   , PDF_image
1709   , ENHPDF_OPEN, ENHPDF_FLUSH, do_enh_writec
1710TERM_TABLE_END (pdf_driver)
1711#undef LAST_TERM
1712#define LAST_TERM pdf_driver
1713#endif /* TERM_TABLE */
1714
1715#endif /* TERM_PROTO_ONLY */
1716
1717#ifdef TERM_HELP
1718START_HELP(pdf)
1719"1 pdf",
1720"?commands set terminal pdf",
1721"?set terminal pdf",
1722"?set term pdf",
1723"?terminal pdf",
1724"?term pdf",
1725"?pdf",
1726" [DEPRECATED] This terminal uses the non-free library PDFlib (GmbH Munchen)"
1727" to produce files in Portable Document Format. Unless you have a commercial",
1728" license for PDFlib and need some special feature it provides you would do",
1729" better to use the cairo pdf terminal instead.  Gnuplot can also export PDF",
1730" files from wxt or qt interactive terminal sessions.",
1731"",
1732" Syntax:",
1733"       set terminal pdf {monochrome|color|colour}",
1734"                        {{no}enhanced}",
1735"                        {fname \"<font>\"} {fsize <fontsize>}",
1736"                        {font \"<fontname>{,<fontsize>}\"} {fontscale <scale>}",
1737"                        {linewidth <lw>} {rounded|butt}",
1738"                        {dl <dashlength>}}",
1739"                        {size <XX>{unit},<YY>{unit}}",
1740"",
1741" The default is to use a different color for each line type. Selecting",
1742" `monochome` will use black for all linetypes, Even in in mono mode",
1743" you can still use explicit colors for filled areas or linestyles.",
1744"",
1745" where <font> is the name of the default font to use (default Helvetica)",
1746" and <fontsize> is the font size (in points, default 12).",
1747" For help on which fonts are available or how to install new ones, please",
1748" see the documentation for your local installation of pdflib.",
1749"",
1750" The `enhanced` option enables enhanced text processing features",
1751" (subscripts, superscripts and mixed fonts). See `enhanced`.",
1752"",
1753" The width of all lines in the plot can be increased by the factor <n>",
1754" specified in `linewidth`. Similarly `dashlength` is a multiplier for the",
1755" default dash spacing.",
1756"",
1757" `rounded` sets line caps and line joins to be rounded; `butt` is the",
1758" default, butt caps and mitered joins.",
1759"",
1760" The default size for PDF output is 5 inches by 3 inches. The `size` option",
1761" changes this to whatever the user requests. By default the X and Y sizes",
1762" are taken to be in inches, but other units are possible (currently only cm).",
1763""
1764END_HELP(pdf)
1765#endif
1766