PageRenderTime 40ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/tags/v5_9_6/drivers/pdf.c

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