PLplot: pdf.c Source File

PLplot 5.10.0

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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