• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

pdf.c

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

Generated on Wed Oct 12 2011 20:42:22 for PLplot by  doxygen 1.7.1