PLplot  5.10.0
pdf.c
Go to the documentation of this file.
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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines