PLplot: pdf.c Source File

PLplot 5.15.0

pdf.c
Go to the documentation of this file.
1 // PLplot driver for PDF based on the haru library http://www.libharu.org.
2 //
3 // Copyright (C) 2006, 2008 Werner Smekal
4 //
5 // This file is part of PLplot.
6 //
7 // PLplot is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU Library General Public License as published
9 // by the Free Software Foundation; either version 2 of the License, or
10 // (at your option) any later version.
11 //
12 // PLplot is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Library General Public License for more details.
16 //
17 // You should have received a copy of the GNU Library General Public License
18 // along with PLplot; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 //
21 //
22
23 // TODO:
24 // - page orientation
25 // - text clipping
26 //
27
28 //--------------------------------------------------------------------------
29 // Header files, defines and local variables
30 //--------------------------------------------------------------------------
31 #include "plDevs.h"
32
33 #ifdef PLD_pdf
34
35 #include <stdarg.h>
36 #include <math.h>
37 #include <setjmp.h>
38 #include <strings.h>
39
40 #include "hpdf.h"
41
42 // PLplot header files
43 //#define DEBUG
44 //#define NEED_PLDEBUG
45 #include "plplotP.h"
46 #include "drivers.h"
47 #include "plunicode-type1.h"
48 #include "plfci-type1.h"
49
50 // Workaround for caseless string comparison
51 #ifndef _WIN32
52 #define stricmp strcasecmp
53 #define strnicmp strncasecmp
54 #endif
55
56 // constants
57
58 // We define a virtual page and scale it down to the
59 // paper size chosen by the user (A4 is default).
60 //
61
62 // Default dimensions of the canvas (in inches) and DPI
63 #define CANVAS_WIDTH ( 50.0 )
64 #define CANVAS_HEIGHT ( 37.5 )
65 #define DEVICE_PIXELS_PER_INCH ( 72 )
66
67 // mm per inch
68 #define MM_PER_INCH ( 25.4 )
69
70 // pixels per mm
71 #define DEVICE_PIXELS_PER_MM ( DEVICE_PIXELS_PER_INCH / MM_PER_INCH )
72
73 // maximum string length for own font handling
74 #define MAX_STRING_LEN 1000
75
76 // container for device specific data
77 typedef struct
78 {
79 HPDF_Doc pdf;
80 HPDF_Page page;
81 HPDF_PageSizes pageSize;
82 FILE *pdfFile;
83 PLFLT scalex, scaley;
84
85 // font variables
86 HPDF_Font m_font;
87 int nlookup, if_symbol_font;
88 const Unicode_to_Type1_table *lookup;
89 HPDF_REAL fontSize;
90 HPDF_REAL fontScale;
91 HPDF_REAL textWidth, textHeight;
92 HPDF_REAL yOffset;
93 HPDF_REAL textRed, textGreen, textBlue;
94 } pdfdev;
95
96 // local variables
97 PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_pdf = "pdf:Portable Document Format PDF:1:pdf:58:pdf\n";
98 static jmp_buf env;
99
100 //--------------------------------------------------------------------------
101 // function declarations
102 //--------------------------------------------------------------------------
103
104 // General
105 //static short desired_offset( short, double );
106 static void poly_line( PLStream *pls, short *xa, short *ya, PLINT npts, short fill );
107
108 // String processing
109 static void process_string( PLStream *, EscText * );
110
111 // PLplot interface functions
112 void plD_dispatch_init_pdf( PLDispatchTable *pdt );
113 void plD_init_pdf( PLStream * );
114 void plD_line_pdf( PLStream *, short, short, short, short );
115 void plD_polyline_pdf( PLStream *, short *, short *, PLINT );
116 void plD_eop_pdf( PLStream * );
117 void plD_bop_pdf( PLStream * );
118 void plD_tidy_pdf( PLStream * );
119 void plD_state_pdf( PLStream *, PLINT );
120 void plD_esc_pdf( PLStream *, PLINT, void * );
121 void error_handler( HPDF_STATUS error_no, HPDF_STATUS detail_no, void *user_data );
122 void PSDrawTextToCanvas( pdfdev* dev, unsigned char* type1_string, short drawText );
123 void PSSetFont( pdfdev* dev, PLUNICODE fci );
124 void PSDrawText( pdfdev* dev, PLUNICODE* ucs4, int ucs4Len, short drawText );
125
126 //--------------------------------------------------------------------------
127 // error_handler( HPDF_STATUS error_no, HPDF_STATUS detail_no,
128 // void *user_data )
129 //
130 // Error handler for haru library.
131 //--------------------------------------------------------------------------
132 #ifdef HPDF_DLL
133 void __stdcall
134 #else
135 void
136 #endif
137 error_handler( HPDF_STATUS error_no, HPDF_STATUS detail_no, void * PL_UNUSED( user_data ) )
138 {
139 // invoke longjmp() when an error has occurred
140 printf( "ERROR: error_no=%04X, detail_no=%d\n", (unsigned int) error_no, (int) detail_no );
141 longjmp( env, 1 );
142 }
143
144
145 //--------------------------------------------------------------------------
146 // plD_dispatch_init_pdf( PLDispatchTable *pdt )
147 //
148 // Initialize device dispatch table.
149 //--------------------------------------------------------------------------
150 void plD_dispatch_init_pdf( PLDispatchTable *pdt )
151 {
152 #ifndef ENABLE_DYNDRIVERS
153 pdt->pl_MenuStr = "Portable Document Format PDF";
154 pdt->pl_DevName = "pdf";
155 #endif
156 pdt->pl_type = plDevType_FileOriented;
157 pdt->pl_seq = 58;
158 pdt->pl_init = (plD_init_fp) plD_init_pdf;
159 pdt->pl_line = (plD_line_fp) plD_line_pdf;
160 pdt->pl_polyline = (plD_polyline_fp) plD_polyline_pdf;
161 pdt->pl_eop = (plD_eop_fp) plD_eop_pdf;
162 pdt->pl_bop = (plD_bop_fp) plD_bop_pdf;
163 pdt->pl_tidy = (plD_tidy_fp) plD_tidy_pdf;
164 pdt->pl_state = (plD_state_fp) plD_state_pdf;
165 pdt->pl_esc = (plD_esc_fp) plD_esc_pdf;
166 }
167
168
169 // driver specific options
170 static PLINT text = 1;
171 static PLINT compress = 1;
172 static PLINT hrshsym = 1;
173 static PLINT color = 1;
174 static char * pageSize = NULL;
175
176 DrvOpt pdf_options[] = {
177 { "text", DRV_INT, &text, "Use own text routines (text=0|1)" },
178 { "color", DRV_INT, &color, "Use color (color=0|1)" },
179 { "compress", DRV_INT, &compress, "Compress pdf output (compress=0|1)" },
180 { "hrshsym", DRV_INT, &hrshsym, "Use Hershey symbol set (hrshsym=0|1)" },
181 { "pagesize", DRV_STR, &pageSize, "Set page size (pagesize=A4|letter|A3|A5)" },
182 { NULL, DRV_INT, NULL, NULL }
183 };
184
185
186 //--------------------------------------------------------------------------
187 // plD_init_pdf( PLStream *pls )
188 //
189 // Initialize device.
190 //--------------------------------------------------------------------------
191 void plD_init_pdf( PLStream *pls )
192 {
193 pdfdev* dev;
194
195 // allocate memory for the device storage
196 dev = (pdfdev *) calloc( 1, sizeof ( pdfdev ) );
197 if ( dev == NULL )
198 plexit( "Insufficient memory\n" );
199 pls->dev = (void *) dev;
200
201 // Check for and set up driver options
202 plParseDrvOpts( pdf_options );
203
204 pls->termin = 0; // not an interactive device
205 if ( color )
206 pls->color = 1; // supports color
207 else
208 pls->color = 0; // monochrome
209 pls->width = 1;
210 pls->bytecnt = 0;
211
212 if ( text )
213 {
214 pls->dev_text = 1; // handles text
215 pls->dev_unicode = 1; // wants text as unicode
216 if ( hrshsym )
217 pls->dev_hrshsym = 1;
218 }
219
220 pls->page = 0;
221 pls->dev_fill0 = 1; // supports hardware solid fills
222 pls->dev_fill1 = 0; // Use PLplot core fallback for pattern fills
223
224 pls->graphx = GRAPHICS_MODE;
225
226 if ( !pls->colorset )
227 pls->color = 1;
228
229 // Set the (virtual) page size. The geometry option is
230 // neglected. Page sizes are set with the pagesize option.
231 plspage( DEVICE_PIXELS_PER_INCH, DEVICE_PIXELS_PER_INCH,
232 (PLINT) ( CANVAS_WIDTH * DEVICE_PIXELS_PER_INCH ), (PLINT) ( CANVAS_HEIGHT * DEVICE_PIXELS_PER_INCH ), 0, 0 );
233
234 // Set up physical limits of plotting device (in drawing units)
235 plP_setphy( 0, (PLINT) ( CANVAS_WIDTH * DEVICE_PIXELS_PER_INCH ),
236 0, (PLINT) ( CANVAS_HEIGHT * DEVICE_PIXELS_PER_INCH ) );
237
238 // Set the number of pixels per mm
239 plP_setpxl( (PLFLT) DEVICE_PIXELS_PER_MM, (PLFLT) DEVICE_PIXELS_PER_MM );
240
241 // If portrait mode is specified, then set up an additional rotation
242 // transformation with aspect ratio allowed to adjust via freeaspect.
243 // Default orientation is landscape (ORIENTATION == 3 or 90 deg rotation
244 // counter-clockwise from portrait). (Legacy PLplot used seascape
245 // which was equivalent to ORIENTATION == 1 or 90 deg clockwise rotation
246 // from portrait.)
247 if ( pls->portrait )
248 {
249 plsdiori( (PLFLT) ( 4 - ORIENTATION ) );
250 pls->freeaspect = 1;
251 }
252
253 // Initialize family file info
254 plFamInit( pls );
255
256 // Prompt for a file name if not already set
257 plOpenFile( pls );
258 dev->pdfFile = pls->OutFile;
259
260 dev->pdf = HPDF_New( error_handler, NULL );
261 if ( !dev->pdf )
262 plexit( "ERROR: cannot create pdf object.\n" );
263
264 if ( compress )
265 HPDF_SetCompressionMode( dev->pdf, HPDF_COMP_ALL );
266
267 // determine size of pdf page - A4 is default
268 dev->pageSize = HPDF_PAGE_SIZE_EOF;
269 if ( pageSize == NULL )
270 dev->pageSize = HPDF_PAGE_SIZE_A4;
271 else if ( !stricmp( pageSize, "letter" ) )
272 dev->pageSize = HPDF_PAGE_SIZE_LETTER;
273 else if ( !stricmp( pageSize, "A3" ) )
274 dev->pageSize = HPDF_PAGE_SIZE_A3;
275 else if ( !stricmp( pageSize, "A4" ) )
276 dev->pageSize = HPDF_PAGE_SIZE_A4;
277 else if ( !stricmp( pageSize, "A5" ) )
278 dev->pageSize = HPDF_PAGE_SIZE_A5;
279
280 if ( dev->pageSize == HPDF_PAGE_SIZE_EOF )
281 plexit( "ERROR: Unknown page size. Allowed strings are: letter, A3, A4, A5.\n" );
282
283 if ( setjmp( env ) )
284 {
285 // HPDF_Free segfaults after error so skip this nicety.
286 //HPDF_Free( dev->pdf );
287 // can't call plexit because that appears to be circular via
288 // what happens with plend. Therefore, print out an error message
289 // and exit.
290 fprintf( stderr, "ERROR in haru library\n" );
291 exit( 1 );
292 }
293 }
294
295 //--------------------------------------------------------------------------
296 // plD_bop_pdf( PLStream *pls )
297 //
298 // Set up for the next page.
299 //--------------------------------------------------------------------------
300 void plD_bop_pdf( PLStream *pls )
301 {
302 pdfdev * dev = (pdfdev *) pls->dev;
303 HPDF_REAL width, height;
304
305 pls->page++;
306
307 // add page and set size (default is A4)
308 dev->page = HPDF_AddPage( dev->pdf );
309 if ( pls->portrait )
310 HPDF_Page_SetSize( dev->page, dev->pageSize, HPDF_PAGE_PORTRAIT );
311 else
312 HPDF_Page_SetSize( dev->page, dev->pageSize, HPDF_PAGE_LANDSCAPE );
313
314 // Determine scaling parameters.
315 width = HPDF_Page_GetWidth( dev->page ); // in pixels/dots
316 height = HPDF_Page_GetHeight( dev->page ); // in pixels/dots
317 dev->scalex = (PLFLT) ( width / ( CANVAS_WIDTH * DEVICE_PIXELS_PER_INCH ) );
318 dev->scaley = (PLFLT) ( height / ( CANVAS_HEIGHT * DEVICE_PIXELS_PER_INCH ) );
319 HPDF_Page_Concat( dev->page, (HPDF_REAL) ( dev->scalex ), 0, 0, (HPDF_REAL) ( dev->scaley ), 0, 0 );
320
321 // Set the background by drawing a rectangle that is the size of
322 // of the canvas and filling it with the background color.
323 HPDF_Page_SetRGBFill( dev->page, (HPDF_REAL) ( pls->cmap0[0].r / 255.0 ),
324 (HPDF_REAL) ( pls->cmap0[0].g / 255.0 ), (HPDF_REAL) ( pls->cmap0[0].b / 255.0 ) );
325 width /= (HPDF_REAL) ( dev->scalex );
326 height /= (HPDF_REAL) ( dev->scaley );
327 HPDF_Page_MoveTo( dev->page, (HPDF_REAL) 0.0, (HPDF_REAL) 0.0 );
328 HPDF_Page_LineTo( dev->page, width, (HPDF_REAL) 0.0 );
329 HPDF_Page_LineTo( dev->page, width, (HPDF_REAL) height );
330 HPDF_Page_LineTo( dev->page, 0.0, (HPDF_REAL) height );
331 HPDF_Page_Fill( dev->page );
332 }
333
334
335 //--------------------------------------------------------------------------
336 // pdf_line()
337 //
338 // Draw a line in the current color from (x1,y1) to (x2,y2).
339 //--------------------------------------------------------------------------
340 void plD_line_pdf( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
341 {
342 short xa[2], ya[2];
343
344 xa[0] = x1a; xa[1] = x2a;
345 ya[0] = y1a; ya[1] = y2a;
346
347 poly_line( pls, xa, ya, 2, 0 );
348 }
349
350
351 //--------------------------------------------------------------------------
352 // pdf_polyline()
353 //
354 // Draw a polyline in the current color.
355 //--------------------------------------------------------------------------
356 void plD_polyline_pdf( PLStream *pls, short *xa, short *ya, PLINT npts )
357 {
358 poly_line( pls, xa, ya, npts, 0 );
359 }
360
361
362 //--------------------------------------------------------------------------
363 // pdf_eop()
364 //
365 // End of page
366 //--------------------------------------------------------------------------
367 void plD_eop_pdf( PLStream * PL_UNUSED( pls ) )
368 {
369 // nothing to be done here
370 }
371
372
373 //--------------------------------------------------------------------------
374 // pdf_tidy()
375 //
376 // Close graphics file or otherwise clean up.
377 //--------------------------------------------------------------------------
378 void plD_tidy_pdf( PLStream *pls )
379 {
380 pdfdev* dev = (pdfdev *) pls->dev;
381
382 // save the document to a stream
383 HPDF_SaveToStream( dev->pdf );
384
385 // rewind the stream.
386 HPDF_ResetStream( dev->pdf );
387
388 // get the data from the stream and output it to stdout.
389 for (;; )
390 {
391 HPDF_BYTE buf[4096]; // TODO: not good
392 HPDF_UINT32 size = 4096;
393 // HPDF_STATUS ret = HPDF_ReadFromStream( dev->pdf, buf, &size );
394 HPDF_ReadFromStream( dev->pdf, buf, &size );
395
396 if ( size == 0 )
397 break;
398
399 if ( fwrite( buf, size, 1, dev->pdfFile ) != 1 )
400 plexit( "ERROR: Cannot write to file!" );
401 }
402
403 plCloseFile( pls );
404
405 // cleanup
406 HPDF_Free( dev->pdf );
407 }
408
409
410 //--------------------------------------------------------------------------
411 // plD_state_pdf()
412 //
413 // Handle change in PLStream state (color, pen width, fill attribute, etc).
414 //
415 // Nothing is done here because these attributes are aquired from
416 // PLStream for each element that is drawn.
417 //--------------------------------------------------------------------------
418 void plD_state_pdf( PLStream * PL_UNUSED( pls ), PLINT PL_UNUSED( op ) )
419 {
420 // Nothing to be done here.
421 }
422
423
424 //--------------------------------------------------------------------------
425 // pdf_esc()
426 //
427 // Escape function.
428 //--------------------------------------------------------------------------
429 void plD_esc_pdf( PLStream *pls, PLINT op, void *ptr )
430 {
431 switch ( op )
432 {
433 case PLESC_FILL: // fill polygon
434 poly_line( pls, pls->dev_x, pls->dev_y, pls->dev_npts, 1 );
435 break;
436 case PLESC_HAS_TEXT: // render text
437 process_string( pls, (EscText *) ptr );
438 break;
439 }
440 }
441
442
443 //--------------------------------------------------------------------------
444 // poly_line()
445 //
446 // Handles drawing filled and unfilled polygons
447 //--------------------------------------------------------------------------
448 void poly_line( PLStream *pls, short *xa, short *ya, PLINT npts, short fill )
449 {
450 pdfdev* dev = (pdfdev *) pls->dev;
451 PLINT i;
452
453 HPDF_Page_SetLineWidth( dev->page, (HPDF_REAL) ( pls->width ) );
454 HPDF_Page_SetLineCap( dev->page, HPDF_ROUND_END );
455 HPDF_Page_SetLineJoin( dev->page, HPDF_ROUND_JOIN );
456 HPDF_Page_SetRGBStroke( dev->page, (HPDF_REAL) ( pls->curcolor.r / 255.0 ),
457 (HPDF_REAL) ( pls->curcolor.g / 255.0 ), (HPDF_REAL) ( pls->curcolor.b / 255.0 ) );
458 HPDF_Page_SetRGBFill( dev->page, (HPDF_REAL) ( pls->curcolor.r / 255.0 ),
459 (HPDF_REAL) ( pls->curcolor.g / 255.0 ), (HPDF_REAL) ( pls->curcolor.b / 255.0 ) );
460
461 HPDF_Page_MoveTo( dev->page, (HPDF_REAL) xa[0], (HPDF_REAL) ya[0] );
462 for ( i = 1; i < npts; i++ )
463 HPDF_Page_LineTo( dev->page, (HPDF_REAL) xa[i], (HPDF_REAL) ya[i] );
464
465 if ( fill == 1 )
466 {
467 if ( pls->dev_eofill )
468 HPDF_Page_EofillStroke( dev->page );
469 else
470 HPDF_Page_FillStroke( dev->page );
471 }
472 else
473 {
474 HPDF_Page_Stroke( dev->page );
475 }
476 }
477
478
479 //--------------------------------------------------------------------------
480 // unsigned char plunicode2type1 (const PLUNICODE index,
481 // const Unicode_to_Type1_table lookup[], const int number_of_entries)
482 //
483 // Function takes an input unicode index, looks through the lookup
484 // table (which must be sorted by PLUNICODE Unicode), then returns the
485 // corresponding Type1 code in the lookup table. If the Unicode index
486 // is not present the returned value is 32 (which is normally a blank
487 // for Type 1 fonts).
488 //--------------------------------------------------------------------------
489 static unsigned char plunicode2type1( const PLUNICODE index,
490 const Unicode_to_Type1_table lookup[],
491 const int nlookup )
492 {
493 int jlo = -1, jmid, jhi = nlookup;
494
495 while ( jhi - jlo > 1 )
496 {
497 // Note that although jlo or jhi can be just outside valid
498 // range (see initialization above) because of while condition
499 // jlo < jmid < jhi and jmid must be in valid range.
500 //
501 jmid = ( jlo + jhi ) / 2;
502 if ( index > lookup[jmid].Unicode )
503 jlo = jmid;
504 else if ( index < lookup[jmid].Unicode )
505 jhi = jmid;
506 else
507 // We have found it!
508 // index == lookup[jmid].Unicode
509 //
510 return ( lookup[jmid].Type1 );
511 }
512 // jlo is invalid or it is valid and index > lookup[jlo].Unicode.
513 // jhi is invalid or it is valid and index < lookup[jhi].Unicode.
514 // All these conditions together imply index cannot be found in lookup.
515 // Mark with ' ' (which is normally the index for blank in type 1 fonts).
516 //
517 return ( ' ' );
518 }
519
520
521 //--------------------------------------------------------------------------
522 // PSDrawTextToCanvas( pdfdev* dev, unsigned char* type1_string, short drawText )
523 //
524 // This function determines the extent of the string and does
525 // the actual drawing to the page if drawText is true.
526 //--------------------------------------------------------------------------
527 void PSDrawTextToCanvas( pdfdev* dev, unsigned char* type1_string, short drawText )
528 {
529 HPDF_REAL th;
530
531 // write text to page
532 if ( drawText )
533 {
534 HPDF_Page_BeginText( dev->page );
535 HPDF_Page_SetTextRenderingMode( dev->page, HPDF_FILL );
536 HPDF_Page_SetRGBFill( dev->page, dev->textRed, dev->textGreen, dev->textBlue );
537 HPDF_Page_MoveTextPos( dev->page, dev->textWidth, dev->yOffset );
538 HPDF_Page_ShowText( dev->page, (char *) type1_string ); // TODO: this conversion must be wrong
539 HPDF_Page_EndText( dev->page );
540 }
541
542 // determine text width and height
543 dev->textWidth += HPDF_Page_TextWidth( dev->page, (char *) type1_string ); // TODO: this conversion must be wrong
544 th = (HPDF_REAL) ( (HPDF_REAL) HPDF_Font_GetCapHeight( dev->m_font ) * dev->fontSize * dev->fontScale / 1000.0 );
545 dev->textHeight = dev->textHeight > ( th + dev->yOffset ) ? dev->textHeight : ( th + dev->yOffset );
546
547 // clear string
548 memset( type1_string, '\0', MAX_STRING_LEN );
549 }
550
551
552 //--------------------------------------------------------------------------
553 // PSSetFont( pdfdev* dev, PLUNICODE fci )
554 //
555 // Sets the font.
556 //--------------------------------------------------------------------------
557 void PSSetFont( pdfdev* dev, PLUNICODE fci )
558 {
559 const char *font;
560
561 // fci = 0 is a special value indicating the Type 1 Symbol font
562 // is desired. This value cannot be confused with a normal FCI value
563 // because it doesn't have the PL_FCI_MARK.
564 if ( fci == 0 )
565 {
566 font = "Symbol";
567 dev->nlookup = number_of_entries_in_unicode_to_symbol_table;
568 dev->lookup = unicode_to_symbol_lookup_table;
569 dev->if_symbol_font = 1;
570 }
571 else
572 {
573 // convert the fci to Base14/Type1 font information
574 font = plP_FCI2FontName( fci, Type1Lookup, N_Type1Lookup );
575 dev->nlookup = number_of_entries_in_unicode_to_standard_table;
576 dev->lookup = unicode_to_standard_lookup_table;
577 dev->if_symbol_font = 0;
578 }
579
580 if ( !( dev->m_font = HPDF_GetFont( dev->pdf, font, NULL ) ) )
581 plexit( "ERROR: Couldn't open font\n" );
582 //pldebug( "PSSetFont", "HPDF requested font size = %f\n", dev->fontSize * dev->fontScale );
583 HPDF_Page_SetFontAndSize( dev->page, dev->m_font, dev->fontSize * dev->fontScale );
584 }
585
586 // 0.8 should mimic the offset of first superscript/subscript level
587 // implemented in plstr (plsym.c) for Hershey fonts. However, when
588 // comparing with -dev xwin and -dev xcairo results changing this
589 // factor to 0.6 appears to offset the centers of the letters
590 // appropriately while 0.8 gives much poorer agreement with the
591 // other devices.
592 # define RISE_FACTOR 0.6
593
594 //--------------------------------------------------------------------------
595 // PSDrawText( pdfdev* dev, PLUNICODE* ucs4, int ucs4Len, short drawText )
596 //
597 // This function is called twice, first to determine the extent of the
598 // text written to the page and then a second time to actually draw
599 // the text.
600 //--------------------------------------------------------------------------
601 void PSDrawText( pdfdev* dev, PLUNICODE* ucs4, int ucs4Len, short drawText )
602 {
603 int i, s;
604 unsigned char type1_string[MAX_STRING_LEN];
605 char plplotEsc;
606 PLUNICODE fci;
607 int last_chance = 0;
608 PLFLT old_sscale, sscale, old_soffset, soffset, dup;
609 PLINT level = 0;
610
611 memset( type1_string, '\0', MAX_STRING_LEN );
612
613 // Get PLplot escape character
614 plgesc( &plplotEsc );
615
616 // Get the current font
617 dev->fontScale = 1.0;
618 dev->yOffset = 0.0;
619 plgfci( &fci );
620 PSSetFont( dev, fci );
621 dev->textWidth = 0;
622 dev->textHeight = 0;
623
624 i = 0; s = 0;
625 while ( i < ucs4Len )
626 {
627 if ( ucs4[i] < PL_FCI_MARK ) // not a font change
628 {
629 if ( ucs4[i] != (PLUNICODE) plplotEsc ) // a character to display
630 {
631 type1_string[s] = plunicode2type1( ucs4[i], dev->lookup, dev->nlookup );
632 if ( ucs4[i] != ' ' && type1_string[s] == ' ' )
633 {
634 // failed lookup
635 if ( !dev->if_symbol_font )
636 {
637 // failed standard font lookup. Try "last chance"
638 // symbol font instead.
639 type1_string[s] = '\0';
640 PSDrawTextToCanvas( dev, type1_string, drawText );
641 s = 0;
642 last_chance = 1;
643 PSSetFont( dev, 0 );
644 continue;
645 }
646 else if ( !last_chance )
647 {
648 // failed symbol font lookup that is not right
649 // after a failed standard font lookup (i.e.,
650 // last_change = 0). Try standard fonts lookup instead.
651 type1_string[s] = '\0';
652 PSDrawTextToCanvas( dev, type1_string, drawText );
653 s = 0;
654 last_chance = 0;
655 PSSetFont( dev, fci );
656 continue;
657 }
658 else
659 {
660 // failed "last_chance" symbol font lookup that
661 // has occurred right after a failed standard
662 // fonts lookup. Just accept blank result and
663 // move on using standard fonts.
664 PSDrawTextToCanvas( dev, type1_string, drawText );
665 s = 0;
666 last_chance = 0;
667 PSSetFont( dev, fci );
668 i++;
669 continue;
670 }
671 }
672 else
673 {
674 // font lookup succeeded.
675 s++;
676 i++;
677 last_chance = 0;
678 continue;
679 }
680 }
681 i++;
682 if ( ucs4[i] == (PLUNICODE) plplotEsc ) // a escape character to display
683 {
684 type1_string[s] = plunicode2type1( ucs4[i], dev->lookup, dev->nlookup );
685 if ( ucs4[i] != ' ' && type1_string[s] == ' ' )
686 {
687 // failed lookup
688 if ( !dev->if_symbol_font )
689 {
690 // failed standard font lookup. Try "last chance"
691 // symbol font instead.
692 type1_string[s] = '\0';
693 PSDrawTextToCanvas( dev, type1_string, drawText );
694 s = 0;
695 last_chance = 1;
696 PSSetFont( dev, 0 );
697 continue;
698 }
699 else if ( !last_chance )
700 {
701 // failed symbol font lookup that is not right
702 // after a failed standard font lookup (i.e.,
703 // last_change = 0). Try standard fonts lookup instead.
704 type1_string[s] = '\0';
705 PSDrawTextToCanvas( dev, type1_string, drawText );
706 s = 0;
707 last_chance = 0;
708 PSSetFont( dev, fci );
709 continue;
710 }
711 else
712 {
713 // failed "last_chance" symbol font lookup that
714 // has occurred right after a failed standard
715 // fonts lookup. Just accept blank result and
716 // move on using standard fonts.
717 PSDrawTextToCanvas( dev, type1_string, drawText );
718 s = 0;
719 last_chance = 0;
720 PSSetFont( dev, fci );
721 i++;
722 continue;
723 }
724 }
725 else
726 {
727 // font lookup succeeded.
728 s++;
729 i++;
730 last_chance = 0;
731 continue;
732 }
733 }
734 else
735 {
736 if ( ucs4[i] == (PLUNICODE) 'u' ) // Superscript
737 {
738 // draw string so far
739 PSDrawTextToCanvas( dev, type1_string, drawText );
740 s = 0;
741
742 plP_script_scale( TRUE, &level,
743 &old_sscale, &sscale, &old_soffset, &soffset );
744 // The correction for the difference in magnitude
745 // between the baseline and middle coordinate systems
746 // for superscripts should be
747 // 0.5*(base font size - superscript/subscript font size).
748 dup = 0.5 * ( 1.0 - sscale );
749 dev->fontScale = (HPDF_REAL) sscale;
750 PSSetFont( dev, fci );
751 dev->yOffset = (HPDF_REAL) ( dev->fontSize * ( soffset * RISE_FACTOR + dup ) );
752 }
753 if ( ucs4[i] == (PLUNICODE) 'd' ) // Subscript
754 {
755 // draw string so far
756 PSDrawTextToCanvas( dev, type1_string, drawText );
757 s = 0;
758
759 plP_script_scale( FALSE, &level,
760 &old_sscale, &sscale, &old_soffset, &soffset );
761 // The correction for the difference in magnitude
762 // between the baseline and middle coordinate systems
763 // for subcripts should be
764 // 0.5*(base font size - superscript/subscript font size).
765 dup = -0.5 * ( 1.0 - sscale );
766 dev->fontScale = (HPDF_REAL) sscale;
767 PSSetFont( dev, fci );
768 dev->yOffset = (HPDF_REAL) ( -dev->fontSize * ( soffset * RISE_FACTOR + dup ) );
769 }
770 if ( ucs4[i] == (PLUNICODE) '-' ) // underline
771 { // draw string so far
772 PSDrawTextToCanvas( dev, type1_string, drawText );
773 s = 0;
774
775 // dev->underlined = !dev->underlined;
776 PSSetFont( dev, fci );
777 }
778 if ( ucs4[i] == (PLUNICODE) '+' ) // overline
779 { // not implemented yet
780 }
781 i++;
782 }
783 }
784 else // a font change
785 {
786 // draw string so far
787 PSDrawTextToCanvas( dev, type1_string, drawText );
788 s = 0;
789
790 // get new font
791 fci = ucs4[i];
792 PSSetFont( dev, fci );
793 i++;
794 }
795 }
796
797 PSDrawTextToCanvas( dev, type1_string, drawText );
798 }
799
800
801 //--------------------------------------------------------------------------
802 // process_string( PLStream* pls, EscText* args )
803 //
804 // Handles the output of the text on the page.
805 //--------------------------------------------------------------------------
806 void process_string( PLStream* pls, EscText* args )
807 {
808 pdfdev * dev = (pdfdev *) pls->dev;
809 PLFLT rotation, shear, stride;
810 HPDF_REAL cos_rot, sin_rot, cos_shear, sin_shear;
811
812 // Check that we got unicode, warning message and return if not
813 if ( args->unicode_array_len == 0 )
814 {
815 printf( "Non unicode string passed to a pdf driver, ignoring\n" );
816 return;
817 }
818
819 // Check that unicode string isn't longer then the max we allow
820 if ( args->unicode_array_len >= MAX_STRING_LEN )
821 {
822 printf( "Sorry, the pdf drivers only handles strings of length < %d\n", MAX_STRING_LEN );
823 return;
824 }
825
826 // Calculate the font size (in pixels)
827 dev->fontSize = (HPDF_REAL) ( pls->chrht * DEVICE_PIXELS_PER_INCH / 25.4 * 1.6 );
828
829 // text color
830 dev->textRed = (HPDF_REAL) ( pls->curcolor.r / 255.0 );
831 dev->textGreen = (HPDF_REAL) ( pls->curcolor.g / 255.0 );
832 dev->textBlue = (HPDF_REAL) ( pls->curcolor.b / 255.0 );
833
834 // calculate transformation matrix (rotation and shear of text)
835 plRotationShear( args->xform, &rotation, &shear, &stride );
836 rotation -= pls->diorot * M_PI / 2.0;
837 cos_rot = (HPDF_REAL) cos( rotation );
838 sin_rot = (HPDF_REAL) sin( rotation );
839 cos_shear = (HPDF_REAL) cos( shear );
840 sin_shear = (HPDF_REAL) sin( shear );
841
842 // calculate text extend -> stored in dev->textWidth and dev->textHeight
843 PSDrawText( dev, args->unicode_array, args->unicode_array_len, 0 );
844
845 // apply transformation matrix and draw text
846 HPDF_Page_GSave( dev->page );
847 HPDF_Page_Concat( dev->page, cos_rot, sin_rot,
848 -cos_rot * sin_shear - sin_rot * cos_shear,
849 -sin_rot * sin_shear + cos_rot * cos_shear,
850 (HPDF_REAL) ( args->x ), (HPDF_REAL) ( args->y ) );
851 HPDF_Page_Concat( dev->page, (HPDF_REAL) 1.0, (HPDF_REAL) 0.0, (HPDF_REAL) 0.0, (HPDF_REAL) 1.0,
852 (HPDF_REAL) ( -args->just * dev->textWidth ), (HPDF_REAL) ( -0.5 * dev->textHeight ) );
853 PSDrawText( dev, args->unicode_array, args->unicode_array_len, 1 );
854 HPDF_Page_GRestore( dev->page );
855 }
856
857 #else
858
859 //--------------------------------------------------------------------------
860 // pldummy_pdf()
861 //
862 // Dummy function if driver should not be available.
863 //--------------------------------------------------------------------------
864 int pldummy_pdf()
865 {
866 return 0;
867 }
868
869 #endif // PLD_pdf
870
plParseDrvOpts
int plParseDrvOpts(DrvOpt *acc_opt)
Definition: plargs.c:1461
plP_script_scale
void plP_script_scale(PLBOOL ifupper, PLINT *level, PLFLT *old_scale, PLFLT *scale, PLFLT *old_offset, PLFLT *offset)
Definition: plsym.c:1302
plplotP.h
plgesc
void plgesc(char *p_esc)
Definition: plcore.c:3914
plexit
void plexit(PLCHAR_VECTOR errormsg)
Definition: plctrl.c:1958
plspage
#define plspage
Definition: plplot.h:831
EscText::just
PLFLT just
Definition: plplotP.h:708
PLColor::b
unsigned char b
Definition: plplot.h:550
PLStream::dev_fill1
PLINT dev_fill1
Definition: plstrm.h:571
MAX_STRING_LEN
#define MAX_STRING_LEN
Definition: aqt.c:47
RISE_FACTOR
#define RISE_FACTOR
Definition: cairo.c:1226
PLStream::OutFile
FILE * OutFile
Definition: plstrm.h:575
PLESC_FILL
#define PLESC_FILL
Definition: plplot.h:279
PLDispatchTable::pl_esc
plD_esc_fp pl_esc
Definition: disptab.h:90
unicode_to_symbol_lookup_table
static const Unicode_to_Type1_table unicode_to_symbol_lookup_table[194]
Definition: plunicode-type1.h:408
PLUNICODE
PLUINT PLUNICODE
Definition: plplot.h:201
plOpenFile
void plOpenFile(PLStream *pls)
Definition: plctrl.c:2571
plCloseFile
void plCloseFile(PLStream *pls)
Definition: plctrl.c:2635
plDevType_FileOriented
Definition: disptab.h:13
number_of_entries_in_unicode_to_standard_table
static const int number_of_entries_in_unicode_to_standard_table
Definition: plunicode-type1.h:247
plD_tidy_fp
void(* plD_tidy_fp)(struct PLStream_struct *)
Definition: disptab.h:72
PLDispatchTable::pl_seq
int pl_seq
Definition: disptab.h:82
PLStream::dev_text
PLINT dev_text
Definition: plstrm.h:572
PLStream::dev_npts
PLINT dev_npts
Definition: plstrm.h:581
PLDispatchTable::pl_MenuStr
const char * pl_MenuStr
Definition: disptab.h:79
PLStream::color
PLINT color
Definition: plstrm.h:569
PLStream::dev_unicode
PLINT dev_unicode
Definition: plstrm.h:747
plfci-type1.h
PLDispatchTable::pl_tidy
plD_tidy_fp pl_tidy
Definition: disptab.h:88
plD_init_fp
void(* plD_init_fp)(struct PLStream_struct *)
Definition: disptab.h:67
plsdiori
#define plsdiori
Definition: plplot.h:809
PLStream::diorot
PLFLT diorot
Definition: plstrm.h:661
plD_eop_fp
void(* plD_eop_fp)(struct PLStream_struct *)
Definition: disptab.h:70
PLDispatchTable::pl_DevName
const char * pl_DevName
Definition: disptab.h:80
PLDispatchTable::pl_init
plD_init_fp pl_init
Definition: disptab.h:83
PLStream::colorset
PLINT colorset
Definition: plstrm.h:569
PLStream::dev_x
short * dev_x
Definition: plstrm.h:582
plFamInit
void plFamInit(PLStream *pls)
Definition: plctrl.c:2751
DRV_STR
Definition: plplotP.h:758
color
static int color
Definition: ps.c:78
PLINT
int PLINT
Definition: plplot.h:181
number_of_entries_in_unicode_to_symbol_table
static const int number_of_entries_in_unicode_to_symbol_table
Definition: plunicode-type1.h:406
PLStream::portrait
PLINT portrait
Definition: plstrm.h:665
plD_line_fp
void(* plD_line_fp)(struct PLStream_struct *, short, short, short, short)
Definition: disptab.h:68
plunicode2type1
static unsigned char plunicode2type1(const PLUNICODE index, const Unicode_to_Type1_table lookup[], const int number_of_entries)
Definition: ps.c:1172
PLColor::g
unsigned char g
Definition: plplot.h:549
Unicode_to_Type1_table
Definition: plunicode-type1.h:30
plD_esc_fp
void(* plD_esc_fp)(struct PLStream_struct *, PLINT, void *)
Definition: disptab.h:74
EscText
Definition: plplotP.h:699
plD_polyline_fp
void(* plD_polyline_fp)(struct PLStream_struct *, short *, short *, PLINT)
Definition: disptab.h:69
PLStream::termin
PLINT termin
Definition: plstrm.h:568
TRUE
#define TRUE
Definition: plplotP.h:176
PLStream::dev_hrshsym
PLINT dev_hrshsym
Definition: plstrm.h:753
PLDispatchTable
Definition: disptab.h:77
N_Type1Lookup
#define N_Type1Lookup
Definition: plfci-type1.h:41
FALSE
#define FALSE
Definition: plplotP.h:177
PLDispatchTable::pl_bop
plD_bop_fp pl_bop
Definition: disptab.h:87
poly_line
static void poly_line(PLStream *, short *, short *, PLINT)
Definition: cairo.c:1430
DrvOpt
Definition: plplotP.h:748
ORIENTATION
#define ORIENTATION
Definition: plplotP.h:358
PLDispatchTable::pl_line
plD_line_fp pl_line
Definition: disptab.h:84
Type1Lookup
static const FCI_to_FontName_Table Type1Lookup[N_Type1Lookup]
Definition: plfci-type1.h:42
plP_setpxl
void plP_setpxl(PLFLT xpmm, PLFLT ypmm)
Definition: plcore.c:4238
PLStream::cmap0
PLColor * cmap0
Definition: plstrm.h:544
drivers.h
plD_dispatch_init_pdf
PLDLLIMPEXP_DRIVER void plD_dispatch_init_pdf(PLDispatchTable *pdt)
plDevs.h
PLDLLIMPEXP_DRIVER
#define PLDLLIMPEXP_DRIVER
Definition: pldll.h:81
buf
static char buf[200]
Definition: tclAPI.c:873
pls
static PLStream * pls[PL_NSTREAMS]
Definition: plcore.h:88
plP_setphy
void plP_setphy(PLINT xmin, PLINT xmax, PLINT ymin, PLINT ymax)
Definition: plcore.c:4249
plgfci
#define plgfci
Definition: plplot.h:735
plRotationShear
void plRotationShear(PLFLT *xFormMatrix, PLFLT *rotation, PLFLT *shear, PLFLT *stride)
Definition: plot3d.c:2767
EscText::unicode_array_len
unsigned short unicode_array_len
Definition: plplotP.h:736
PLStream::dev_y
short * dev_y
Definition: plstrm.h:582
PLStream
Definition: plstrm.h:523
text
static int text
Definition: ps.c:77
plunicode-type1.h
PL_UNUSED
#define PL_UNUSED(x)
Definition: plplot.h:138
PLFLT
float PLFLT
Definition: plplot.h:163
PLStream::graphx
PLINT graphx
Definition: plstrm.h:568
PLStream::chrht
PLFLT chrht
Definition: plstrm.h:686
PLStream::page
PLINT page
Definition: plstrm.h:578
plD_bop_fp
void(* plD_bop_fp)(struct PLStream_struct *)
Definition: disptab.h:71
pldummy_pdf
int pldummy_pdf()
Definition: pdf.c:864
plP_FCI2FontName
PLCHAR_VECTOR plP_FCI2FontName(PLUNICODE fci, const FCI_to_FontName_Table lookup[], const int nlookup)
Definition: plsym.c:1548
PLColor::r
unsigned char r
Definition: plplot.h:548
PLESC_HAS_TEXT
#define PLESC_HAS_TEXT
Definition: plplot.h:290
PLStream::width
PLFLT width
Definition: plstrm.h:552
EscText::y
PLINT y
Definition: plplotP.h:713
DRV_INT
Definition: plplotP.h:758
PLStream::curcolor
PLColor curcolor
Definition: plstrm.h:543
PLDispatchTable::pl_state
plD_state_fp pl_state
Definition: disptab.h:89
hrshsym
static int hrshsym
Definition: ps.c:79
PLDispatchTable::pl_eop
plD_eop_fp pl_eop
Definition: disptab.h:86
EscText::x
PLINT x
Definition: plplotP.h:712
unicode_to_standard_lookup_table
static const Unicode_to_Type1_table unicode_to_standard_lookup_table[154]
Definition: plunicode-type1.h:249
PLDispatchTable::pl_polyline
plD_polyline_fp pl_polyline
Definition: disptab.h:85
plD_state_fp
void(* plD_state_fp)(struct PLStream_struct *, PLINT)
Definition: disptab.h:73
EscText::unicode_array
PLUNICODE * unicode_array
Definition: plplotP.h:735
PLStream::dev
void * dev
Definition: plstrm.h:594
M_PI
#define M_PI
Definition: plplotP.h:119
PLStream::freeaspect
PLINT freeaspect
Definition: plstrm.h:665
PLStream::bytecnt
PLINT bytecnt
Definition: plstrm.h:578
PLStream::dev_fill0
PLINT dev_fill0
Definition: plstrm.h:571
PLDispatchTable::pl_type
int pl_type
Definition: disptab.h:81
EscText::xform
PLFLT * xform
Definition: plplotP.h:709
plcallback::fill
PLDLLIMPEXP_CXX void fill(PLINT n, const PLFLT *x, const PLFLT *y)
Definition: plstream.cc:246
PLStream::dev_eofill
PLINT dev_eofill
Definition: plstrm.h:788
GRAPHICS_MODE
#define GRAPHICS_MODE
Definition: plplotP.h:288
PL_FCI_MARK
#define PL_FCI_MARK
Definition: plplot.h:370