[BACK]Return to pdf.trm CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gnuplot / term

Annotation of OpenXM_contrib/gnuplot/term/pdf.trm, Revision 1.1.1.1

1.1       ohara       1: /*Hello, Emacs, this is -*-C-*- ! */
                      2: /*------------------------------
                      3:        GNUPLOT - pdf.trm
                      4:
                      5:        This file is included by ../term.c.
                      6:
                      7:        This driver uses PDFlib from www.pdflib.com
                      8:
                      9:        Author:
                     10:
                     11:                Hans-Bernhard Br"oker
                     12:                broeker@physik.rwth-aachen.de
                     13:
                     14:        Licence: see the gnuplot copyright (to be merged into here...)
                     15:
                     16:        Options: can #define PDF_DONT_COMPRESS to avoid PDF output
                     17:        generated being compressed (by the 'deflate' algorithm as used
                     18:        in 'zip' or 'gzip'). That helps in debugging.
                     19:
                     20: ------------------------------*/
                     21:
                     22: /* CODEME: Add patterned lines (?). Implement the PM3D stuff.  */
                     23:
                     24: #include "driver.h"
                     25:
                     26: #ifdef TERM_REGISTER
                     27: register_term (pdf)
                     28: #endif
                     29:
                     30: #ifdef TERM_PROTO
                     31: TERM_PUBLIC void PDF_options __PROTO ((void));
                     32: TERM_PUBLIC void PDF_init __PROTO ((void));
                     33: TERM_PUBLIC void PDF_graphics __PROTO ((void));
                     34: TERM_PUBLIC void PDF_text __PROTO ((void));
                     35: TERM_PUBLIC void PDF_linetype __PROTO ((int linetype));
                     36: TERM_PUBLIC void PDF_move __PROTO ((unsigned int x, unsigned int y));
                     37: TERM_PUBLIC void PDF_vector __PROTO ((unsigned int x, unsigned int y));
                     38: TERM_PUBLIC void PDF_put_text __PROTO ((unsigned int x, unsigned int y, char *str));
                     39: TERM_PUBLIC void PDF_reset __PROTO ((void));
                     40: TERM_PUBLIC int PDF_justify_text __PROTO ((enum JUSTIFY mode));
                     41: TERM_PUBLIC int PDF_text_angle __PROTO ((int ang));
                     42: TERM_PUBLIC void PDF_point __PROTO ((unsigned int x, unsigned int y, int pointstyle));
                     43: TERM_PUBLIC int PDF_set_font __PROTO ((char *font));
                     44: TERM_PUBLIC void PDF_boxfill __PROTO((int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height));
                     45: TERM_PUBLIC void PDF_linewidth __PROTO ((double linewidth));
                     46:
                     47: #define PDF_NUM_POINTTYPES 75  /* number of point symbol types not counting the dot */
                     48:
                     49: #define PDF_RESOLUTION  (20)   /* number of terminal pixels per pt */
                     50: #define PDF_XMAX       (5*72*PDF_RESOLUTION) /* 5 inches, 72 pt/inch */
                     51: #define PDF_YMAX       (3*72*PDF_RESOLUTION) /* 3 inches, 72 pt/inch */
                     52:
                     53: #endif /* TERM_PROTO */
                     54:
                     55: #ifndef TERM_PROTO_ONLY
                     56: #ifdef TERM_BODY
                     57:
                     58: #include <pdflib.h>
                     59:
                     60: PDF *myPDF = NULL;
                     61:
                     62: unsigned int PDF_xLast = UINT_MAX;     /* current pen horizontal position*/
                     63: unsigned int PDF_yLast = UINT_MAX;     /* current pen vertical position*/
                     64:
                     65: int PDF_LineType = -3;         /* current line type*/
                     66: double PDF_LineWidth = 1.0;    /* current line width*/
                     67: int PDF_TextAngle = 0;         /* current text orientation*/
                     68: enum JUSTIFY PDF_TextJust = LEFT; /* current text justification*/
                     69:
                     70: char PDF_fontNameDef[MAX_ID_LEN + 1] = "Helvetica"; /* default text font family*/
                     71: double PDF_fontSizeDef = 6;    /* default text size*/
                     72: char PDF_fontNameCur[MAX_ID_LEN + 1] = "Helvetica"; /* current text font family*/
                     73: double PDF_fontSizeCur = 6;    /* current text size*/
                     74:
                     75: TBOOLEAN PDF_pageIsOpen = FALSE; /* already started a page ?? */
                     76: TBOOLEAN PDF_pathIsOpen = FALSE; /* open path flag*/
                     77:
                     78: int PDF_fontAscent = 0;                /* estimated current font ascent*/
                     79: int PDF_fontDescent = 0;       /* estimated current font descent*/
                     80: int PDF_fontLeading = 0;       /* estimated current font leading*/
                     81: int PDF_fontAvWidth = 0;       /* estimated current font char average width*/
                     82:
                     83: static short PDF_Pen_RealID __PROTO ((int));
                     84: static void PDF_PathOpen __PROTO ((void));
                     85: static void PDF_PathClose __PROTO ((void));
                     86: static void PDF_SetFont __PROTO ((void));
                     87:
                     88: /*------------------------ helper functions -------------------*/
                     89:
                     90: static short
                     91: PDF_Pen_RealID (inPenCode)
                     92:     int inPenCode;
                     93: {
                     94:     if (inPenCode >= 13)
                     95:        inPenCode %= 13;        /* normalize pen code*/
                     96:     if (inPenCode < -2)
                     97:        inPenCode = -2;
                     98:
                     99:     return (inPenCode + 2);
                    100: }
                    101:
                    102: /* Functions to ensure that as many move() and vector() calls as
                    103:  * possible get converted into a single long 'path', before closing it
                    104:  * with a stroke or similar command. */
                    105: static void
                    106: PDF_PathOpen ()
                    107: {
                    108:     PDF_pathIsOpen = TRUE;
                    109: }
                    110:
                    111: static void
                    112: PDF_PathClose ()
                    113: {
                    114:     if (PDF_pathIsOpen) {
                    115:        PDF_stroke(myPDF);
                    116:
                    117:        PDF_pathIsOpen = FALSE;
                    118:     }
                    119: }
                    120:
                    121: /* Helper function to deal with switching over to a newly selected
                    122:  * font.  For now, this does not try to embed fonts into the PDF
                    123:  * file. This relies on the user restricting herself to the 14
                    124:  * 'classical' fonts built into every valid PDF reader application */
                    125: static void
                    126: PDF_SetFont ()
                    127: {
                    128:     int font_handle = PDF_findfont(myPDF, PDF_fontNameCur, "host", 0);
                    129:
                    130:     PDF_setfont(myPDF, font_handle, PDF_fontSizeCur * PDF_RESOLUTION);
                    131:
                    132:     /* Ask PDFlib for the actual numbers */
                    133:     PDF_fontAscent = (int) (PDF_RESOLUTION * PDF_fontSizeCur * PDF_get_value(myPDF, "ascender", 0));
                    134:     PDF_fontDescent = (int) (- PDF_RESOLUTION * PDF_fontSizeCur * PDF_get_value(myPDF, "descender", 0));
                    135:     PDF_fontLeading = (int) (PDF_RESOLUTION * PDF_fontSizeCur * 0.25);
                    136:
                    137:     /* Assume this particular string is a somewhat reasonable typical
                    138:      * output, for getting at the average character width */
                    139:     PDF_fontAvWidth = (int)
                    140:        (PDF_RESOLUTION * PDF_stringwidth(myPDF, "01234567890123456789",
                    141:                                          font_handle, PDF_fontSizeCur)
                    142:         / 20.0);
                    143: }
                    144:
                    145: /*------------------- the terminal entry functions --------------------*/
                    146:
                    147:
                    148: TERM_PUBLIC void
                    149: PDF_options ()
                    150: {
                    151:     struct value a;
                    152:
                    153:     if (!END_OF_COMMAND) {     /* get default font family name*/
                    154:        if (almost_equals (c_token, "fn$ame"))  {
                    155:            c_token++;
                    156:
                    157:            if (!END_OF_COMMAND && isstring (c_token)) {
                    158:                quote_str (PDF_fontNameDef, c_token, MAX_ID_LEN);
                    159:                c_token++;
                    160:            } else
                    161:                int_error("fname: expecting font name", c_token);
                    162:        }
                    163:     }
                    164:
                    165:     if (!END_OF_COMMAND) {     /* get default font size*/
                    166:        if (almost_equals (c_token, "fs$ize")) {
                    167:            c_token++;
                    168:
                    169:            if (END_OF_COMMAND)
                    170:                int_error("fsize: expecting font size", c_token);
                    171:            PDF_fontSizeDef = real (const_express (&a));
                    172:        }
                    173:     }
                    174:
                    175:     if (!END_OF_COMMAND)
                    176:         int_error("unexpected text at end of command", c_token);
                    177:
                    178:     /* Save options back into options string in normalized format */
                    179:     sprintf(term_options, "fname '%s'  fsize %g",
                    180:            PDF_fontNameDef, PDF_fontSizeDef);
                    181: }
                    182:
                    183:
                    184: TERM_PUBLIC void
                    185: PDF_init ()
                    186: {
                    187:     static TBOOLEAN PDFlib_booted = FALSE;
                    188:
                    189:     if (!PDFlib_booted) {
                    190:        PDF_boot();
                    191:        PDFlib_booted = TRUE;
                    192:     }
                    193:
                    194:     if (!myPDF)
                    195:        myPDF = PDF_new();
                    196:
                    197:     /*open new PDF file */
                    198:     if (PDF_open_fp(myPDF, gpoutfile) == -1)
                    199:        int_error("Error:cannot open PDF file .\n", NO_CARET);
                    200:
                    201: #ifdef PDF_DONT_COMPRESS
                    202:     /* for easier debugging of the output, turn off PDF stream
                    203:      * compression */
                    204:     PDF_set_value(myPDF, "compress", 0);
                    205: #endif
                    206:
                    207:     PDF_set_info(myPDF,"Creator","gnuplot-3.8e");
                    208:     PDF_set_info(myPDF,"Author","Hans-Bernhard Broeker"); /* FIXME: put in username? */
                    209:     PDF_set_info(myPDF,"Title","gnuplot diagram"); /* FIXME: use 'set title', if any ? */
                    210:
                    211:     PDF_LineType = -3;
                    212:
                    213:     /* set current font to default */
                    214:     strcpy(PDF_fontNameCur, PDF_fontNameDef);
                    215:     PDF_fontSizeCur = PDF_fontSizeDef;
                    216:
                    217:     /* Have to start the first page now, in order to know the actual
                    218:      * size of the selected font */
                    219:     PDF_graphics();
                    220:
                    221:     /* set h_char, v_char*/
                    222:     term->h_char = PDF_fontAvWidth;
                    223:     term->v_char = (PDF_fontAscent + PDF_fontDescent + PDF_fontLeading);
                    224:
                    225:     /* set h_tic, v_tic*/
                    226:     term->h_tic = term->v_tic = 3 * PDF_RESOLUTION;
                    227:
                    228:     /* initialize terminal's pointsize from "set pointsize" value */
                    229:     term_pointsize = pointsize;
                    230: }
                    231:
                    232:
                    233: TERM_PUBLIC void
                    234: PDF_graphics ()
                    235: {
                    236:     if (PDF_pageIsOpen)
                    237:        return;                 /* already open --> nothing to do */
                    238:
                    239:     PDF_pathIsOpen = FALSE;
                    240:     PDF_xLast = PDF_yLast = UINT_MAX;
                    241:
                    242:     /* set xmax, ymax*/
                    243:     term->xmax = PDF_XMAX * xsize;
                    244:     term->ymax = PDF_YMAX * ysize;
                    245:
                    246:     PDF_begin_page(myPDF, (double)term->xmax / PDF_RESOLUTION,
                    247:                   (double)term->ymax / PDF_RESOLUTION);
                    248:     PDF_scale(myPDF, 1.0/PDF_RESOLUTION, 1.0/PDF_RESOLUTION);
                    249:     if (title.text && title.text[0])
                    250:        /* a title has been set --> use it as the bookmark name, too */
                    251:        PDF_add_bookmark(myPDF, title.text, 0, 1);
                    252:     PDF_pageIsOpen = TRUE;
                    253:
                    254:     PDF_SetFont();
                    255: }
                    256:
                    257:
                    258: TERM_PUBLIC void
                    259: PDF_text ()
                    260: {
                    261:     PDF_PathClose();
                    262:     PDF_end_page(myPDF);
                    263:     PDF_pageIsOpen = FALSE;
                    264: }
                    265:
                    266:
                    267: TERM_PUBLIC void
                    268: PDF_reset ()
                    269: {
                    270:     assert(PDF_pageIsOpen == FALSE);
                    271:     PDF_close(myPDF);
                    272:     PDF_delete(myPDF);
                    273:     myPDF = NULL;
                    274: }
                    275:
                    276:
                    277: TERM_PUBLIC void
                    278: PDF_linetype (int linetype)
                    279: {
                    280:     if (linetype != PDF_LineType) {
                    281:        int real_linetype = PDF_Pen_RealID(linetype);
                    282:        struct rgb *this_color = web_color_rgbs + 1 + real_linetype;
                    283:
                    284:        PDF_PathClose ();
                    285:        PDF_LineType = linetype;
                    286:
                    287:        PDF_setrgbcolor(myPDF, this_color->r / 255.0,
                    288:                        this_color->g / 255.0, this_color->b / 255.0);
                    289:     }
                    290: }
                    291:
                    292:
                    293: TERM_PUBLIC void
                    294: PDF_linewidth (double linewidth)
                    295: {
                    296:     PDF_PathClose();
                    297:     PDF_LineWidth = PDF_RESOLUTION * linewidth / 4.0;
                    298:     PDF_setlinewidth(myPDF, PDF_LineWidth);
                    299: }
                    300:
                    301:
                    302: TERM_PUBLIC void
                    303: PDF_move (unsigned int x, unsigned int y)
                    304: {
                    305:     if (PDF_pathIsOpen && x == PDF_xLast && y == PDF_yLast)
                    306:        return;
                    307:
                    308:     PDF_PathOpen ();
                    309:     PDF_moveto(myPDF, x, y);
                    310:
                    311:     PDF_xLast = x;
                    312:     PDF_yLast = y;
                    313: }
                    314:
                    315:
                    316: TERM_PUBLIC void
                    317: PDF_vector (unsigned int x, unsigned int y)
                    318: {
                    319:     if (PDF_pathIsOpen && x == PDF_xLast && y == PDF_yLast)
                    320:        return;
                    321:
                    322:     PDF_PathOpen ();
                    323:     PDF_lineto(myPDF, x, y);
                    324:
                    325:     PDF_xLast = x;
                    326:     PDF_yLast = y;
                    327: }
                    328:
                    329: /* Helper function. Many symbols have an additional dot in their
                    330:  * center, so isolate its drawing into a separate function. */
                    331: static GP_INLINE void
                    332: PDF_dot (unsigned int x, unsigned int y)
                    333: {
                    334:     /* Imitate PS's way of creating a small dot by a zero-length line
                    335:      * segment with rounded endpoints */
                    336:     PDF_setlinecap(myPDF, 1); /* rounded ends */
                    337:     PDF_moveto(myPDF, x, y);
                    338:     PDF_lineto(myPDF, x, y);
                    339:     PDF_stroke(myPDF);
                    340: }
                    341:
                    342:
                    343: TERM_PUBLIC void
                    344: PDF_point (unsigned int x, unsigned int y, int number)
                    345: {
                    346:     PDF_PathClose ();
                    347:     PDF_save(myPDF);
                    348:
                    349:     if (number < 0) {
                    350:        /* Like the PostScript driver, treat all negative numbers as
                    351:          * 'with dots'. */
                    352:        PDF_dot(x, y);
                    353:     } else {
                    354:        /* Change coordinate system so the point symbols themselves
                    355:         * can be drawn without depending on position or size (-->
                    356:         * better compression and less coding for gnuplot) */
                    357:        /* NB: I use the do_pointsize() default implementation, which
                    358:         * just stores the last set pointsize into `term_pointsize',
                    359:         * to avoid introducing another static driver-local variable
                    360:         * */
                    361:        PDF_translate(myPDF, x, y);
                    362:        PDF_scale(myPDF, term->h_tic / 2.0 * term_pointsize,
                    363:                  term->v_tic / 2.0 * term_pointsize);
                    364:        /* Correct linewidth to counter the scaling effect --- assume
                    365:         * h_tic is usable, to avoid having to average h_ and v_tic */
                    366:        PDF_setlinewidth(myPDF,
                    367:                         PDF_LineWidth / (term->h_tic / 2.0 * term_pointsize));
                    368:        switch (number %= PDF_NUM_POINTTYPES) {
                    369:        case 0:                 /* Plus */
                    370:            PDF_moveto(myPDF, -1, 0);
                    371:            PDF_lineto(myPDF, 1, 0);
                    372:            PDF_moveto(myPDF, 0, -1);
                    373:            PDF_lineto(myPDF, 0, 1);
                    374:            PDF_stroke(myPDF);
                    375:            break;
                    376:        case 2:                 /* Star */
                    377:            PDF_moveto(myPDF, -1, 0);
                    378:            PDF_lineto(myPDF, 1, 0);
                    379:            PDF_moveto(myPDF, 0, -1);
                    380:            PDF_lineto(myPDF, 0, 1);
                    381:            /* FALLTHROUGH */
                    382:        case 1:                 /* Cross */
                    383:            PDF_moveto(myPDF, -1, -1);
                    384:            PDF_lineto(myPDF, 1, 1);
                    385:            PDF_moveto(myPDF, 1, -1);
                    386:            PDF_lineto(myPDF, -1, 1);
                    387:            PDF_stroke(myPDF);
                    388:            break;
                    389:
                    390: /* For each x = 0..5, 4 shapes are defined:
                    391:  * 3 + 2*x --> hollow symbol with a dot at its center
                    392:  * 4 + 2*x --> solid symbol filled in linetype's color
                    393:  * 63 + x  --> hollow symbol without the center dot
                    394:  * 69 + x  --> symbol filled with white --> opaque symbol */
                    395:
                    396:        case 63+0:              /* BoxEmpty */
                    397:        case 3+2*0:             /* Box */
                    398:            PDF_moveto(myPDF, -1, -1);
                    399:            PDF_lineto(myPDF, 1, -1);
                    400:            PDF_lineto(myPDF, 1, 1);
                    401:            PDF_lineto(myPDF, -1, 1);
                    402:            PDF_closepath_stroke(myPDF);
                    403:            if (number == 3) PDF_dot(0,0);
                    404:            break;
                    405:        case 69+0:              /* BoxWhitefilled */
                    406:            PDF_setgray_fill(myPDF, 1);
                    407:            /* FALLTHROUGH */
                    408:        case 4+2*0:             /* BoxFilled */
                    409:            PDF_moveto(myPDF, -1, -1);
                    410:            PDF_lineto(myPDF, 1, -1);
                    411:            PDF_lineto(myPDF, 1, 1);
                    412:            PDF_lineto(myPDF, -1, 1);
                    413:            PDF_closepath_fill_stroke(myPDF);
                    414:            break;
                    415:
                    416:        case 63+1:              /* CircleEmpty */
                    417:        case 3+2*1:             /* Circle */
                    418:            PDF_circle(myPDF, 0, 0, 1);
                    419:            PDF_stroke(myPDF);
                    420:            if (number == 5) PDF_dot(0,0);
                    421:            break;
                    422:        case 69+1:              /* CircleWhitefilled */
                    423:            PDF_setgray_fill(myPDF, 1);
                    424:            /* FALLTHROUGH */
                    425:        case 4+2*1:             /* CircleFilled */
                    426:            PDF_circle(myPDF, 0, 0, 1);
                    427:            PDF_fill_stroke(myPDF);
                    428:            break;
                    429:
                    430:        case 63+2:              /* TriangleUpEmpty */
                    431:        case 3+2*2:             /* TriangleUp */
                    432:            PDF_moveto(myPDF, 0, 1.12);
                    433:            PDF_lineto(myPDF, -1, -0.5);
                    434:            PDF_lineto(myPDF, 1, -0.5);
                    435:            PDF_closepath_stroke(myPDF);
                    436:            if (number == 7) PDF_dot(0,0);
                    437:            break;
                    438:        case 69+2:              /* TriangleUpWhitefilled */
                    439:            PDF_setgray_fill(myPDF, 1);
                    440:            /* FALLTHROUGH */
                    441:        case 4+2*2:                     /* TriangleUpFilled */
                    442:            PDF_moveto(myPDF, 0, 1.12);
                    443:            PDF_lineto(myPDF, -1, -0.5);
                    444:            PDF_lineto(myPDF, 1, -0.5);
                    445:            PDF_closepath_fill_stroke(myPDF);
                    446:            break;
                    447:
                    448:        case 63+3:              /* TriangleDownEmpty */
                    449:        case 3+2*3:             /* TriangleDown */
                    450:            PDF_moveto(myPDF, 0, -1.12);
                    451:            PDF_lineto(myPDF, -1, 0.5);
                    452:            PDF_lineto(myPDF, 1, 0.5);
                    453:            PDF_closepath_stroke(myPDF);
                    454:            if (number == 9) PDF_dot(0,0);
                    455:            break;
                    456:        case 69+3:              /* TriangleDownWhitefilled */
                    457:            PDF_setgray_fill(myPDF, 1);
                    458:            /* FALLTHROUGH */
                    459:        case 4+2*3:             /* TriangleDownFilled */
                    460:            PDF_moveto(myPDF, 0, -1.12);
                    461:            PDF_lineto(myPDF, -1, 0.5);
                    462:            PDF_lineto(myPDF, 1, 0.5);
                    463:            PDF_closepath_fill_stroke(myPDF);
                    464:            break;
                    465:
                    466:        case 63+4:              /* DiamondEmpty */
                    467:        case 3+2*4:             /* Diamond */
                    468:            PDF_moveto(myPDF, 0, -1);
                    469:            PDF_lineto(myPDF, 1, 0);
                    470:            PDF_lineto(myPDF, 0, 1);
                    471:            PDF_lineto(myPDF, -1, 0);
                    472:            PDF_closepath_stroke(myPDF);
                    473:            if (number == 11) PDF_dot(0,0);
                    474:            break;
                    475:        case 69+4:              /* DiamondWhitefilled */
                    476:            PDF_setgray_fill(myPDF, 1);
                    477:            /* FALLTHROUGH */
                    478:        case 4+2*4:             /* DiamondFilled */
                    479:            PDF_moveto(myPDF, 0, -1);
                    480:            PDF_lineto(myPDF, 1, 0);
                    481:            PDF_lineto(myPDF, 0, 1);
                    482:            PDF_lineto(myPDF, -1, 0);
                    483:            PDF_closepath_fill_stroke(myPDF);
                    484:            break;
                    485:
                    486:        case 63+5:              /* PentagonEmpty */
                    487:        case 3+2*5:             /* Pentagon */
                    488:            PDF_moveto(myPDF, 0, 1);
                    489:            PDF_lineto(myPDF, -0.95, 0.31);
                    490:            PDF_lineto(myPDF, -0.58, -0.81);
                    491:            PDF_lineto(myPDF, +0.58, -0.81);
                    492:            PDF_lineto(myPDF, +0.95, 0.31);
                    493:            PDF_closepath_stroke(myPDF);
                    494:            if (number == 13) PDF_dot(0,0);
                    495:            break;
                    496:        case 69+5:              /* PentagonWhitefilled */
                    497:            PDF_setgray_fill(myPDF, 1);
                    498:            /* FALLTHROUGH */
                    499:        case 4+2*5:             /* PentagonFilled */
                    500:            PDF_moveto(myPDF, 0, 1);
                    501:            PDF_lineto(myPDF, -0.95, 0.31);
                    502:            PDF_lineto(myPDF, -0.58, -0.81);
                    503:            PDF_lineto(myPDF, +0.58, -0.81);
                    504:            PDF_lineto(myPDF, +0.95, 0.31);
                    505:            PDF_closepath_fill_stroke(myPDF);
                    506:            break;
                    507:
                    508: /* 15 + (0..15): circles with varying parts of'em filled. The added
                    509:  * number is a bit-pattern of the 4 quadrants: 1 signals a quadrant
                    510:  * filled */
                    511:        case 15+0:
                    512:            PDF_moveto(myPDF, 0, 0);
                    513:            PDF_lineto(myPDF, 0, 1);
                    514:            PDF_arc(myPDF, 0, 0, 1, 90, 360+90);
                    515:            PDF_closepath_stroke(myPDF);
                    516:            break;
                    517:
                    518: /* Generalize common code into a macro... */
                    519: #define CIRCLE_SINGLE_PIESLICE(x, y, angle1, angle2)           \
                    520:            PDF_moveto(myPDF, 0, 0);                            \
                    521:            PDF_lineto(myPDF, (x), (y));                        \
                    522:            PDF_arc(myPDF, 0, 0, 1, (angle1), (angle2));        \
                    523:            PDF_lineto(myPDF, 0, 0);                            \
                    524:            PDF_closepath(myPDF);                               \
                    525:            PDF_fill_stroke(myPDF);                             \
                    526:            PDF_arc(myPDF, 0, 0, 1, (angle2), (angle1) + 360);  \
                    527:            PDF_stroke(myPDF);                                  \
                    528:            break;
                    529:
                    530: #define CIRCLE_SINGLE_QUADRANT(x, y, angle)                    \
                    531:            CIRCLE_SINGLE_PIESLICE(x, y, angle, angle+90);
                    532:        case 15+1:
                    533:            CIRCLE_SINGLE_QUADRANT(1, 0, 0);
                    534:        case 15+2:
                    535:            CIRCLE_SINGLE_QUADRANT(0, 1, 90);
                    536:        case 15+4:
                    537:            CIRCLE_SINGLE_QUADRANT(-1, 0, 180);
                    538:        case 15+8:
                    539:            CIRCLE_SINGLE_QUADRANT(0, -1, 270);
                    540: #undef CIRCLE_SINGLE_QUADRANT
                    541:
                    542: #define CIRCLE_TWO_NEIGHBOR_QUADRANTS(x, y, angle)             \
                    543:            CIRCLE_SINGLE_PIESLICE(x, y, angle, angle+180)
                    544:        case 15+3:
                    545:            CIRCLE_TWO_NEIGHBOR_QUADRANTS(1, 0, 0);
                    546:        case 15+6:
                    547:            CIRCLE_TWO_NEIGHBOR_QUADRANTS(0, 1, 90);
                    548:        case 15+12:
                    549:            CIRCLE_TWO_NEIGHBOR_QUADRANTS(-1, 0, 180);
                    550:        case 15+9:
                    551:            CIRCLE_TWO_NEIGHBOR_QUADRANTS(0, -1, 270);
                    552: #undef CIRCLE_TWO_NEIGHBOR_QUADRANTS
                    553:
                    554: #define CIRCLE_TWO_OPPOSING_QUADRANTS(x, y, angle)             \
                    555:            PDF_moveto(myPDF, 0, 0);                            \
                    556:            PDF_lineto(myPDF, x, y);                            \
                    557:            PDF_arc(myPDF, 0, 0, 1, angle, angle + 90);         \
                    558:            PDF_lineto(myPDF, 0, 0);                            \
                    559:            PDF_fill_stroke(myPDF);                             \
                    560:            PDF_moveto(myPDF, 0, 0);                            \
                    561:            PDF_lineto(myPDF, -x, -y);                          \
                    562:            PDF_arc(myPDF, 0, 0, 1, angle + 180, angle + 270);  \
                    563:            PDF_lineto(myPDF, 0, 0);                            \
                    564:            PDF_fill_stroke(myPDF);                             \
                    565:            PDF_arc(myPDF, 0, 0, 1, angle + 90, angle + 360);   \
                    566:            PDF_stroke(myPDF);                                  \
                    567:            break;
                    568:        case 15+5:
                    569:            CIRCLE_TWO_OPPOSING_QUADRANTS(1, 0, 0);
                    570:        case 15+10:
                    571:            CIRCLE_TWO_OPPOSING_QUADRANTS(0, 1, 90);
                    572: #undef CIRCLE_TWO_OPPOSING_QUADRANTS
                    573:
                    574: #define CIRCLE_THREE_QUADRANTS(x, y, angle)                    \
                    575:            CIRCLE_SINGLE_PIESLICE(x, y, angle, angle+270)
                    576:        case 15+7:
                    577:            CIRCLE_THREE_QUADRANTS(1, 0, 0);
                    578:        case 15+14:
                    579:            CIRCLE_THREE_QUADRANTS(0, 1, 90);
                    580:        case 15+13:
                    581:            CIRCLE_THREE_QUADRANTS(-1, 0, 180);
                    582:        case 15+11:
                    583:            CIRCLE_THREE_QUADRANTS(0, -1, 270);
                    584: #undef CIRCLE_THREE_QUADRANTS
                    585: #undef CIRCLE_SINGLE_PIESLICE
                    586:
                    587:        case 15+15:
                    588:            PDF_circle(myPDF, 0, 0, 1);
                    589:            PDF_closepath_fill_stroke(myPDF);
                    590:            break;
                    591:
                    592:
                    593: /*************************************************************************/
                    594: /* 31 + (0..15): squares with different quadrants of them filled in. */
                    595: /*************************************************************************/
                    596: /*************************************************************************/
                    597: /* 47 + (0..15): diamonds with filled quadrants as given by bit pattern  */
                    598: /*   Diamonds are drawn as squares rotated by 45 degrees, so can use
                    599:  * fall-through from diamond to squares, and re-use some macros. */
                    600: /*************************************************************************/
                    601:        case 47+0:
                    602:            PDF_rotate(myPDF, 45);
                    603:            /* FALLTHROUGH */
                    604:        case 31+0:
                    605:            PDF_moveto(myPDF, 0, 0);
                    606:            PDF_lineto(myPDF, 0, 1);
                    607:            PDF_lineto(myPDF, -1, 1);
                    608:            PDF_lineto(myPDF, -1, -1);
                    609:            PDF_lineto(myPDF, 1, -1);
                    610:            PDF_lineto(myPDF, 1, 1);
                    611:            PDF_lineto(myPDF, 0, 1);
                    612:            PDF_stroke(myPDF);
                    613:            break;
                    614:
                    615:        case 47+15:
                    616:            PDF_rotate(myPDF, 45);
                    617:            /* FALLTHROUGH */
                    618:        case 31+15:
                    619:            PDF_moveto(myPDF, -1, 1);
                    620:            PDF_lineto(myPDF, -1, -1);
                    621:            PDF_lineto(myPDF, 1, -1);
                    622:            PDF_lineto(myPDF, 1, 1);
                    623:            PDF_closepath_fill_stroke(myPDF);
                    624:            break;
                    625:
                    626: /* macros defining shapes of the partly filled symbols. Done by
                    627:  * rotating the starting point (x0, y0) by 90 degrees or 45 degrees
                    628:  * (with length adjustment).  The rotations can be done without
                    629:  * trigonometric function calls, since their values are known:
                    630:  * cos(90)=0, sin(90)=1, cos(45)=sin(45)=1/sqrt(2).  A good compiler
                    631:  * should be able to optimize away all the local variables and
                    632:  * loops...  */
                    633:
                    634: #define SQUARE_SINGLE_PIESLICE(x0, y0, quadrants)                      \
                    635:            {                                                           \
                    636:                int quadrant = 0;                                       \
                    637:                int x= x0, y=y0;                                        \
                    638:                PDF_moveto(myPDF, 0, 0);                                \
                    639:                PDF_lineto(myPDF, x, y);                                \
                    640:                /* poor man's rotation by 45 and 90 degrees around the  \
                    641:                 * square's outline. */                                 \
                    642:                while (quadrant++ < quadrants) {                        \
                    643:                    int dummy;                                          \
                    644:                    PDF_lineto(myPDF, x-y, x+y);                        \
                    645:                    dummy = x; x = -y; y = dummy;                       \
                    646:                }                                                       \
                    647:                PDF_lineto(myPDF, x, y);                                \
                    648:                PDF_closepath_fill_stroke(myPDF);                       \
                    649:                PDF_moveto(myPDF, x, y);                                \
                    650:                while (quadrant++ <= 4) {                               \
                    651:                    int dummy;                                          \
                    652:                    PDF_lineto(myPDF, x-y, x+y);                        \
                    653:                    dummy = x; x = -y; y = dummy;                       \
                    654:                }                                                       \
                    655:                PDF_lineto(myPDF, x, y);                                \
                    656:                PDF_stroke(myPDF);                                      \
                    657:            }                                                           \
                    658:            break;
                    659:
                    660: #define SQUARE_TWO_OPPOSING_QUADRANTS(x0, y0, angle)   \
                    661:            {                                           \
                    662:                int x = x0, y = y0, dummy;              \
                    663:                int counter = 0;                        \
                    664:                                                        \
                    665:                while (counter++ < 2) {                 \
                    666:                    PDF_moveto(myPDF, 0, 0);            \
                    667:                    PDF_lineto(myPDF, x, y);            \
                    668:                    PDF_lineto(myPDF, x-y, x+y);        \
                    669:                    dummy = x; x = -y; y = dummy;       \
                    670:                    PDF_lineto(myPDF, x, y);            \
                    671:                    PDF_closepath_fill_stroke(myPDF);   \
                    672:                                                        \
                    673:                    PDF_moveto(myPDF, x, y);            \
                    674:                    PDF_lineto(myPDF, x-y, x+y);        \
                    675:                    dummy = x; x = -y; y = dummy;       \
                    676:                    PDF_lineto(myPDF, x, y);            \
                    677:                    PDF_stroke(myPDF);                  \
                    678:                }                                       \
                    679:                break;                                  \
                    680:            }
                    681:
                    682: /* Macros for diamonds just prepend the rotation and then call those
                    683:  * for squares: */
                    684: #define DIAMOND_SINGLE_PIESLICE(x, y, quadrants)       \
                    685:            PDF_rotate(myPDF, 45);                      \
                    686:            SQUARE_SINGLE_PIESLICE(x, y, quadrants);
                    687: #define DIAMOND_TWO_OPPOSING_QUADRANTS(x, y, angle)    \
                    688:            PDF_rotate(myPDF, 45);                      \
                    689:            SQUARE_TWO_OPPOSING_QUADRANTS(x, y, angle);
                    690:
                    691: /* ... and now all the individual cases. The 'angle' arguments' are
                    692:  * purely for the sake of easing cut'n'paste with the circle case */
                    693: #define SQUARE_SINGLE_QUADRANT(x, y, angle)                    \
                    694:            SQUARE_SINGLE_PIESLICE(x, y, 1);
                    695:        case 31+1:
                    696:            SQUARE_SINGLE_QUADRANT(1, 0, 0);
                    697:        case 31+2:
                    698:            SQUARE_SINGLE_QUADRANT(0, 1, 90);
                    699:        case 31+4:
                    700:            SQUARE_SINGLE_QUADRANT(-1, 0, 180);
                    701:        case 31+8:
                    702:            SQUARE_SINGLE_QUADRANT(0, -1, 270);
                    703: #undef SQUARE_SINGLE_QUADRANT
                    704:
                    705: #define SQUARE_TWO_NEIGHBOR_QUADRANTS(x, y, angle)             \
                    706:            SQUARE_SINGLE_PIESLICE(x, y, 2)
                    707:        case 31+3:
                    708:            SQUARE_TWO_NEIGHBOR_QUADRANTS(1, 0, 0);
                    709:        case 31+6:
                    710:            SQUARE_TWO_NEIGHBOR_QUADRANTS(0, 1, 90);
                    711:        case 31+12:
                    712:            SQUARE_TWO_NEIGHBOR_QUADRANTS(-1, 0, 180);
                    713:        case 31+9:
                    714:            SQUARE_TWO_NEIGHBOR_QUADRANTS(0, -1, 270);
                    715: #undef SQUARE_TWO_NEIGHBOR_QUADRANTS
                    716:
                    717:        case 31+5:
                    718:            SQUARE_TWO_OPPOSING_QUADRANTS(1, 0, 0);
                    719:        case 31+10:
                    720:            SQUARE_TWO_OPPOSING_QUADRANTS(0, 1, 90);
                    721:
                    722: #define SQUARE_THREE_QUADRANTS(x, y, angle)                    \
                    723:            SQUARE_SINGLE_PIESLICE(x, y, 3)
                    724:        case 31+7:
                    725:            SQUARE_THREE_QUADRANTS(1, 0, 0);
                    726:        case 31+14:
                    727:            SQUARE_THREE_QUADRANTS(0, 1, 90);
                    728:        case 31+13:
                    729:            SQUARE_THREE_QUADRANTS(-1, 0, 180);
                    730:        case 31+11:
                    731:            SQUARE_THREE_QUADRANTS(0, -1, 270);
                    732: #undef SQUARE_THREE_QUADRANTS
                    733:
                    734: #define DIAMOND_SINGLE_QUADRANT(x, y, angle)                   \
                    735:            DIAMOND_SINGLE_PIESLICE(x, y, 1)
                    736:        case 47+1:
                    737:            DIAMOND_SINGLE_QUADRANT(1, 0, 0);
                    738:        case 47+2:
                    739:            DIAMOND_SINGLE_QUADRANT(0, 1, 90);
                    740:        case 47+4:
                    741:            DIAMOND_SINGLE_QUADRANT(-1, 0, 180);
                    742:        case 47+8:
                    743:            DIAMOND_SINGLE_QUADRANT(0, -1, 270);
                    744: #undef DIAMOND_SINGLE_QUADRANT
                    745:
                    746: #define DIAMOND_TWO_NEIGHBOR_QUADRANTS(x, y, angle)            \
                    747:            DIAMOND_SINGLE_PIESLICE(x, y, 2)
                    748:        case 47+3:
                    749:            DIAMOND_TWO_NEIGHBOR_QUADRANTS(1, 0, 0);
                    750:        case 47+6:
                    751:            DIAMOND_TWO_NEIGHBOR_QUADRANTS(0, 1, 90);
                    752:        case 47+12:
                    753:            DIAMOND_TWO_NEIGHBOR_QUADRANTS(-1, 0, 180);
                    754:        case 47+9:
                    755:            DIAMOND_TWO_NEIGHBOR_QUADRANTS(0, -1, 270);
                    756: #undef DIAMOND_TWO_NEIGHBOR_QUADRANTS
                    757:
                    758:
                    759:        case 47+5:
                    760:            DIAMOND_TWO_OPPOSING_QUADRANTS(1, 0, 0);
                    761:        case 47+10:
                    762:            DIAMOND_TWO_OPPOSING_QUADRANTS(0, 1, 90);
                    763: #undef DIAMOND_TWO_OPPOSING_QUADRANTS
                    764: #undef SQUARE_TWO_OPPOSING_QUADRANTS
                    765:
                    766: #define DIAMOND_THREE_QUADRANTS(x, y, angle)                   \
                    767:            DIAMOND_SINGLE_PIESLICE(x, y, 3)
                    768:        case 47+7:
                    769:            DIAMOND_THREE_QUADRANTS(1, 0, 0);
                    770:        case 47+14:
                    771:            DIAMOND_THREE_QUADRANTS(0, 1, 90);
                    772:        case 47+13:
                    773:            DIAMOND_THREE_QUADRANTS(-1, 0, 180);
                    774:        case 47+11:
                    775:            DIAMOND_THREE_QUADRANTS(0, -1, 270);
                    776: #undef DIAMOND_THREE_QUADRANTS
                    777: #undef DIAMOND_SINGLE_PIESLICE
                    778: #undef SQUARE_SINGLE_PIESLICE
                    779:
                    780:        default:
                    781:            {
                    782:            char temp[64];
                    783:            sprintf(temp, "PDF: unknown point type number %d", number);
                    784:            int_warn(temp,NO_CARET);
                    785:            }
                    786:        }
                    787:     }
                    788:
                    789:     PDF_restore(myPDF);
                    790:     PDF_xLast = x;
                    791:     PDF_yLast = y;
                    792: }
                    793:
                    794:
                    795: TERM_PUBLIC int
                    796: PDF_justify_text (enum JUSTIFY mode)
                    797: {
                    798:     PDF_TextJust = mode;
                    799:     return (TRUE);
                    800: }
                    801:
                    802:
                    803: TERM_PUBLIC int
                    804: PDF_text_angle (int ang)
                    805: {
                    806:     if (ang == 0 || ang == 1) {
                    807:        /* FIXME: need to do this in a different way? */
                    808:        PDF_TextAngle = ang;
                    809:        return (TRUE);
                    810:     }
                    811:
                    812:     return (FALSE);
                    813: }
                    814:
                    815:
                    816: TERM_PUBLIC void
                    817: PDF_put_text (unsigned int x, unsigned int y, char *str)
                    818: {
                    819:     char *alignment = NULL;
                    820:     double h = x, v = y;
                    821:
                    822:     PDF_PathClose ();
                    823:
                    824:     /* horizontal justification*/
                    825:     switch (PDF_TextJust) {
                    826:     case LEFT:
                    827:        alignment = "left";
                    828:        break;
                    829:     case CENTRE:
                    830:        alignment = "center";
                    831:        break;
                    832:     case RIGHT:
                    833:        alignment = "right";
                    834:        break;
                    835:     }
                    836:
                    837:     /* vertical justification*/
                    838:     switch (PDF_TextAngle) {
                    839:     case 1:
                    840:        h += (PDF_fontAscent - PDF_fontDescent) / 2;
                    841:        break;          /* vertical text*/
                    842:     default:
                    843:        v -= (PDF_fontAscent - PDF_fontDescent) / 2;
                    844:        break;          /* horizontal text*/
                    845:     }
                    846:
                    847:     if (PDF_TextAngle) {
                    848:        PDF_save(myPDF);
                    849:        PDF_rotate(myPDF, 90);
                    850:        PDF_show_boxed(myPDF, str, v , -h, 0, 0, alignment, NULL);
                    851:        PDF_restore(myPDF);
                    852:     } else {
                    853:        PDF_show_boxed(myPDF, str, h , v, 0, 0, alignment, NULL);
                    854:     }
                    855:
                    856: }
                    857:
                    858:
                    859: TERM_PUBLIC int
                    860: PDF_set_font (char *font)
                    861: {
                    862:     if (strlen (font) > 0) {   /* if available, parse the font specification ("fontname,fontsize")*/
                    863:        short index;
                    864:        char *token,
                    865:            seps[] = ",", *buffer = (char *) malloc (strlen (font) + 1);
                    866:
                    867:        if (buffer == NULL)
                    868:            return (FALSE);
                    869:        strcpy (buffer, font);
                    870:
                    871:        for (token = strtok (buffer, seps), index = 1;
                    872:             token != NULL; token = strtok (NULL, seps), index++
                    873:            ) {
                    874:            switch (index) {
                    875:            case 1:
                    876:                strcpy (PDF_fontNameCur, token);
                    877:                break;  /* font name*/
                    878:            case 2:
                    879:                PDF_fontSizeCur = atoi (token);
                    880:                break;  /* font size*/
                    881:            default:
                    882:                break;
                    883:            }
                    884:        }
                    885:
                    886:        free (buffer);
                    887:     } else {                   /* otherwise simply reset the default font*/
                    888:        strcpy (PDF_fontNameCur, PDF_fontNameDef);
                    889:        PDF_fontSizeCur = PDF_fontSizeDef;
                    890:     }
                    891:
                    892:
                    893:     PDF_PathClose();
                    894:     PDF_SetFont();
                    895:     return (TRUE);
                    896: }
                    897:
                    898: TERM_PUBLIC void
                    899: PDF_boxfill(int style, unsigned int x1, unsigned int y1,
                    900:            unsigned int width, unsigned int height)
                    901: {
                    902:     (void) style;              /* unused */
                    903:     PDF_PathClose();
                    904:     PDF_save(myPDF);
                    905:     PDF_setgray(myPDF, 1);
                    906:     PDF_moveto(myPDF, x1, y1);
                    907:     PDF_lineto(myPDF, x1+width, y1);
                    908:     PDF_lineto(myPDF, x1+width, y1+height);
                    909:     PDF_lineto(myPDF, x1, y1+height);
                    910:     PDF_fill(myPDF);
                    911:     PDF_restore(myPDF);
                    912: }
                    913:
                    914: #endif /* TERM_BODY */
                    915:
                    916: #ifdef TERM_TABLE
                    917: TERM_TABLE_START (pdf_driver)
                    918:     "pdf", "PDF (Portable Document File) file driver",
                    919:     0 /* xmax */ , 0 /* ymax */ , 0 /* vchar */ , 0 /* hchar */ ,
                    920:     0 /* vtic */ , 0 /* htic */ ,
                    921:     PDF_options, PDF_init, PDF_reset, PDF_text, null_scale, PDF_graphics,
                    922:     PDF_move, PDF_vector, PDF_linetype, PDF_put_text, PDF_text_angle,
                    923:     PDF_justify_text, PDF_point, do_arrow, PDF_set_font, do_pointsize,
                    924:     TERM_BINARY,
                    925:     0 /* suspend */, 0 /* resume */ , PDF_boxfill, PDF_linewidth
                    926: TERM_TABLE_END (pdf_driver)
                    927: #undef LAST_TERM
                    928: #define LAST_TERM pdf_driver
                    929: #endif /* TERM_TABLE */
                    930:
                    931: #endif /* TERM_PROTO_ONLY */
                    932:
                    933: #ifdef TERM_HELP
                    934:     START_HELP (pdf)
                    935:     "1 pdf",
                    936:     "?commands set terminal pdf",
                    937:     "?set terminal pdf",
                    938:     "?set term pdf",
                    939:     "?terminal pdf",
                    940:     "?term pdf",
                    941:     "?pdf",
                    942:     " This terminal produces files in the Adobe Portable Document Format",
                    943:     " (PDF), useable for printing or display with tools like Acrobat Reader",
                    944:     "",
                    945:     " Syntax:",
                    946:     "       set terminal pdf {fname \"<font>\"} {fsize <fontsize>}",
                    947:     "",
                    948:     " where <font> is the name of the default font to use (default Helvetica)",
                    949:     " and <fontsize> is the font size (in points, default 12)"
                    950:     END_HELP (pdf)
                    951: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>