00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include <stdarg.h>
00030 #include <math.h>
00031
00032
00033
00034 #include "plplotP.h"
00035 #include "drivers.h"
00036
00037
00038
00039 #define SVG_Default_X 720
00040 #define SVG_Default_Y 540
00041
00042 #define POINTS_PER_INCH 72
00043
00044 #define MAX_STRING_LEN 1000
00045
00046
00047
00048
00049 #define FONT_SIZE_RATIO 1.34
00050 #define FONT_SHIFT_RATIO 0.705
00051 #define FONT_SHIFT_OFFSET 0.5
00052
00053
00054
00055 PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_svg = "svg:Scalable Vector Graphics (SVG 1.1):1:svg:57:svg\n";
00056
00057 static int already_warned = 0;
00058
00059 static int text_clipping = 1;
00060 static DrvOpt svg_options[] = { { "text_clipping", DRV_INT, &text_clipping, "Use text clipping (text_clipping=0|1)" } };
00061
00062 typedef struct
00063 {
00064 short textClipping;
00065 int canvasXSize;
00066 int canvasYSize;
00067 PLFLT scale;
00068 int svgIndent;
00069 FILE *svgFile;
00070 int gradient_index;
00071
00072 } SVG;
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084 static void svg_open( SVG *, char * );
00085 static void svg_open_end( SVG * );
00086 static void svg_attr_value( SVG *, char *, char * );
00087 static void svg_attr_values( SVG *, char *, char *, ... );
00088 static void svg_close( SVG *, char * );
00089 static void svg_general( SVG *, char * );
00090 static void svg_indent( SVG * );
00091 static void svg_stroke_width( PLStream * );
00092 static void svg_stroke_color( PLStream * );
00093 static void svg_fill_color( PLStream * );
00094 static void svg_fill_background_color( PLStream * );
00095 static int svg_family_check( PLStream * );
00096
00097
00098
00099
00100 static void poly_line( PLStream *, short *, short *, PLINT, short );
00101 static void gradient( PLStream *, short *, short *, PLINT );
00102 static void write_hex( FILE *, unsigned char );
00103 static void write_unicode( FILE *, PLUNICODE );
00104 static void specify_font( FILE *, PLUNICODE );
00105
00106
00107
00108 static void proc_str( PLStream *, EscText * );
00109
00110
00111
00112 void plD_dispatch_init_svg( PLDispatchTable *pdt );
00113 void plD_init_svg( PLStream * );
00114 void plD_line_svg( PLStream *, short, short, short, short );
00115 void plD_polyline_svg( PLStream *, short *, short *, PLINT );
00116 void plD_eop_svg( PLStream * );
00117 void plD_bop_svg( PLStream * );
00118 void plD_tidy_svg( PLStream * );
00119 void plD_state_svg( PLStream *, PLINT );
00120 void plD_esc_svg( PLStream *, PLINT, void * );
00121
00122
00123
00124
00125
00126
00127
00128 void plD_dispatch_init_svg( PLDispatchTable *pdt )
00129 {
00130 #ifndef ENABLE_DYNDRIVERS
00131 pdt->pl_MenuStr = "Scalable Vector Graphics (SVG 1.1)";
00132 pdt->pl_DevName = "svg";
00133 #endif
00134 pdt->pl_type = plDevType_FileOriented;
00135 pdt->pl_seq = 57;
00136 pdt->pl_init = (plD_init_fp) plD_init_svg;
00137 pdt->pl_line = (plD_line_fp) plD_line_svg;
00138 pdt->pl_polyline = (plD_polyline_fp) plD_polyline_svg;
00139 pdt->pl_eop = (plD_eop_fp) plD_eop_svg;
00140 pdt->pl_bop = (plD_bop_fp) plD_bop_svg;
00141 pdt->pl_tidy = (plD_tidy_fp) plD_tidy_svg;
00142 pdt->pl_state = (plD_state_fp) plD_state_svg;
00143 pdt->pl_esc = (plD_esc_fp) plD_esc_svg;
00144 }
00145
00146
00147
00148
00149
00150
00151
00152 void plD_init_svg( PLStream *pls )
00153 {
00154 SVG *aStream;
00155
00156 pls->termin = 0;
00157 pls->color = 1;
00158 pls->width = 1;
00159 pls->verbose = 1;
00160 pls->bytecnt = 0;
00161
00162 pls->dev_text = 1;
00163 pls->dev_unicode = 1;
00164 pls->page = 0;
00165 pls->dev_fill0 = 1;
00166 pls->dev_fill1 = 0;
00167 pls->dev_gradient = 1;
00168
00169 pls->graphx = GRAPHICS_MODE;
00170
00171 if ( !pls->colorset )
00172 pls->color = 1;
00173
00174
00175 plFamInit( pls );
00176
00177
00178 plOpenFile( pls );
00179
00180
00181 if ( pls->dev != NULL )
00182 free( (void *) pls->dev );
00183
00184 pls->dev = calloc( 1, (size_t) sizeof ( SVG ) );
00185 if ( pls->dev == NULL )
00186 plexit( "plD_init_svg: Out of memory." );
00187
00188 aStream = (SVG *) pls->dev;
00189
00190
00191
00192 if ( pls->xlength <= 0 || pls->ylength <= 0 )
00193 {
00194 aStream->canvasXSize = SVG_Default_X;
00195 aStream->canvasYSize = SVG_Default_Y;
00196 }
00197 else
00198 {
00199 aStream->canvasXSize = pls->xlength;
00200 aStream->canvasYSize = pls->ylength;
00201 }
00202
00203
00204 if ( aStream->canvasXSize > aStream->canvasYSize )
00205 aStream->scale = (PLFLT) ( PIXELS_X - 1 ) / (PLFLT) aStream->canvasXSize;
00206 else
00207 aStream->scale = (PLFLT) PIXELS_Y / (PLFLT) aStream->canvasYSize;
00208 plP_setphy( (PLINT) 0, (PLINT) ( aStream->scale * aStream->canvasXSize ), (PLINT) 0, (PLINT) ( aStream->scale * aStream->canvasYSize ) );
00209
00210 plP_setpxl( aStream->scale * POINTS_PER_INCH / 25.4, aStream->scale * POINTS_PER_INCH / 25.4 );
00211
00212 aStream->svgFile = pls->OutFile;
00213
00214
00215 plParseDrvOpts( svg_options );
00216
00217
00218 if ( text_clipping )
00219 {
00220 aStream->textClipping = 1;
00221 }
00222 aStream->textClipping = text_clipping;
00223
00224 aStream->svgIndent = 0;
00225 aStream->gradient_index = 0;
00226 svg_general( aStream, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
00227 svg_general( aStream, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n" );
00228 svg_general( aStream, " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n" );
00229 }
00230
00231
00232
00233
00234
00235
00236
00237 void plD_bop_svg( PLStream *pls )
00238 {
00239 SVG *aStream;
00240
00241
00242 plGetFam( pls );
00243
00244
00245
00246 aStream = pls->dev;
00247
00248 pls->famadv = 1;
00249 pls->page++;
00250 if ( svg_family_check( pls ) )
00251 {
00252 return;
00253 }
00254
00255
00256
00257 svg_open( aStream, "svg" );
00258 svg_attr_value( aStream, "xmlns", "http://www.w3.org/2000/svg" );
00259 svg_attr_value( aStream, "xmlns:xlink", "http://www.w3.org/1999/xlink" );
00260 svg_attr_value( aStream, "version", "1.1" );
00261
00262
00263 svg_attr_values( aStream, "width", "%dpt", aStream->canvasXSize );
00264 svg_attr_values( aStream, "height", "%dpt", aStream->canvasYSize );
00265 svg_attr_values( aStream, "viewBox", "%d %d %d %d", 0, 0, aStream->canvasXSize, aStream->canvasYSize );
00266 svg_general( aStream, ">\n" );
00267
00268
00269
00270
00271 svg_open( aStream, "rect" );
00272 svg_attr_values( aStream, "x", "%d", 0 );
00273 svg_attr_values( aStream, "y", "%d", 0 );
00274 svg_attr_values( aStream, "width", "%d", aStream->canvasXSize );
00275 svg_attr_values( aStream, "height", "%d", aStream->canvasYSize );
00276 svg_attr_value( aStream, "stroke", "none" );
00277 svg_fill_background_color( pls );
00278 svg_open_end( aStream );
00279
00280
00281
00282 svg_open( aStream, "g" );
00283 svg_attr_values( aStream, "transform", "matrix(1 0 0 -1 0 %d)", aStream->canvasYSize );
00284 svg_general( aStream, ">\n" );
00285 }
00286
00287
00288
00289
00290
00291
00292
00293 void plD_line_svg( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
00294 {
00295 SVG *aStream;
00296
00297 aStream = pls->dev;
00298
00299 if ( svg_family_check( pls ) )
00300 {
00301 return;
00302 }
00303 svg_open( aStream, "polyline" );
00304 svg_stroke_width( pls );
00305 svg_stroke_color( pls );
00306 svg_attr_value( aStream, "fill", "none" );
00307
00308 svg_attr_values( aStream, "points", "%r,%r %r,%r", (double) x1a / aStream->scale, (double) y1a / aStream->scale, (double) x2a / aStream->scale, (double) y2a / aStream->scale );
00309 svg_open_end( aStream );
00310 }
00311
00312
00313
00314
00315
00316
00317
00318 void plD_polyline_svg( PLStream *pls, short *xa, short *ya, PLINT npts )
00319 {
00320 if ( svg_family_check( pls ) )
00321 {
00322 return;
00323 }
00324 poly_line( pls, xa, ya, npts, 0 );
00325 }
00326
00327
00328
00329
00330
00331
00332
00333 void plD_eop_svg( PLStream *pls )
00334 {
00335 SVG *aStream;
00336
00337 aStream = pls->dev;
00338
00339 if ( svg_family_check( pls ) )
00340 {
00341 return;
00342 }
00343
00344
00345 svg_close( aStream, "g" );
00346 svg_close( aStream, "svg" );
00347 }
00348
00349
00350
00351
00352
00353
00354
00355 void plD_tidy_svg( PLStream *pls )
00356 {
00357 SVG *aStream;
00358
00359 aStream = pls->dev;
00360 if ( svg_family_check( pls ) )
00361 {
00362 return;
00363 }
00364 plCloseFile( pls );
00365 }
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376 void plD_state_svg( PLStream *pls, PLINT op )
00377 {
00378 }
00379
00380
00381
00382
00383
00384
00385
00386 void plD_esc_svg( PLStream *pls, PLINT op, void *ptr )
00387 {
00388 if ( svg_family_check( pls ) )
00389 {
00390 return;
00391 }
00392 switch ( op )
00393 {
00394 case PLESC_FILL:
00395 poly_line( pls, pls->dev_x, pls->dev_y, pls->dev_npts, 1 );
00396 break;
00397 case PLESC_GRADIENT:
00398 gradient( pls, pls->dev_x, pls->dev_y, pls->dev_npts );
00399 break;
00400 case PLESC_HAS_TEXT:
00401 proc_str( pls, (EscText *) ptr );
00402 break;
00403 }
00404 }
00405
00406
00407
00408
00409
00410
00411
00412 void poly_line( PLStream *pls, short *xa, short *ya, PLINT npts, short fill )
00413 {
00414 int i;
00415 SVG *aStream;
00416
00417 aStream = pls->dev;
00418
00419 svg_open( aStream, "polyline" );
00420 if ( fill )
00421 {
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432 if ( pls->curcolor.a < 0.99 )
00433 {
00434 svg_attr_value( aStream, "stroke", "none" );
00435 }
00436 else
00437 {
00438 svg_stroke_width( pls );
00439 svg_stroke_color( pls );
00440 }
00441 svg_fill_color( pls );
00442 if ( pls->dev_eofill )
00443 svg_attr_value( aStream, "fill-rule", "evenodd" );
00444 else
00445 svg_attr_value( aStream, "fill-rule", "nonzero" );
00446 }
00447 else
00448 {
00449 svg_stroke_width( pls );
00450 svg_stroke_color( pls );
00451 svg_attr_value( aStream, "fill", "none" );
00452 }
00453
00454 svg_indent( aStream );
00455 fprintf( aStream->svgFile, "points=\"" );
00456 for ( i = 0; i < npts; i++ )
00457 {
00458 fprintf( aStream->svgFile, "%.2f,%.2f ", (double) xa[i] / aStream->scale, (double) ya[i] / aStream->scale );
00459 if ( ( ( i + 1 ) % 10 ) == 0 )
00460 {
00461 fprintf( aStream->svgFile, "\n" );
00462 svg_indent( aStream );
00463 }
00464 }
00465 fprintf( aStream->svgFile, "\"/>\n" );
00466 aStream->svgIndent -= 2;
00467 }
00468
00469
00470
00471
00472
00473
00474
00475 void gradient( PLStream *pls, short *xa, short *ya, PLINT npts )
00476 {
00477 int i;
00478
00479 char buffer[50];
00480 SVG *aStream;
00481
00482 aStream = pls->dev;
00483
00484 svg_open( aStream, "g>" );
00485 svg_open( aStream, "defs>" );
00486 svg_open( aStream, "linearGradient" );
00487
00488 sprintf( buffer, "MyGradient%010d", aStream->gradient_index );
00489 svg_attr_value( aStream, "id", buffer );
00490 svg_attr_value( aStream, "gradientUnits", "userSpaceOnUse" );
00491 sprintf( buffer, "%.2f", pls->xgradient[0] / aStream->scale );
00492 svg_attr_value( aStream, "x1", buffer );
00493 sprintf( buffer, "%.2f", pls->ygradient[0] / aStream->scale );
00494 svg_attr_value( aStream, "y1", buffer );
00495 sprintf( buffer, "%.2f", pls->xgradient[1] / aStream->scale );
00496 svg_attr_value( aStream, "x2", buffer );
00497 sprintf( buffer, "%.2f", pls->ygradient[1] / aStream->scale );
00498 svg_attr_value( aStream, "y2", buffer );
00499 svg_general( aStream, ">\n" );
00500
00501 for ( i = 0; i < pls->ncol1; i++ )
00502 {
00503 svg_indent( aStream );
00504 fprintf( aStream->svgFile, "<stop offset=\"%.3f\" ",
00505 (double) i / (double) ( pls->ncol1 - 1 ) );
00506 fprintf( aStream->svgFile, "stop-color=\"#" );
00507 write_hex( aStream->svgFile, pls->cmap1[i].r );
00508 write_hex( aStream->svgFile, pls->cmap1[i].g );
00509 write_hex( aStream->svgFile, pls->cmap1[i].b );
00510 fprintf( aStream->svgFile, "\" " );
00511 fprintf( aStream->svgFile, "stop-opacity=\"%.3f\"/>\n", pls->cmap1[i].a );
00512 }
00513
00514 svg_close( aStream, "linearGradient" );
00515 svg_close( aStream, "defs" );
00516 svg_open( aStream, "polyline" );
00517 sprintf( buffer, "url(#MyGradient%010d)", aStream->gradient_index++ );
00518 svg_attr_value( aStream, "fill", buffer );
00519 svg_indent( aStream );
00520 fprintf( aStream->svgFile, "points=\"" );
00521 for ( i = 0; i < npts; i++ )
00522 {
00523 fprintf( aStream->svgFile, "%.2f,%.2f ", (double) xa[i] / aStream->scale, (double) ya[i] / aStream->scale );
00524 if ( ( ( i + 1 ) % 10 ) == 0 )
00525 {
00526 fprintf( aStream->svgFile, "\n" );
00527 svg_indent( aStream );
00528 }
00529 }
00530 fprintf( aStream->svgFile, "\"/>\n" );
00531 aStream->svgIndent -= 2;
00532 svg_close( aStream, "g" );
00533 }
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564 void proc_str( PLStream *pls, EscText *args )
00565 {
00566 char plplot_esc;
00567 short static which_clip = 0;
00568 short i;
00569 short totalTags = 1;
00570 short ucs4Len = args->unicode_array_len;
00571 double ftHt, scaled_offset, scaled_ftHt;
00572 PLUNICODE fci;
00573 PLINT rcx[4], rcy[4];
00574 PLFLT rotation, shear, stride, cos_rot, sin_rot, sin_shear, cos_shear;
00575 PLFLT t[4];
00576 int glyph_size, sum_glyph_size;
00577 short if_write;
00578
00579 PLUNICODE *ucs4 = args->unicode_array;
00580 SVG *aStream;
00581 PLFLT old_sscale, sscale, old_soffset, soffset, old_dup, dup;
00582 PLINT level;
00583
00584
00585 if ( ucs4Len == 0 )
00586 {
00587 printf( "Non unicode string passed to SVG driver, ignoring\n" );
00588 return;
00589 }
00590
00591
00592 plgesc( &plplot_esc );
00593 plgfci( &fci );
00594
00595
00596 ftHt = FONT_SIZE_RATIO * pls->chrht * POINTS_PER_INCH / 25.4;
00597
00598
00599 aStream = (SVG *) pls->dev;
00600 if ( aStream->textClipping )
00601 {
00602 svg_open( aStream, "clipPath" );
00603 svg_attr_values( aStream, "id", "text-clipping%d", which_clip );
00604 svg_general( aStream, ">\n" );
00605
00606
00607
00608 difilt_clip( rcx, rcy );
00609
00610
00611 svg_open( aStream, "polygon" );
00612 svg_attr_values( aStream,
00613 "points",
00614 "%f,%f %f,%f %f,%f %f,%f",
00615 ( (PLFLT) rcx[0] ) / aStream->scale,
00616 ( (PLFLT) rcy[0] ) / aStream->scale,
00617 ( (PLFLT) rcx[1] ) / aStream->scale,
00618 ( (PLFLT) rcy[1] ) / aStream->scale,
00619 ( (PLFLT) rcx[2] ) / aStream->scale,
00620 ( (PLFLT) rcy[2] ) / aStream->scale,
00621 ( (PLFLT) rcx[3] ) / aStream->scale,
00622 ( (PLFLT) rcy[3] ) / aStream->scale );
00623 svg_open_end( aStream );
00624
00625 svg_close( aStream, "clipPath" );
00626 svg_open( aStream, "g" );
00627 svg_attr_values( aStream, "clip-path", "url(#text-clipping%d)", which_clip );
00628 svg_general( aStream, ">\n" );
00629
00630 which_clip++;
00631 }
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657 plRotationShear( args->xform, &rotation, &shear, &stride );
00658
00659
00660
00661 rotation -= pls->diorot * PI / 2.0;
00662 cos_rot = cos( rotation );
00663 sin_rot = -sin( rotation );
00664 sin_shear = sin( shear );
00665 cos_shear = -cos( shear );
00666 t[0] = cos_rot * stride;
00667 t[1] = -sin_rot * stride;
00668 t[2] = cos_rot * sin_shear + sin_rot * cos_shear;
00669 t[3] = -sin_rot * sin_shear + cos_rot * cos_shear;
00670
00671
00672
00673 svg_open( aStream, "g" );
00674 svg_attr_values( aStream, "transform", "matrix(%f %f %f %f %f %f)", t[0], t[1], t[2], t[3], (double) ( args->x / aStream->scale ), (double) ( args->y / aStream->scale ) );
00675 svg_general( aStream, ">\n" );
00676
00677 svg_open( aStream, "g" );
00678 svg_attr_values( aStream, "transform", "matrix(1.0 0.0 0.0 1.0 0.0 %f)", FONT_SHIFT_RATIO * 0.5 * ftHt + FONT_SHIFT_OFFSET );
00679 svg_general( aStream, ">\n" );
00680
00681
00682
00683
00684
00685 svg_open( aStream, "text" );
00686
00687 svg_attr_value( aStream, "dominant-baseline", "no-change" );
00688
00689
00690 svg_fill_color( pls );
00691
00692
00693 svg_attr_value( aStream, "xml:space", "preserve" );
00694
00695
00696 svg_attr_values( aStream, "font-size", "%d", (int) ftHt );
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709 glyph_size = (int) ftHt;
00710 sum_glyph_size = 0;
00711 if_write = 0;
00712 while ( if_write < 2 )
00713 {
00714 if ( if_write == 1 )
00715 {
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726 if ( args->just < 0.33 )
00727 {
00728 svg_attr_value( aStream, "text-anchor", "start" );
00729 svg_attr_values( aStream, "x", "%f", (double) ( -args->just * sum_glyph_size ) );
00730 }
00731 else if ( args->just > 0.66 )
00732 {
00733 svg_attr_value( aStream, "text-anchor", "end" );
00734 svg_attr_values( aStream, "x", "%f", (double) ( ( 1. - args->just ) * sum_glyph_size ) );
00735 }
00736 else
00737 {
00738 svg_attr_value( aStream, "text-anchor", "middle" );
00739 svg_attr_values( aStream, "x", "%f", (double) ( ( 0.5 - args->just ) * sum_glyph_size ) );
00740 }
00741
00742
00743
00744 svg_attr_value( aStream, "y", "0" );
00745 fprintf( aStream->svgFile, ">" );
00746
00747
00748 specify_font( aStream->svgFile, fci );
00749 }
00750 i = 0;
00751 scaled_ftHt = ftHt;
00752 level = 0;
00753 dup = 0.;
00754 while ( i < ucs4Len )
00755 {
00756 if ( ucs4[i] < PL_FCI_MARK )
00757 {
00758 if ( ucs4[i] != (PLUNICODE) plplot_esc )
00759 {
00760 if ( if_write )
00761 {
00762 write_unicode( aStream->svgFile, ucs4[i] );
00763 }
00764 else
00765 {
00766 sum_glyph_size += glyph_size;
00767 }
00768 i++;
00769 continue;
00770 }
00771 i++;
00772 if ( ucs4[i] == (PLUNICODE) plplot_esc )
00773 {
00774 if ( if_write )
00775 {
00776 write_unicode( aStream->svgFile, ucs4[i] );
00777 }
00778 else
00779 {
00780 sum_glyph_size += glyph_size;
00781 }
00782 i++;
00783 continue;
00784 }
00785 else
00786 {
00787
00788
00789
00790 if ( ucs4[i] == (PLUNICODE) 'u' )
00791 {
00792 plP_script_scale( TRUE, &level,
00793 &old_sscale, &sscale, &old_soffset, &soffset );
00794
00795
00796
00797
00798 old_dup = dup;
00799 dup = 0.5 * ( 1.0 - sscale );
00800 if ( level <= 0 )
00801 {
00802 scaled_offset = FONT_SHIFT_RATIO * ftHt * ( 0.80 * ( soffset - old_soffset ) - ( dup - old_dup ) );
00803 }
00804 else
00805 {
00806 scaled_offset = -FONT_SHIFT_RATIO * ftHt * ( 0.80 * ( soffset - old_soffset ) + ( dup - old_dup ) );
00807 }
00808 scaled_ftHt = sscale * ftHt;
00809 if ( if_write )
00810 {
00811 totalTags++;
00812 fprintf( aStream->svgFile, "<tspan dy=\"%f\" font-size=\"%d\">", scaled_offset, (int) scaled_ftHt );
00813 }
00814 else
00815 {
00816 glyph_size = (int) scaled_ftHt;
00817 }
00818 }
00819 if ( ucs4[i] == (PLUNICODE) 'd' )
00820 {
00821 plP_script_scale( FALSE, &level,
00822 &old_sscale, &sscale, &old_soffset, &soffset );
00823
00824
00825
00826
00827 old_dup = dup;
00828 dup = 0.5 * ( 1.0 - sscale );
00829 if ( level < 0 )
00830 {
00831 scaled_offset = FONT_SHIFT_RATIO * ftHt * ( 0.80 * ( soffset - old_soffset ) - ( dup - old_dup ) );
00832 }
00833 else
00834 {
00835 scaled_offset = -FONT_SHIFT_RATIO * ftHt * ( 0.80 * ( soffset - old_soffset ) + ( dup - old_dup ) );
00836 }
00837 scaled_ftHt = sscale * ftHt;
00838 if ( if_write )
00839 {
00840 totalTags++;
00841 fprintf( aStream->svgFile, "<tspan dy=\"%f\" font-size=\"%d\">", scaled_offset, (int) scaled_ftHt );
00842 }
00843 else
00844 {
00845 glyph_size = (int) scaled_ftHt;
00846 }
00847 }
00848 i++;
00849 }
00850 }
00851 else
00852 {
00853 if ( if_write )
00854 {
00855 specify_font( aStream->svgFile, ucs4[i] );
00856 totalTags++;
00857 }
00858 i++;
00859 }
00860 }
00861 if_write++;
00862 }
00863
00864
00865
00866
00867
00868 for ( i = 0; i < totalTags; i++ )
00869 {
00870 fprintf( aStream->svgFile, "</tspan>" );
00871 }
00872
00873
00874
00875
00876
00877
00878
00879
00880 fprintf( aStream->svgFile, "</text>\n" );
00881 aStream->svgIndent -= 2;
00882 svg_close( aStream, "g" );
00883 svg_close( aStream, "g" );
00884 if ( aStream->textClipping )
00885 {
00886 svg_close( aStream, "g" );
00887 }
00888 }
00889
00890
00891
00892
00893
00894
00895
00896 void svg_open( SVG *aStream, char *tag )
00897 {
00898 svg_indent( aStream );
00899 fprintf( aStream->svgFile, "<%s\n", tag );
00900 aStream->svgIndent += 2;
00901 }
00902
00903
00904
00905
00906
00907
00908
00909
00910 void svg_open_end( SVG *aStream )
00911 {
00912 svg_indent( aStream );
00913 fprintf( aStream->svgFile, "/>\n" );
00914 aStream->svgIndent -= 2;
00915 }
00916
00917
00918
00919
00920
00921
00922
00923
00924 void svg_attr_value( SVG *aStream, char *attribute, char *value )
00925 {
00926 svg_indent( aStream );
00927 fprintf( aStream->svgFile, "%s=\"%s\"\n", attribute, value );
00928 }
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941 void svg_attr_values( SVG *aStream, char *attribute, char *format, ... )
00942 {
00943 va_list ap;
00944 char *p, *sval;
00945 int ival;
00946 double dval;
00947
00948 svg_indent( aStream );
00949 fprintf( aStream->svgFile, "%s=\"", attribute );
00950 va_start( ap, format );
00951 for ( p = format; *p; p++ )
00952 {
00953 if ( *p != '%' )
00954 {
00955 fprintf( aStream->svgFile, "%c", *p );
00956 continue;
00957 }
00958 switch ( *++p )
00959 {
00960 case 'd':
00961 ival = va_arg( ap, int );
00962 fprintf( aStream->svgFile, "%d", ival );
00963 break;
00964 case 'f':
00965 dval = va_arg( ap, double );
00966 fprintf( aStream->svgFile, "%f", dval );
00967 break;
00968 case 'r':
00969
00970 dval = va_arg( ap, double );
00971 fprintf( aStream->svgFile, "%.2f", dval );
00972 break;
00973 case 's':
00974 sval = va_arg( ap, char * );
00975 fprintf( aStream->svgFile, "%s", sval );
00976 break;
00977 default:
00978 fprintf( aStream->svgFile, "%c", *p );
00979 break;
00980 }
00981 }
00982 fprintf( aStream->svgFile, "\"\n" );
00983 va_end( ap );
00984 }
00985
00986
00987
00988
00989
00990
00991
00992 void svg_close( SVG *aStream, char *tag )
00993 {
00994 aStream->svgIndent -= 2;
00995 svg_indent( aStream );
00996 if ( strlen( tag ) > 0 )
00997 {
00998 fprintf( aStream->svgFile, "</%s>\n", tag );
00999 }
01000 else
01001 {
01002 fprintf( aStream->svgFile, "/>\n" );
01003 }
01004 }
01005
01006
01007
01008
01009
01010
01011
01012 void svg_general( SVG *aStream, char *text )
01013 {
01014 svg_indent( aStream );
01015 fprintf( aStream->svgFile, "%s", text );
01016 }
01017
01018
01019
01020
01021
01022
01023
01024 void svg_indent( SVG *aStream )
01025 {
01026 short i;
01027 for ( i = 0; i < aStream->svgIndent; i++ )
01028 {
01029 fprintf( aStream->svgFile, " " );
01030 }
01031 }
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041 void svg_stroke_width( PLStream *pls )
01042 {
01043 SVG *aStream;
01044
01045 aStream = pls->dev;
01046 svg_indent( aStream );
01047 fprintf( aStream->svgFile, "stroke-width=\"%d\"\n", MAX( 1, pls->width ) );
01048 }
01049
01050
01051
01052
01053
01054
01055
01056 void svg_stroke_color( PLStream *pls )
01057 {
01058 SVG *aStream;
01059
01060 aStream = pls->dev;
01061 svg_indent( aStream );
01062 fprintf( aStream->svgFile, "stroke=\"#" );
01063 write_hex( aStream->svgFile, pls->curcolor.r );
01064 write_hex( aStream->svgFile, pls->curcolor.g );
01065 write_hex( aStream->svgFile, pls->curcolor.b );
01066 fprintf( aStream->svgFile, "\"\n" );
01067 svg_indent( aStream );
01068 fprintf( aStream->svgFile, "stroke-opacity=\"%f\"\n", pls->curcolor.a );
01069 }
01070
01071
01072
01073
01074
01075
01076
01077 void svg_fill_color( PLStream *pls )
01078 {
01079 SVG *aStream;
01080
01081 aStream = pls->dev;
01082 svg_indent( aStream );
01083 fprintf( aStream->svgFile, "fill=\"#" );
01084 write_hex( aStream->svgFile, pls->curcolor.r );
01085 write_hex( aStream->svgFile, pls->curcolor.g );
01086 write_hex( aStream->svgFile, pls->curcolor.b );
01087 fprintf( aStream->svgFile, "\"\n" );
01088 svg_indent( aStream );
01089 fprintf( aStream->svgFile, "fill-opacity=\"%f\"\n", pls->curcolor.a );
01090 }
01091
01092
01093
01094
01095
01096
01097
01098 void svg_fill_background_color( PLStream *pls )
01099 {
01100 SVG *aStream;
01101
01102 aStream = pls->dev;
01103 svg_indent( aStream );
01104 fprintf( aStream->svgFile, "fill=\"#" );
01105 write_hex( aStream->svgFile, pls->cmap0[0].r );
01106 write_hex( aStream->svgFile, pls->cmap0[0].g );
01107 write_hex( aStream->svgFile, pls->cmap0[0].b );
01108 fprintf( aStream->svgFile, "\"\n" );
01109 svg_indent( aStream );
01110 fprintf( aStream->svgFile, "fill-opacity=\"%f\"\n", pls->cmap0[0].a );
01111 }
01112
01113
01114
01115
01116
01117
01118
01119
01120 int svg_family_check( PLStream *pls )
01121 {
01122 if ( pls->family || pls->page == 1 )
01123 {
01124 return 0;
01125 }
01126 else
01127 {
01128 if ( !already_warned )
01129 {
01130 already_warned = 1;
01131 plwarn( "All pages after the first skipped because family file output not specified.\n" );
01132 }
01133 return 1;
01134 }
01135 }
01136
01137
01138
01139
01140
01141
01142
01143 void write_hex( FILE *svgFile, unsigned char val )
01144 {
01145 if ( val < 16 )
01146 {
01147 fprintf( svgFile, "0%X", val );
01148 }
01149 else
01150 {
01151 fprintf( svgFile, "%X", val );
01152 }
01153 }
01154
01155
01156
01157
01158
01159
01160
01161
01162 void write_unicode( FILE *svgFile, PLUNICODE ucs4_char )
01163 {
01164 if ( ucs4_char >= ' ' || ucs4_char == '\t' || ucs4_char == '\n' || ucs4_char == '\r' )
01165 fprintf( svgFile, "&#x%x;", ucs4_char );
01166 else
01167 fprintf( svgFile, "&#x%x;", ' ' );
01168 }
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185 void specify_font( FILE *svgFile, PLUNICODE ucs4_char )
01186 {
01187 fprintf( svgFile, "<tspan " );
01188
01189
01190
01191 if ( ( ucs4_char & 0x00F ) == 0x000 )
01192 {
01193 fprintf( svgFile, "font-family=\"sans-serif\" " );
01194 }
01195 else if ( ( ucs4_char & 0x00F ) == 0x001 )
01196 {
01197 fprintf( svgFile, "font-family=\"serif\" " );
01198 }
01199 else if ( ( ucs4_char & 0x00F ) == 0x002 )
01200 {
01201 fprintf( svgFile, "font-family=\"mono-space\" " );
01202 }
01203 else if ( ( ucs4_char & 0x00F ) == 0x003 )
01204 {
01205 fprintf( svgFile, "font-family=\"cursive\" " );
01206 }
01207 else if ( ( ucs4_char & 0x00F ) == 0x004 )
01208 {
01209
01210 fprintf( svgFile, "font-family=\"sans-serif\" " );
01211 }
01212
01213
01214
01215 if ( ( ucs4_char & 0x0F0 ) == 0x000 )
01216 {
01217 fprintf( svgFile, "font-style=\"normal\" " );
01218 }
01219 else if ( ( ucs4_char & 0x0F0 ) == 0x010 )
01220 {
01221 fprintf( svgFile, "font-style=\"italic\" " );
01222 }
01223 else if ( ( ucs4_char & 0x0F0 ) == 0x020 )
01224 {
01225 fprintf( svgFile, "font-style=\"oblique\" " );
01226 }
01227
01228
01229
01230 if ( ( ucs4_char & 0xF00 ) == 0x000 )
01231 {
01232 fprintf( svgFile, "font-weight=\"normal\">" );
01233 }
01234 else if ( ( ucs4_char & 0xF00 ) == 0x100 )
01235 {
01236 fprintf( svgFile, "font-weight=\"bold\">" );
01237 }
01238 }