PLplot
5.10.0
|
00001 // PLplot driver for PDF based on the haru library http://www.libharu.org. 00002 // 00003 // Copyright (C) 2006, 2008 Werner Smekal 00004 // 00005 // This file is part of PLplot. 00006 // 00007 // PLplot is free software; you can redistribute it and/or modify 00008 // it under the terms of the GNU Library General Public License as published 00009 // by the Free Software Foundation; either version 2 of the License, or 00010 // (at your option) any later version. 00011 // 00012 // PLplot is distributed in the hope that it will be useful, 00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 // GNU Library General Public License for more details. 00016 // 00017 // You should have received a copy of the GNU Library General Public License 00018 // along with PLplot; if not, write to the Free Software 00019 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 // 00021 // 00022 00023 // TODO: 00024 // - page orientation 00025 // - text clipping 00026 // 00027 00028 //-------------------------------------------------------------------------- 00029 // Header files, defines and local variables 00030 //-------------------------------------------------------------------------- 00031 #include "plDevs.h" 00032 00033 #ifdef PLD_pdf 00034 00035 #include <stdarg.h> 00036 #include <math.h> 00037 #include <setjmp.h> 00038 #include <strings.h> 00039 00040 #include "hpdf.h" 00041 00042 // PLplot header files 00043 //#define DEBUG 00044 //#define NEED_PLDEBUG 00045 #include "plplotP.h" 00046 #include "drivers.h" 00047 #include "plunicode-type1.h" 00048 #include "plfci-type1.h" 00049 00050 // Workaround for caseless string comparison 00051 #ifndef WIN32 00052 #define stricmp strcasecmp 00053 #define strnicmp strncasecmp 00054 #endif 00055 00056 // constants 00057 00058 // We define a virtual page and scale it down to the 00059 // paper size chosen by the user (A4 is default). 00060 // 00061 00062 // Default dimensions of the canvas (in inches) and DPI 00063 #define CANVAS_WIDTH ( 50.0 ) 00064 #define CANVAS_HEIGHT ( 37.5 ) 00065 #define DEVICE_PIXELS_PER_INCH ( 72 ) 00066 00067 // mm per inch 00068 #define MM_PER_INCH ( 25.4 ) 00069 00070 // pixels per mm 00071 #define DEVICE_PIXELS_PER_MM ( DEVICE_PIXELS_PER_INCH / MM_PER_INCH ) 00072 00073 // maximum string length for own font handling 00074 #define MAX_STRING_LEN 1000 00075 00076 // container for device specific data 00077 typedef struct 00078 { 00079 HPDF_Doc pdf; 00080 HPDF_Page page; 00081 HPDF_PageSizes pageSize; 00082 FILE *pdfFile; 00083 PLFLT scalex, scaley; 00084 00085 // font variables 00086 HPDF_Font m_font; 00087 int nlookup, if_symbol_font; 00088 const Unicode_to_Type1_table *lookup; 00089 HPDF_REAL fontSize; 00090 HPDF_REAL fontScale; 00091 HPDF_REAL textWidth, textHeight; 00092 HPDF_REAL yOffset; 00093 HPDF_REAL textRed, textGreen, textBlue; 00094 } pdfdev; 00095 00096 // local variables 00097 PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_pdf = "pdf:Portable Document Format PDF:1:pdf:58:pdf\n"; 00098 static jmp_buf env; 00099 00100 //-------------------------------------------------------------------------- 00101 // function declarations 00102 //-------------------------------------------------------------------------- 00103 00104 // General 00105 //static short desired_offset( short, double ); 00106 static void poly_line( PLStream *pls, short *xa, short *ya, PLINT npts, short fill ); 00107 00108 // String processing 00109 static void process_string( PLStream *, EscText * ); 00110 00111 // PLplot interface functions 00112 void plD_dispatch_init_pdf( PLDispatchTable *pdt ); 00113 void plD_init_pdf( PLStream * ); 00114 void plD_line_pdf( PLStream *, short, short, short, short ); 00115 void plD_polyline_pdf( PLStream *, short *, short *, PLINT ); 00116 void plD_eop_pdf( PLStream * ); 00117 void plD_bop_pdf( PLStream * ); 00118 void plD_tidy_pdf( PLStream * ); 00119 void plD_state_pdf( PLStream *, PLINT ); 00120 void plD_esc_pdf( PLStream *, PLINT, void * ); 00121 void error_handler( HPDF_STATUS error_no, HPDF_STATUS detail_no, void *user_data ); 00122 void PSDrawTextToCanvas( pdfdev* dev, unsigned char* type1_string, short drawText ); 00123 void PSSetFont( pdfdev* dev, PLUNICODE fci ); 00124 void PSDrawText( pdfdev* dev, PLUNICODE* ucs4, int ucs4Len, short drawText ); 00125 00126 //-------------------------------------------------------------------------- 00127 // error_handler( HPDF_STATUS error_no, HPDF_STATUS detail_no, 00128 // void *user_data ) 00129 // 00130 // Error handler for haru library. 00131 //-------------------------------------------------------------------------- 00132 #ifdef HPDF_DLL 00133 void __stdcall 00134 #else 00135 void 00136 #endif 00137 error_handler( HPDF_STATUS error_no, HPDF_STATUS detail_no, void * PL_UNUSED( user_data ) ) 00138 { 00139 // invoke longjmp() when an error has occurred 00140 printf( "ERROR: error_no=%04X, detail_no=%d\n", (unsigned int) error_no, (int) detail_no ); 00141 longjmp( env, 1 ); 00142 } 00143 00144 00145 //-------------------------------------------------------------------------- 00146 // plD_dispatch_init_pdf( PLDispatchTable *pdt ) 00147 // 00148 // Initialize device dispatch table. 00149 //-------------------------------------------------------------------------- 00150 void plD_dispatch_init_pdf( PLDispatchTable *pdt ) 00151 { 00152 #ifndef ENABLE_DYNDRIVERS 00153 pdt->pl_MenuStr = "Portable Document Format PDF"; 00154 pdt->pl_DevName = "pdf"; 00155 #endif 00156 pdt->pl_type = plDevType_FileOriented; 00157 pdt->pl_seq = 58; 00158 pdt->pl_init = (plD_init_fp) plD_init_pdf; 00159 pdt->pl_line = (plD_line_fp) plD_line_pdf; 00160 pdt->pl_polyline = (plD_polyline_fp) plD_polyline_pdf; 00161 pdt->pl_eop = (plD_eop_fp) plD_eop_pdf; 00162 pdt->pl_bop = (plD_bop_fp) plD_bop_pdf; 00163 pdt->pl_tidy = (plD_tidy_fp) plD_tidy_pdf; 00164 pdt->pl_state = (plD_state_fp) plD_state_pdf; 00165 pdt->pl_esc = (plD_esc_fp) plD_esc_pdf; 00166 } 00167 00168 00169 // driver specific options 00170 static PLINT text = 1; 00171 static PLINT compress = 1; 00172 static PLINT hrshsym = 1; 00173 static PLINT color = 1; 00174 static char * pageSize = NULL; 00175 00176 DrvOpt pdf_options[] = { 00177 { "text", DRV_INT, &text, "Use own text routines (text=0|1)" }, 00178 { "color", DRV_INT, &color, "Use color (color=0|1)" }, 00179 { "compress", DRV_INT, &compress, "Compress pdf output (compress=0|1)" }, 00180 { "hrshsym", DRV_INT, &hrshsym, "Use Hershey symbol set (hrshsym=0|1)" }, 00181 { "pagesize", DRV_STR, &pageSize, "Set page size (pagesize=A4|letter|A3|A5)" }, 00182 { NULL, DRV_INT, NULL, NULL } 00183 }; 00184 00185 00186 //-------------------------------------------------------------------------- 00187 // plD_init_pdf( PLStream *pls ) 00188 // 00189 // Initialize device. 00190 //-------------------------------------------------------------------------- 00191 void plD_init_pdf( PLStream *pls ) 00192 { 00193 pdfdev* dev; 00194 00195 // allocate memory for the device storage 00196 dev = (pdfdev *) calloc( 1, sizeof ( pdfdev ) ); 00197 if ( dev == NULL ) 00198 plexit( "Insufficient memory\n" ); 00199 pls->dev = (void *) dev; 00200 00201 // Check for and set up driver options 00202 plParseDrvOpts( pdf_options ); 00203 00204 pls->termin = 0; // not an interactive device 00205 if ( color ) 00206 pls->color = 1; // supports color 00207 else 00208 pls->color = 0; // monochrome 00209 pls->width = 1; 00210 pls->bytecnt = 0; 00211 00212 if ( text ) 00213 { 00214 pls->dev_text = 1; // handles text 00215 pls->dev_unicode = 1; // wants text as unicode 00216 if ( hrshsym ) 00217 pls->dev_hrshsym = 1; 00218 } 00219 00220 pls->page = 0; 00221 pls->dev_fill0 = 1; // supports hardware solid fills 00222 pls->dev_fill1 = 0; // Use PLplot core fallback for pattern fills 00223 00224 pls->graphx = GRAPHICS_MODE; 00225 00226 if ( !pls->colorset ) 00227 pls->color = 1; 00228 00229 // Set the (virtual) page size. The geometry option is 00230 // neglected. Page sizes are set with the pagesize option. 00231 plspage( DEVICE_PIXELS_PER_INCH, DEVICE_PIXELS_PER_INCH, 00232 (PLINT) ( CANVAS_WIDTH * DEVICE_PIXELS_PER_INCH ), (PLINT) ( CANVAS_HEIGHT * DEVICE_PIXELS_PER_INCH ), 0, 0 ); 00233 00234 // Set up physical limits of plotting device (in drawing units) 00235 plP_setphy( 0, (PLINT) ( CANVAS_WIDTH * DEVICE_PIXELS_PER_INCH ), 00236 0, (PLINT) ( CANVAS_HEIGHT * DEVICE_PIXELS_PER_INCH ) ); 00237 00238 // Set the number of pixels per mm 00239 plP_setpxl( (PLFLT) DEVICE_PIXELS_PER_MM, (PLFLT) DEVICE_PIXELS_PER_MM ); 00240 00241 // If portrait mode is specified, then set up an additional rotation 00242 // transformation with aspect ratio allowed to adjust via freeaspect. 00243 // Default orientation is landscape (ORIENTATION == 3 or 90 deg rotation 00244 // counter-clockwise from portrait). (Legacy PLplot used seascape 00245 // which was equivalent to ORIENTATION == 1 or 90 deg clockwise rotation 00246 // from portrait.) 00247 if ( pls->portrait ) 00248 { 00249 plsdiori( (PLFLT) ( 4 - ORIENTATION ) ); 00250 pls->freeaspect = 1; 00251 } 00252 00253 // Initialize family file info 00254 plFamInit( pls ); 00255 00256 // Prompt for a file name if not already set 00257 plOpenFile( pls ); 00258 dev->pdfFile = pls->OutFile; 00259 00260 dev->pdf = HPDF_New( error_handler, NULL ); 00261 if ( !dev->pdf ) 00262 plexit( "ERROR: cannot create pdf object.\n" ); 00263 00264 if ( compress ) 00265 HPDF_SetCompressionMode( dev->pdf, HPDF_COMP_ALL ); 00266 00267 // determine size of pdf page - A4 is default 00268 dev->pageSize = HPDF_PAGE_SIZE_EOF; 00269 if ( pageSize == NULL ) 00270 dev->pageSize = HPDF_PAGE_SIZE_A4; 00271 else if ( !stricmp( pageSize, "letter" ) ) 00272 dev->pageSize = HPDF_PAGE_SIZE_LETTER; 00273 else if ( !stricmp( pageSize, "A3" ) ) 00274 dev->pageSize = HPDF_PAGE_SIZE_A3; 00275 else if ( !stricmp( pageSize, "A4" ) ) 00276 dev->pageSize = HPDF_PAGE_SIZE_A4; 00277 else if ( !stricmp( pageSize, "A5" ) ) 00278 dev->pageSize = HPDF_PAGE_SIZE_A5; 00279 00280 if ( dev->pageSize == HPDF_PAGE_SIZE_EOF ) 00281 plexit( "ERROR: Unknown page size. Allowed strings are: letter, A3, A4, A5.\n" ); 00282 00283 if ( setjmp( env ) ) 00284 { 00285 // HPDF_Free segfaults after error so skip this nicety. 00286 //HPDF_Free( dev->pdf ); 00287 // can't call plexit because that appears to be circular via 00288 // what happens with plend. Therefore, print out an error message 00289 // and exit. 00290 fprintf( stderr, "ERROR in haru library\n" ); 00291 exit( 1 ); 00292 } 00293 } 00294 00295 //-------------------------------------------------------------------------- 00296 // plD_bop_pdf( PLStream *pls ) 00297 // 00298 // Set up for the next page. 00299 //-------------------------------------------------------------------------- 00300 void plD_bop_pdf( PLStream *pls ) 00301 { 00302 pdfdev * dev = (pdfdev *) pls->dev; 00303 HPDF_REAL width, height; 00304 00305 pls->page++; 00306 00307 // add page and set size (default is A4) 00308 dev->page = HPDF_AddPage( dev->pdf ); 00309 if ( pls->portrait ) 00310 HPDF_Page_SetSize( dev->page, dev->pageSize, HPDF_PAGE_PORTRAIT ); 00311 else 00312 HPDF_Page_SetSize( dev->page, dev->pageSize, HPDF_PAGE_LANDSCAPE ); 00313 00314 // Determine scaling parameters. 00315 width = HPDF_Page_GetWidth( dev->page ); // in pixels/dots 00316 height = HPDF_Page_GetHeight( dev->page ); // in pixels/dots 00317 dev->scalex = (PLFLT) ( width / ( CANVAS_WIDTH * DEVICE_PIXELS_PER_INCH ) ); 00318 dev->scaley = (PLFLT) ( height / ( CANVAS_HEIGHT * DEVICE_PIXELS_PER_INCH ) ); 00319 HPDF_Page_Concat( dev->page, (HPDF_REAL) ( dev->scalex ), 0, 0, (HPDF_REAL) ( dev->scaley ), 0, 0 ); 00320 00321 // Set the background by drawing a rectangle that is the size of 00322 // of the canvas and filling it with the background color. 00323 HPDF_Page_SetRGBFill( dev->page, (HPDF_REAL) ( pls->cmap0[0].r / 255.0 ), 00324 (HPDF_REAL) ( pls->cmap0[0].g / 255.0 ), (HPDF_REAL) ( pls->cmap0[0].b / 255.0 ) ); 00325 width /= (HPDF_REAL) ( dev->scalex ); 00326 height /= (HPDF_REAL) ( dev->scaley ); 00327 HPDF_Page_MoveTo( dev->page, (HPDF_REAL) 0.0, (HPDF_REAL) 0.0 ); 00328 HPDF_Page_LineTo( dev->page, width, (HPDF_REAL) 0.0 ); 00329 HPDF_Page_LineTo( dev->page, width, (HPDF_REAL) height ); 00330 HPDF_Page_LineTo( dev->page, 0.0, (HPDF_REAL) height ); 00331 HPDF_Page_Fill( dev->page ); 00332 } 00333 00334 00335 //-------------------------------------------------------------------------- 00336 // pdf_line() 00337 // 00338 // Draw a line in the current color from (x1,y1) to (x2,y2). 00339 //-------------------------------------------------------------------------- 00340 void plD_line_pdf( PLStream *pls, short x1a, short y1a, short x2a, short y2a ) 00341 { 00342 short xa[2], ya[2]; 00343 00344 xa[0] = x1a; xa[1] = x2a; 00345 ya[0] = y1a; ya[1] = y2a; 00346 00347 poly_line( pls, xa, ya, 2, 0 ); 00348 } 00349 00350 00351 //-------------------------------------------------------------------------- 00352 // pdf_polyline() 00353 // 00354 // Draw a polyline in the current color. 00355 //-------------------------------------------------------------------------- 00356 void plD_polyline_pdf( PLStream *pls, short *xa, short *ya, PLINT npts ) 00357 { 00358 poly_line( pls, xa, ya, npts, 0 ); 00359 } 00360 00361 00362 //-------------------------------------------------------------------------- 00363 // pdf_eop() 00364 // 00365 // End of page 00366 //-------------------------------------------------------------------------- 00367 void plD_eop_pdf( PLStream * PL_UNUSED( pls ) ) 00368 { 00369 // nothing to be done here 00370 } 00371 00372 00373 //-------------------------------------------------------------------------- 00374 // pdf_tidy() 00375 // 00376 // Close graphics file or otherwise clean up. 00377 //-------------------------------------------------------------------------- 00378 void plD_tidy_pdf( PLStream *pls ) 00379 { 00380 pdfdev* dev = (pdfdev *) pls->dev; 00381 00382 // save the document to a stream 00383 HPDF_SaveToStream( dev->pdf ); 00384 00385 // rewind the stream. 00386 HPDF_ResetStream( dev->pdf ); 00387 00388 // get the data from the stream and output it to stdout. 00389 for (;; ) 00390 { 00391 HPDF_BYTE buf[4096]; // TODO: not good 00392 HPDF_UINT32 size = 4096; 00393 // HPDF_STATUS ret = HPDF_ReadFromStream( dev->pdf, buf, &size ); 00394 HPDF_ReadFromStream( dev->pdf, buf, &size ); 00395 00396 if ( size == 0 ) 00397 break; 00398 00399 if ( fwrite( buf, size, 1, dev->pdfFile ) != 1 ) 00400 plexit( "ERROR: Cannot write to file!" ); 00401 } 00402 00403 plCloseFile( pls ); 00404 00405 // cleanup 00406 HPDF_Free( dev->pdf ); 00407 } 00408 00409 00410 //-------------------------------------------------------------------------- 00411 // plD_state_pdf() 00412 // 00413 // Handle change in PLStream state (color, pen width, fill attribute, etc). 00414 // 00415 // Nothing is done here because these attributes are aquired from 00416 // PLStream for each element that is drawn. 00417 //-------------------------------------------------------------------------- 00418 void plD_state_pdf( PLStream * PL_UNUSED( pls ), PLINT PL_UNUSED( op ) ) 00419 { 00420 // Nothing to be done here. 00421 } 00422 00423 00424 //-------------------------------------------------------------------------- 00425 // pdf_esc() 00426 // 00427 // Escape function. 00428 //-------------------------------------------------------------------------- 00429 void plD_esc_pdf( PLStream *pls, PLINT op, void *ptr ) 00430 { 00431 switch ( op ) 00432 { 00433 case PLESC_FILL: // fill polygon 00434 poly_line( pls, pls->dev_x, pls->dev_y, pls->dev_npts, 1 ); 00435 break; 00436 case PLESC_HAS_TEXT: // render text 00437 process_string( pls, (EscText *) ptr ); 00438 break; 00439 } 00440 } 00441 00442 00443 //-------------------------------------------------------------------------- 00444 // poly_line() 00445 // 00446 // Handles drawing filled and unfilled polygons 00447 //-------------------------------------------------------------------------- 00448 void poly_line( PLStream *pls, short *xa, short *ya, PLINT npts, short fill ) 00449 { 00450 pdfdev* dev = (pdfdev *) pls->dev; 00451 PLINT i; 00452 00453 HPDF_Page_SetLineWidth( dev->page, (HPDF_REAL) ( pls->width ) ); 00454 HPDF_Page_SetLineCap( dev->page, HPDF_ROUND_END ); 00455 HPDF_Page_SetLineJoin( dev->page, HPDF_ROUND_JOIN ); 00456 HPDF_Page_SetRGBStroke( dev->page, (HPDF_REAL) ( pls->curcolor.r / 255.0 ), 00457 (HPDF_REAL) ( pls->curcolor.g / 255.0 ), (HPDF_REAL) ( pls->curcolor.b / 255.0 ) ); 00458 HPDF_Page_SetRGBFill( dev->page, (HPDF_REAL) ( pls->curcolor.r / 255.0 ), 00459 (HPDF_REAL) ( pls->curcolor.g / 255.0 ), (HPDF_REAL) ( pls->curcolor.b / 255.0 ) ); 00460 00461 HPDF_Page_MoveTo( dev->page, (HPDF_REAL) xa[0], (HPDF_REAL) ya[0] ); 00462 for ( i = 1; i < npts; i++ ) 00463 HPDF_Page_LineTo( dev->page, (HPDF_REAL) xa[i], (HPDF_REAL) ya[i] ); 00464 00465 if ( fill == 1 ) 00466 { 00467 if ( pls->dev_eofill ) 00468 HPDF_Page_EofillStroke( dev->page ); 00469 else 00470 HPDF_Page_FillStroke( dev->page ); 00471 } 00472 else 00473 { 00474 HPDF_Page_Stroke( dev->page ); 00475 } 00476 } 00477 00478 00479 //-------------------------------------------------------------------------- 00480 // unsigned char plunicode2type1 (const PLUNICODE index, 00481 // const Unicode_to_Type1_table lookup[], const int number_of_entries) 00482 // 00483 // Function takes an input unicode index, looks through the lookup 00484 // table (which must be sorted by PLUNICODE Unicode), then returns the 00485 // corresponding Type1 code in the lookup table. If the Unicode index 00486 // is not present the returned value is 32 (which is normally a blank 00487 // for Type 1 fonts). 00488 //-------------------------------------------------------------------------- 00489 static unsigned char plunicode2type1( const PLUNICODE index, 00490 const Unicode_to_Type1_table lookup[], 00491 const int nlookup ) 00492 { 00493 int jlo = -1, jmid, jhi = nlookup; 00494 00495 while ( jhi - jlo > 1 ) 00496 { 00497 // Note that although jlo or jhi can be just outside valid 00498 // range (see initialization above) because of while condition 00499 // jlo < jmid < jhi and jmid must be in valid range. 00500 // 00501 jmid = ( jlo + jhi ) / 2; 00502 if ( index > lookup[jmid].Unicode ) 00503 jlo = jmid; 00504 else if ( index < lookup[jmid].Unicode ) 00505 jhi = jmid; 00506 else 00507 // We have found it! 00508 // index == lookup[jmid].Unicode 00509 // 00510 return ( lookup[jmid].Type1 ); 00511 } 00512 // jlo is invalid or it is valid and index > lookup[jlo].Unicode. 00513 // jhi is invalid or it is valid and index < lookup[jhi].Unicode. 00514 // All these conditions together imply index cannot be found in lookup. 00515 // Mark with ' ' (which is normally the index for blank in type 1 fonts). 00516 // 00517 return ( ' ' ); 00518 } 00519 00520 00521 //-------------------------------------------------------------------------- 00522 // PSDrawTextToCanvas( pdfdev* dev, unsigned char* type1_string, short drawText ) 00523 // 00524 // This function determines the extent of the string and does 00525 // the actual drawing to the page if drawText is true. 00526 //-------------------------------------------------------------------------- 00527 void PSDrawTextToCanvas( pdfdev* dev, unsigned char* type1_string, short drawText ) 00528 { 00529 HPDF_REAL th; 00530 00531 // write text to page 00532 if ( drawText ) 00533 { 00534 HPDF_Page_BeginText( dev->page ); 00535 HPDF_Page_SetTextRenderingMode( dev->page, HPDF_FILL ); 00536 HPDF_Page_SetRGBFill( dev->page, dev->textRed, dev->textGreen, dev->textBlue ); 00537 HPDF_Page_MoveTextPos( dev->page, dev->textWidth, dev->yOffset ); 00538 HPDF_Page_ShowText( dev->page, (char *) type1_string ); // TODO: this conversion must be wrong 00539 HPDF_Page_EndText( dev->page ); 00540 } 00541 00542 // determine text width and height 00543 dev->textWidth += HPDF_Page_TextWidth( dev->page, (char *) type1_string ); // TODO: this conversion must be wrong 00544 th = (HPDF_REAL) ( (HPDF_REAL) HPDF_Font_GetCapHeight( dev->m_font ) * dev->fontSize * dev->fontScale / 1000.0 ); 00545 dev->textHeight = dev->textHeight > ( th + dev->yOffset ) ? dev->textHeight : ( th + dev->yOffset ); 00546 00547 // clear string 00548 memset( type1_string, '\0', MAX_STRING_LEN ); 00549 } 00550 00551 00552 //-------------------------------------------------------------------------- 00553 // PSSetFont( pdfdev* dev, PLUNICODE fci ) 00554 // 00555 // Sets the font. 00556 //-------------------------------------------------------------------------- 00557 void PSSetFont( pdfdev* dev, PLUNICODE fci ) 00558 { 00559 const char *font; 00560 00561 // fci = 0 is a special value indicating the Type 1 Symbol font 00562 // is desired. This value cannot be confused with a normal FCI value 00563 // because it doesn't have the PL_FCI_MARK. 00564 if ( fci == 0 ) 00565 { 00566 font = "Symbol"; 00567 dev->nlookup = number_of_entries_in_unicode_to_symbol_table; 00568 dev->lookup = unicode_to_symbol_lookup_table; 00569 dev->if_symbol_font = 1; 00570 } 00571 else 00572 { 00573 // convert the fci to Base14/Type1 font information 00574 font = plP_FCI2FontName( fci, Type1Lookup, N_Type1Lookup ); 00575 dev->nlookup = number_of_entries_in_unicode_to_standard_table; 00576 dev->lookup = unicode_to_standard_lookup_table; 00577 dev->if_symbol_font = 0; 00578 } 00579 00580 if ( !( dev->m_font = HPDF_GetFont( dev->pdf, font, NULL ) ) ) 00581 plexit( "ERROR: Couldn't open font\n" ); 00582 //pldebug( "PSSetFont", "HPDF requested font size = %f\n", dev->fontSize * dev->fontScale ); 00583 HPDF_Page_SetFontAndSize( dev->page, dev->m_font, dev->fontSize * dev->fontScale ); 00584 } 00585 00586 // 0.8 should mimic the offset of first superscript/subscript level 00587 // implemented in plstr (plsym.c) for Hershey fonts. However, when 00588 // comparing with -dev xwin and -dev xcairo results changing this 00589 // factor to 0.6 appears to offset the centers of the letters 00590 // appropriately while 0.8 gives much poorer agreement with the 00591 // other devices. 00592 # define RISE_FACTOR 0.6 00593 00594 //-------------------------------------------------------------------------- 00595 // PSDrawText( pdfdev* dev, PLUNICODE* ucs4, int ucs4Len, short drawText ) 00596 // 00597 // This function is called twice, first to determine the extent of the 00598 // text written to the page and then a second time to actually draw 00599 // the text. 00600 //-------------------------------------------------------------------------- 00601 void PSDrawText( pdfdev* dev, PLUNICODE* ucs4, int ucs4Len, short drawText ) 00602 { 00603 int i, s; 00604 unsigned char type1_string[MAX_STRING_LEN]; 00605 char plplotEsc; 00606 PLUNICODE fci; 00607 int last_chance = 0; 00608 PLFLT old_sscale, sscale, old_soffset, soffset, dup; 00609 PLINT level = 0; 00610 00611 memset( type1_string, '\0', MAX_STRING_LEN ); 00612 00613 // Get PLplot escape character 00614 plgesc( &plplotEsc ); 00615 00616 // Get the current font 00617 dev->fontScale = 1.0; 00618 dev->yOffset = 0.0; 00619 plgfci( &fci ); 00620 PSSetFont( dev, fci ); 00621 dev->textWidth = 0; 00622 dev->textHeight = 0; 00623 00624 i = 0; s = 0; 00625 while ( i < ucs4Len ) 00626 { 00627 if ( ucs4[i] < PL_FCI_MARK ) // not a font change 00628 { 00629 if ( ucs4[i] != (PLUNICODE) plplotEsc ) // a character to display 00630 { 00631 type1_string[s] = plunicode2type1( ucs4[i], dev->lookup, dev->nlookup ); 00632 if ( ucs4[i] != ' ' && type1_string[s] == ' ' ) 00633 { 00634 // failed lookup 00635 if ( !dev->if_symbol_font ) 00636 { 00637 // failed standard font lookup. Try "last chance" 00638 // symbol font instead. 00639 type1_string[s] = '\0'; 00640 PSDrawTextToCanvas( dev, type1_string, drawText ); 00641 s = 0; 00642 last_chance = 1; 00643 PSSetFont( dev, 0 ); 00644 continue; 00645 } 00646 else if ( !last_chance ) 00647 { 00648 // failed symbol font lookup that is not right 00649 // after a failed standard font lookup (i.e., 00650 // last_change = 0). Try standard fonts lookup instead. 00651 type1_string[s] = '\0'; 00652 PSDrawTextToCanvas( dev, type1_string, drawText ); 00653 s = 0; 00654 last_chance = 0; 00655 PSSetFont( dev, fci ); 00656 continue; 00657 } 00658 else 00659 { 00660 // failed "last_chance" symbol font lookup that 00661 // has occurred right after a failed standard 00662 // fonts lookup. Just accept blank result and 00663 // move on using standard fonts. 00664 PSDrawTextToCanvas( dev, type1_string, drawText ); 00665 s = 0; 00666 last_chance = 0; 00667 PSSetFont( dev, fci ); 00668 i++; 00669 continue; 00670 } 00671 } 00672 else 00673 { 00674 // font lookup succeeded. 00675 s++; 00676 i++; 00677 last_chance = 0; 00678 continue; 00679 } 00680 } 00681 i++; 00682 if ( ucs4[i] == (PLUNICODE) plplotEsc ) // a escape character to display 00683 { 00684 type1_string[s] = plunicode2type1( ucs4[i], dev->lookup, dev->nlookup ); 00685 if ( ucs4[i] != ' ' && type1_string[s] == ' ' ) 00686 { 00687 // failed lookup 00688 if ( !dev->if_symbol_font ) 00689 { 00690 // failed standard font lookup. Try "last chance" 00691 // symbol font instead. 00692 type1_string[s] = '\0'; 00693 PSDrawTextToCanvas( dev, type1_string, drawText ); 00694 s = 0; 00695 last_chance = 1; 00696 PSSetFont( dev, 0 ); 00697 continue; 00698 } 00699 else if ( !last_chance ) 00700 { 00701 // failed symbol font lookup that is not right 00702 // after a failed standard font lookup (i.e., 00703 // last_change = 0). Try standard fonts lookup instead. 00704 type1_string[s] = '\0'; 00705 PSDrawTextToCanvas( dev, type1_string, drawText ); 00706 s = 0; 00707 last_chance = 0; 00708 PSSetFont( dev, fci ); 00709 continue; 00710 } 00711 else 00712 { 00713 // failed "last_chance" symbol font lookup that 00714 // has occurred right after a failed standard 00715 // fonts lookup. Just accept blank result and 00716 // move on using standard fonts. 00717 PSDrawTextToCanvas( dev, type1_string, drawText ); 00718 s = 0; 00719 last_chance = 0; 00720 PSSetFont( dev, fci ); 00721 i++; 00722 continue; 00723 } 00724 } 00725 else 00726 { 00727 // font lookup succeeded. 00728 s++; 00729 i++; 00730 last_chance = 0; 00731 continue; 00732 } 00733 } 00734 else 00735 { 00736 if ( ucs4[i] == (PLUNICODE) 'u' ) // Superscript 00737 { 00738 // draw string so far 00739 PSDrawTextToCanvas( dev, type1_string, drawText ); 00740 s = 0; 00741 00742 plP_script_scale( TRUE, &level, 00743 &old_sscale, &sscale, &old_soffset, &soffset ); 00744 // The correction for the difference in magnitude 00745 // between the baseline and middle coordinate systems 00746 // for superscripts should be 00747 // 0.5*(base font size - superscript/subscript font size). 00748 dup = 0.5 * ( 1.0 - sscale ); 00749 dev->fontScale = (HPDF_REAL) sscale; 00750 PSSetFont( dev, fci ); 00751 dev->yOffset = (HPDF_REAL) ( dev->fontSize * ( soffset * RISE_FACTOR + dup ) ); 00752 } 00753 if ( ucs4[i] == (PLUNICODE) 'd' ) // Subscript 00754 { 00755 // draw string so far 00756 PSDrawTextToCanvas( dev, type1_string, drawText ); 00757 s = 0; 00758 00759 plP_script_scale( FALSE, &level, 00760 &old_sscale, &sscale, &old_soffset, &soffset ); 00761 // The correction for the difference in magnitude 00762 // between the baseline and middle coordinate systems 00763 // for subcripts should be 00764 // 0.5*(base font size - superscript/subscript font size). 00765 dup = -0.5 * ( 1.0 - sscale ); 00766 dev->fontScale = (HPDF_REAL) sscale; 00767 PSSetFont( dev, fci ); 00768 dev->yOffset = (HPDF_REAL) ( -dev->fontSize * ( soffset * RISE_FACTOR + dup ) ); 00769 } 00770 if ( ucs4[i] == (PLUNICODE) '-' ) // underline 00771 { // draw string so far 00772 PSDrawTextToCanvas( dev, type1_string, drawText ); 00773 s = 0; 00774 00775 // dev->underlined = !dev->underlined; 00776 PSSetFont( dev, fci ); 00777 } 00778 if ( ucs4[i] == (PLUNICODE) '+' ) // overline 00779 { // not implemented yet 00780 } 00781 i++; 00782 } 00783 } 00784 else // a font change 00785 { 00786 // draw string so far 00787 PSDrawTextToCanvas( dev, type1_string, drawText ); 00788 s = 0; 00789 00790 // get new font 00791 fci = ucs4[i]; 00792 PSSetFont( dev, fci ); 00793 i++; 00794 } 00795 } 00796 00797 PSDrawTextToCanvas( dev, type1_string, drawText ); 00798 } 00799 00800 00801 //-------------------------------------------------------------------------- 00802 // process_string( PLStream* pls, EscText* args ) 00803 // 00804 // Handles the output of the text on the page. 00805 //-------------------------------------------------------------------------- 00806 void process_string( PLStream* pls, EscText* args ) 00807 { 00808 pdfdev * dev = (pdfdev *) pls->dev; 00809 PLFLT rotation, shear, stride; 00810 HPDF_REAL cos_rot, sin_rot, cos_shear, sin_shear; 00811 00812 // Check that we got unicode, warning message and return if not 00813 if ( args->unicode_array_len == 0 ) 00814 { 00815 printf( "Non unicode string passed to a pdf driver, ignoring\n" ); 00816 return; 00817 } 00818 00819 // Check that unicode string isn't longer then the max we allow 00820 if ( args->unicode_array_len >= MAX_STRING_LEN ) 00821 { 00822 printf( "Sorry, the pdf drivers only handles strings of length < %d\n", MAX_STRING_LEN ); 00823 return; 00824 } 00825 00826 // Calculate the font size (in pixels) 00827 dev->fontSize = (HPDF_REAL) ( pls->chrht * DEVICE_PIXELS_PER_INCH / 25.4 * 1.6 ); 00828 00829 // text color 00830 dev->textRed = (HPDF_REAL) ( pls->curcolor.r / 255.0 ); 00831 dev->textGreen = (HPDF_REAL) ( pls->curcolor.g / 255.0 ); 00832 dev->textBlue = (HPDF_REAL) ( pls->curcolor.b / 255.0 ); 00833 00834 // calculate transformation matrix (rotation and shear of text) 00835 plRotationShear( args->xform, &rotation, &shear, &stride ); 00836 rotation -= pls->diorot * M_PI / 2.0; 00837 cos_rot = (HPDF_REAL) cos( rotation ); 00838 sin_rot = (HPDF_REAL) sin( rotation ); 00839 cos_shear = (HPDF_REAL) cos( shear ); 00840 sin_shear = (HPDF_REAL) sin( shear ); 00841 00842 // calculate text extend -> stored in dev->textWidth and dev->textHeight 00843 PSDrawText( dev, args->unicode_array, args->unicode_array_len, 0 ); 00844 00845 // apply transformation matrix and draw text 00846 HPDF_Page_GSave( dev->page ); 00847 HPDF_Page_Concat( dev->page, cos_rot, sin_rot, 00848 -cos_rot * sin_shear - sin_rot * cos_shear, 00849 -sin_rot * sin_shear + cos_rot * cos_shear, 00850 (HPDF_REAL) ( args->x ), (HPDF_REAL) ( args->y ) ); 00851 HPDF_Page_Concat( dev->page, (HPDF_REAL) 1.0, (HPDF_REAL) 0.0, (HPDF_REAL) 0.0, (HPDF_REAL) 1.0, 00852 (HPDF_REAL) ( -args->just * dev->textWidth ), (HPDF_REAL) ( -0.5 * dev->textHeight ) ); 00853 PSDrawText( dev, args->unicode_array, args->unicode_array_len, 1 ); 00854 HPDF_Page_GRestore( dev->page ); 00855 } 00856 00857 #else 00858 00859 //-------------------------------------------------------------------------- 00860 // pldummy_pdf() 00861 // 00862 // Dummy function if driver should not be available. 00863 //-------------------------------------------------------------------------- 00864 int pldummy_pdf() 00865 { 00866 return 0; 00867 } 00868 00869 #endif // PLD_pdf 00870