PLplot 5.15.0
Loading...
Searching...
No Matches
svg.c
Go to the documentation of this file.
1// November 8, 2006
2//
3// PLplot driver for SVG 1.1 (http://www.w3.org/Graphics/SVG/)
4//
5// Copyright (C) 2006 Hazen Babcock
6//
7// This file is part of PLplot.
8//
9// PLplot is free software; you can redistribute it and/or modify
10// it under the terms of the GNU Library General Public License as published
11// by the Free Software Foundation; either version 2 of the License, or
12// (at your option) any later version.
13//
14// PLplot is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17// GNU Library General Public License for more details.
18//
19// You should have received a copy of the GNU Library General Public License
20// along with PLplot; if not, write to the Free Software
21// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22//
23//
24
25//---------------------------------------------
26// Header files, defines and local variables
27// ---------------------------------------------
28
29#include <stdarg.h>
30#include <math.h>
31
32// PLplot header files
33
34#include "plplotP.h"
35#include "drivers.h"
36
37// constants
38
39#define SVG_Default_X 720
40#define SVG_Default_Y 540
41
42#define POINTS_PER_INCH 72
43
44#define MAX_STRING_LEN 1000
45
46// This has been generated empirically by looking carefully at results from
47// examples 1 and 2.
48
49#define FONT_SIZE_RATIO 1.34
50#define FONT_SHIFT_RATIO 0.705
51#define FONT_SHIFT_OFFSET 0.5
52
53// local variables
54
55PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_svg = "svg:Scalable Vector Graphics (SVG 1.1):1:svg:57:svg\n";
56
57static int already_warned = 0;
58
59static int text_clipping = 1;
60static DrvOpt svg_options[] = { { "text_clipping", DRV_INT, &text_clipping, "Use text clipping (text_clipping=0|1)" } };
61
62typedef struct
63{
70 FILE *svgFile;
72 // char curColor[7];
73} SVG;
74
75// font stuff
76
77// Debugging extras
78
79//-----------------------------------------------
80// function declarations
81// -----------------------------------------------
82
83// Functions for writing XML SVG tags to a file
84
85static void svg_open( SVG *, const char * );
86static void svg_open_end( SVG * );
87static void svg_attr_value( SVG *, const char *, const char * );
88static void svg_attr_values( SVG *, const char *, const char *, ... );
89static void svg_close( SVG *, const char * );
90static void svg_general( SVG *, const char * );
91static void svg_indent( SVG * );
92static void svg_stroke_width( PLStream * );
93static void svg_stroke_color( PLStream * );
94static void svg_fill_color( PLStream * );
95static void svg_fill_background_color( PLStream * );
96static int svg_family_check( PLStream * );
97
98
99// General
100
101static void poly_line( PLStream *, short *, short *, PLINT, short );
102static void gradient( PLStream *, short *, short *, PLINT );
103static void write_hex( FILE *, unsigned char );
104static void write_unicode( FILE *, PLUNICODE );
105static void specify_font( FILE *, PLUNICODE );
106
107// String processing
108
109static void proc_str( PLStream *, EscText * );
110
111// PLplot interface functions
112
114void plD_init_svg( PLStream * );
115void plD_line_svg( PLStream *, short, short, short, short );
116void plD_polyline_svg( PLStream *, short *, short *, PLINT );
117void plD_eop_svg( PLStream * );
118void plD_bop_svg( PLStream * );
119void plD_tidy_svg( PLStream * );
121void plD_esc_svg( PLStream *, PLINT, void * );
122
123//--------------------------------------------------------------------------
124// dispatch_init_init()
125//
126// Initialize device dispatch table
127//--------------------------------------------------------------------------
128
130{
131#ifndef ENABLE_DYNDRIVERS
132 pdt->pl_MenuStr = "Scalable Vector Graphics (SVG 1.1)";
133 pdt->pl_DevName = "svg";
134#endif
136 pdt->pl_seq = 57;
145}
146
147//--------------------------------------------------------------------------
148// svg_init()
149//
150// Initialize device
151//--------------------------------------------------------------------------
152
154{
155 SVG *aStream;
156
157 pls->termin = 0; // not an interactive device
158 pls->color = 1; // supports color
159 pls->width = 1;
160 pls->verbose = 1;
161 pls->bytecnt = 0;
162 //pls->debug = 1;
163 pls->dev_text = 1; // handles text
164 pls->dev_unicode = 1; // wants text as unicode
165 pls->page = 0;
166 pls->dev_fill0 = 1; // driver generates solid fills
167 pls->dev_fill1 = 0; // Use PLplot core fallback for pattern fills
168 pls->dev_gradient = 1; // driver renders gradient
169
171
172 if ( !pls->colorset )
173 pls->color = 1;
174
175 // Initialize family file info
176 plFamInit( pls );
177
178 // Prompt for a file name if not already set
179 plOpenFile( pls );
180// Allocate and initialize device-specific data
181
182 if ( pls->dev != NULL )
183 free( (void *) pls->dev );
184
185 pls->dev = calloc( 1, (size_t) sizeof ( SVG ) );
186 if ( pls->dev == NULL )
187 plexit( "plD_init_svg: Out of memory." );
188
189 aStream = (SVG *) pls->dev;
190
191 // Set the bounds for plotting in points (unit of 1/72 of an inch). Default is SVG_Default_X points x SVG_Default_Y points unless otherwise specified by plspage or -geometry option.
192
193 if ( pls->xlength <= 0 || pls->ylength <= 0 )
194 {
195 aStream->canvasXSize = SVG_Default_X;
196 aStream->canvasYSize = SVG_Default_Y;
197 }
198 else
199 {
200 aStream->canvasXSize = pls->xlength;
201 aStream->canvasYSize = pls->ylength;
202 }
203 // Calculate ratio of (larger) internal PLplot coordinates to external
204 // coordinates used for svg file.
205 if ( aStream->canvasXSize > aStream->canvasYSize )
206 aStream->scale = (PLFLT) ( PIXELS_X - 1 ) / (PLFLT) aStream->canvasXSize;
207 else
208 aStream->scale = (PLFLT) PIXELS_Y / (PLFLT) aStream->canvasYSize;
209 plP_setphy( (PLINT) 0, (PLINT) ( aStream->scale * aStream->canvasXSize ), (PLINT) 0, (PLINT) ( aStream->scale * aStream->canvasYSize ) ); // Scaled points.
210
211 plP_setpxl( aStream->scale * POINTS_PER_INCH / 25.4, aStream->scale * POINTS_PER_INCH / 25.4 ); // Scaled points/mm.
212
213 aStream->svgFile = pls->OutFile;
214
215 // Handle the text clipping option
217
218 // Turn on text clipping if the user desires this
219 if ( text_clipping )
220 {
221 aStream->textClipping = 1;
222 }
223 aStream->textClipping = (short) text_clipping;
224
225 aStream->svgIndent = 0;
226 aStream->gradient_index = 0;
227 svg_general( aStream, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
228 svg_general( aStream, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n" );
229 svg_general( aStream, " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n" );
230}
231
232//--------------------------------------------------------------------------
233// svg_bop()
234//
235// Set up for the next page.
236//--------------------------------------------------------------------------
237
239{
240 SVG *aStream;
241
242 // Plot familying stuff. Not really understood, just copying gd.c
243 plGetFam( pls );
244// n.b. pls->dev can change because of an indirect call to plD_init_svg
245// from plGetFam if familying is enabled. Thus, wait to define aStream until
246// now.
247 aStream = pls->dev;
248
249 pls->famadv = 1;
250 pls->page++;
251 if ( svg_family_check( pls ) )
252 {
253 return;
254 }
255
256 // write opening svg tag for the new page
257
258 svg_open( aStream, "svg" );
259 svg_attr_value( aStream, "xmlns", "http://www.w3.org/2000/svg" );
260 svg_attr_value( aStream, "xmlns:xlink", "http://www.w3.org/1999/xlink" );
261 svg_attr_value( aStream, "version", "1.1" );
262 // svg_attr_values("width", "%dcm", (int)((double)canvasXSize/POINTS_PER_INCH * 2.54));
263 // svg_attr_values("height", "%dcm", (int)((double)canvasYSize/POINTS_PER_INCH * 2.54));
264 svg_attr_values( aStream, "width", "%dpt", aStream->canvasXSize );
265 svg_attr_values( aStream, "height", "%dpt", aStream->canvasYSize );
266 svg_attr_values( aStream, "viewBox", "%d %d %d %d", 0, 0, aStream->canvasXSize, aStream->canvasYSize );
267 svg_general( aStream, ">\n" );
268
269 // set the background by drawing a rectangle that is the size of
270 // of the canvas and filling it with the background color.
271
272 svg_open( aStream, "rect" );
273 svg_attr_values( aStream, "x", "%d", 0 );
274 svg_attr_values( aStream, "y", "%d", 0 );
275 svg_attr_values( aStream, "width", "%d", aStream->canvasXSize );
276 svg_attr_values( aStream, "height", "%d", aStream->canvasYSize );
277 svg_attr_value( aStream, "stroke", "none" );
279 svg_open_end( aStream );
280
281 // invert the coordinate system so that PLplot graphs appear right side up
282
283 svg_open( aStream, "g" );
284 svg_attr_values( aStream, "transform", "matrix(1 0 0 -1 0 %d)", aStream->canvasYSize );
285 svg_general( aStream, ">\n" );
286}
287
288//--------------------------------------------------------------------------
289// svg_line()
290//
291// Draw a line in the current color from (x1,y1) to (x2,y2).
292//--------------------------------------------------------------------------
293
294void plD_line_svg( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
295{
296 SVG *aStream;
297
298 aStream = pls->dev;
299
300 if ( svg_family_check( pls ) )
301 {
302 return;
303 }
304 svg_open( aStream, "polyline" );
307 svg_attr_value( aStream, "fill", "none" );
308 // svg_attr_value(aStream, "shape-rendering", "crispEdges");
309 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 );
310 svg_open_end( aStream );
311}
312
313//--------------------------------------------------------------------------
314// svg_polyline()
315//
316// Draw a polyline in the current color.
317//--------------------------------------------------------------------------
318
319void plD_polyline_svg( PLStream *pls, short *xa, short *ya, PLINT npts )
320{
321 if ( svg_family_check( pls ) )
322 {
323 return;
324 }
325 poly_line( pls, xa, ya, npts, 0 );
326}
327
328//--------------------------------------------------------------------------
329// svg_eop()
330//
331// End of page
332//--------------------------------------------------------------------------
333
335{
336 SVG *aStream;
337
338 aStream = pls->dev;
339
340 if ( svg_family_check( pls ) )
341 {
342 return;
343 }
344 // write the closing svg tag
345
346 svg_close( aStream, "g" );
347 svg_close( aStream, "svg" );
348}
349
350//--------------------------------------------------------------------------
351// svg_tidy()
352//
353// Close graphics file or otherwise clean up.
354//--------------------------------------------------------------------------
355
357{
358 if ( svg_family_check( pls ) )
359 {
360 return;
361 }
362 plCloseFile( pls );
363}
364
365//--------------------------------------------------------------------------
366// plD_state_svg()
367//
368// Handle change in PLStream state (color, pen width, fill attribute, etc).
369//
370// Nothing is done here because these attributes are aquired from
371// PLStream for each element that is drawn.
372//--------------------------------------------------------------------------
373
375{
376}
377
378//--------------------------------------------------------------------------
379// svg_esc()
380//
381// Escape function.
382//--------------------------------------------------------------------------
383
384void plD_esc_svg( PLStream *pls, PLINT op, void *ptr )
385{
386 if ( svg_family_check( pls ) )
387 {
388 return;
389 }
390 switch ( op )
391 {
392 case PLESC_FILL: // fill polygon
394 break;
395 case PLESC_GRADIENT: // render gradient inside polygon
397 break;
398 case PLESC_HAS_TEXT: // render text
399 proc_str( pls, (EscText *) ptr );
400 break;
401 }
402}
403
404//--------------------------------------------------------------------------
405// poly_line()
406//
407// Handles drawing filled and unfilled polygons
408//--------------------------------------------------------------------------
409
410void poly_line( PLStream *pls, short *xa, short *ya, PLINT npts, short fill )
411{
412 int i;
413 SVG *aStream;
414
415 aStream = pls->dev;
416
417 svg_open( aStream, "polyline" );
418 if ( fill )
419 {
420 // Two adjacent regions will put non-zero width boundary strokes on top
421 // of each other on their common boundary. Thus, a stroke on the boundary
422 // of a filled region is generally a bad idea when the fill is partially
423 // opaque because the partial opacity of the two boundary strokes which
424 // are on top of each other will mutually interfere and produce a
425 // bad-looking result. On the other hand, for completely opaque fills
426 // a boundary stroke is a good idea since if it is of sufficient width
427 // it will keep the background from leaking through at the anti-aliased
428 // edges of filled regions that have a common boundary with other
429 // filled regions.
430 if ( pls->curcolor.a < 0.99 )
431 {
432 svg_attr_value( aStream, "stroke", "none" );
433 }
434 else
435 {
438 }
440 if ( pls->dev_eofill )
441 svg_attr_value( aStream, "fill-rule", "evenodd" );
442 else
443 svg_attr_value( aStream, "fill-rule", "nonzero" );
444 }
445 else
446 {
449 svg_attr_value( aStream, "fill", "none" );
450 }
451 //svg_attr_value(aStream, "shape-rendering", "crispEdges");
452 svg_indent( aStream );
453 fprintf( aStream->svgFile, "points=\"" );
454 for ( i = 0; i < npts; i++ )
455 {
456 fprintf( aStream->svgFile, "%.2f,%.2f ", (double) xa[i] / aStream->scale, (double) ya[i] / aStream->scale );
457 if ( ( ( i + 1 ) % 10 ) == 0 )
458 {
459 fprintf( aStream->svgFile, "\n" );
460 svg_indent( aStream );
461 }
462 }
463 fprintf( aStream->svgFile, "\"/>\n" );
464 aStream->svgIndent -= 2;
465}
466
467//--------------------------------------------------------------------------
468// gradient()
469//
470// Draws gradient
471//--------------------------------------------------------------------------
472
473void gradient( PLStream *pls, short *xa, short *ya, PLINT npts )
474{
475 int i;
476 // 27 should be the maximum needed below, but be generous.
477 char buffer[50];
478 SVG *aStream;
479
480 aStream = pls->dev;
481
482 svg_open( aStream, "g>" );
483 svg_open( aStream, "defs>" );
484 svg_open( aStream, "linearGradient" );
485 // Allows ~2^31 unique gradient id's, gradient_index incremented below.
486 sprintf( buffer, "MyGradient%010d", aStream->gradient_index );
487 svg_attr_value( aStream, "id", buffer );
488 svg_attr_value( aStream, "gradientUnits", "userSpaceOnUse" );
489 sprintf( buffer, "%.2f", pls->xgradient[0] / aStream->scale );
490 svg_attr_value( aStream, "x1", buffer );
491 sprintf( buffer, "%.2f", pls->ygradient[0] / aStream->scale );
492 svg_attr_value( aStream, "y1", buffer );
493 sprintf( buffer, "%.2f", pls->xgradient[1] / aStream->scale );
494 svg_attr_value( aStream, "x2", buffer );
495 sprintf( buffer, "%.2f", pls->ygradient[1] / aStream->scale );
496 svg_attr_value( aStream, "y2", buffer );
497 svg_general( aStream, ">\n" );
498
499 for ( i = 0; i < pls->ncol1; i++ )
500 {
501 svg_indent( aStream );
502 fprintf( aStream->svgFile, "<stop offset=\"%.3f\" ",
503 (double) i / (double) ( pls->ncol1 - 1 ) );
504 fprintf( aStream->svgFile, "stop-color=\"#" );
505 write_hex( aStream->svgFile, pls->cmap1[i].r );
506 write_hex( aStream->svgFile, pls->cmap1[i].g );
507 write_hex( aStream->svgFile, pls->cmap1[i].b );
508 fprintf( aStream->svgFile, "\" " );
509 fprintf( aStream->svgFile, "stop-opacity=\"%.3f\"/>\n", pls->cmap1[i].a );
510 }
511
512 svg_close( aStream, "linearGradient" );
513 svg_close( aStream, "defs" );
514 svg_open( aStream, "polyline" );
515 sprintf( buffer, "url(#MyGradient%010d)", aStream->gradient_index++ );
516 svg_attr_value( aStream, "fill", buffer );
517 svg_indent( aStream );
518 fprintf( aStream->svgFile, "points=\"" );
519 for ( i = 0; i < npts; i++ )
520 {
521 fprintf( aStream->svgFile, "%.2f,%.2f ", (double) xa[i] / aStream->scale, (double) ya[i] / aStream->scale );
522 if ( ( ( i + 1 ) % 10 ) == 0 )
523 {
524 fprintf( aStream->svgFile, "\n" );
525 svg_indent( aStream );
526 }
527 }
528 fprintf( aStream->svgFile, "\"/>\n" );
529 aStream->svgIndent -= 2;
530 svg_close( aStream, "g" );
531}
532
533//--------------------------------------------------------------------------
534// proc_str()
535//
536// Processes strings for display.
537//
538// NOTE:
539//
540// (1) This was tested on Firefox and Camino where it seemed to display
541// text properly. However, it isn't obvious to me that these browsers
542// conform to the specification. Basically the issue is that some of
543// the text properties (i.e. dy) that you specify inside a tspan element
544// remain in force until the end of the text element. It would seem to
545// me that they should only apply inside the tspan tag. To get around
546// this, and because it was easier anyway, I used what is essentially
547// a list of tspan tags rather than a tree of tspan tags. Perhaps
548// better described as a tree with one branch?
549//
550// (2) To deal with the some whitespace annoyances, the entire text
551// element must be written on a single line. If there are lots of
552// format characters then this line might end up being too long
553// for some SVG implementations.
554//
555// (3) Text placement is not ideal. Vertical offset seems to be
556// particularly troublesome.
557//
558// (4) See additional notes in specify_font re. to sans / serif
559//
560//--------------------------------------------------------------------------
561
563{
564 char plplot_esc;
565 short i;
566 short totalTags = 1;
567 short ucs4Len = (short) args->unicode_array_len;
568 double ftHt, scaled_offset, scaled_ftHt;
569 PLUNICODE fci;
570 PLINT rcx[4], rcy[4];
571 static PLINT prev_rcx[4], prev_rcy[4];
572 PLFLT rotation, shear, stride, cos_rot, sin_rot, sin_shear, cos_shear;
573 PLFLT t[4];
574 int glyph_size, sum_glyph_size;
575 short if_write;
576 // PLFLT *t = args->xform;
577 PLUNICODE *ucs4 = args->unicode_array;
578 SVG *aStream;
579 PLFLT old_sscale, sscale, old_soffset, soffset, old_dup, ddup;
580 PLINT level;
581 PLINT same_clip;
582
583 // check that we got unicode
584 if ( ucs4Len == 0 )
585 {
586 printf( "Non unicode string passed to SVG driver, ignoring\n" );
587 return;
588 }
589
590 // get plplot escape character and the current font
591 plgesc( &plplot_esc );
592 plgfci( &fci );
593
594 // determine the font height in points.
595 ftHt = FONT_SIZE_RATIO * pls->chrht * POINTS_PER_INCH / 25.4;
596
597 // Setup & apply text clipping area if desired
598 aStream = (SVG *) pls->dev;
599 if ( aStream->textClipping )
600 {
601 // Use PLplot core routine difilt_clip to appropriately
602 // transform the coordinates of the clipping rectangle
603 difilt_clip( rcx, rcy );
604 same_clip = TRUE;
605 if ( aStream->which_clip == 0 )
606 {
607 same_clip = FALSE;
608 }
609 else
610 {
611 for ( i = 0; i < 4; i++ )
612 {
613 if ( rcx[i] != prev_rcx[i] ||
614 rcy[i] != prev_rcy[i] )
615 same_clip = FALSE;
616 }
617 }
618 if ( !same_clip )
619 {
620 svg_open( aStream, "clipPath" );
621 svg_attr_values( aStream, "id", "text-clipping%d", aStream->which_clip );
622 svg_general( aStream, ">\n" );
623
624 // Output a polygon to represent the clipping region.
625 svg_open( aStream, "polygon" );
626 svg_attr_values( aStream,
627 "points",
628 "%f,%f %f,%f %f,%f %f,%f",
629 ( (PLFLT) rcx[0] ) / aStream->scale,
630 ( (PLFLT) rcy[0] ) / aStream->scale,
631 ( (PLFLT) rcx[1] ) / aStream->scale,
632 ( (PLFLT) rcy[1] ) / aStream->scale,
633 ( (PLFLT) rcx[2] ) / aStream->scale,
634 ( (PLFLT) rcy[2] ) / aStream->scale,
635 ( (PLFLT) rcx[3] ) / aStream->scale,
636 ( (PLFLT) rcy[3] ) / aStream->scale );
637 svg_open_end( aStream );
638
639 svg_close( aStream, "clipPath" );
640 for ( i = 0; i < 4; i++ )
641 {
642 prev_rcx[i] = rcx[i];
643 prev_rcy[i] = rcy[i];
644 }
645 aStream->which_clip++;
646 }
647 svg_open( aStream, "g" );
648 svg_attr_values( aStream, "clip-path",
649 "url(#text-clipping%d)", aStream->which_clip - 1 );
650 svg_general( aStream, ">\n" );
651 }
652
653 // This draws the clipping region on the screen which can
654 // be very helpful for debugging.
655
656 //
657 // svg_open(aStream, "polygon");
658 // svg_attr_values(aStream,
659 // "points",
660 // "%f,%f %f,%f %f,%f %f,%f",
661 // ((PLFLT)rcx[0])/aStream->scale,
662 // ((PLFLT)rcy[0])/aStream->scale,
663 // ((PLFLT)rcx[1])/aStream->scale,
664 // ((PLFLT)rcy[1])/aStream->scale,
665 // ((PLFLT)rcx[2])/aStream->scale,
666 // ((PLFLT)rcy[2])/aStream->scale,
667 // ((PLFLT)rcx[3])/aStream->scale,
668 // ((PLFLT)rcy[3])/aStream->scale);
669 // svg_stroke_width(pls);
670 // svg_stroke_color(pls);
671 // svg_attr_value(aStream, "fill", "none");
672 // svg_open_end(aStream);
673 //
674
675 // Calculate the tranformation matrix for SVG based on the
676 // transformation matrix provided by PLplot.
677 plRotationShear( args->xform, &rotation, &shear, &stride );
678 // N.B. Experimentally, I (AWI) have found the svg rotation angle is
679 // the negative of the libcairo rotation angle, and the svg shear angle
680 // is pi minus the libcairo shear angle.
681 rotation -= pls->diorot * PI / 2.0;
682 cos_rot = cos( rotation );
683 sin_rot = -sin( rotation );
684 sin_shear = sin( shear );
685 cos_shear = -cos( shear );
686 t[0] = cos_rot * stride;
687 t[1] = -sin_rot * stride;
688 t[2] = cos_rot * sin_shear + sin_rot * cos_shear;
689 t[3] = -sin_rot * sin_shear + cos_rot * cos_shear;
690
691 //--------------
692 // open text tag
693 // --------------
694
695 svg_open( aStream, "text" );
696
697 svg_attr_value( aStream, "dominant-baseline", "no-change" );
698
699 // set font color
701
702 // white space preserving mode
703 svg_attr_value( aStream, "xml:space", "preserve" );
704
705 // set the font size
706 svg_attr_values( aStream, "font-size", "%d", (int) ftHt );
707
708 // Apply coordinate transform for text display.
709 // The transformation also defines the location of the text in x and y.
710 svg_attr_values( aStream, "transform", "matrix(%f %f %f %f %f %f)",
711 t[0], t[1], t[2], t[3],
712 (double) ( args->x / aStream->scale ),
713 (double) ( args->y / aStream->scale ) );
714
715
716 //----------------------------------------------------------
717 // Write the text with formatting
718 // We just keep stacking up tspan tags, then close them all
719 // after we have written out all of the text.
720 // ----------------------------------------------------------
721
722 // For if_write = 0, we write nothing and instead accumulate the
723 // sum_glyph_size from the fontsize of the individual glyphs which
724 // is then used to figure out the initial x position from text-anchor and
725 // args->just that is used to write out the SVG xml for if_write = 1.
726
727 glyph_size = (int) ftHt;
728 sum_glyph_size = 0;
729 if_write = 0;
730 while ( if_write < 2 )
731 {
732 if ( if_write == 1 )
733 {
734 //printf("number of characters = %f\n", sum_glyph_size/ftHt);
735 // The above coordinate transform defines the _raw_ x position of the
736 // text without justification so this attribute value depends on
737 // text-anchor and args->just*sum_glyph_size
738 // N.B. sum_glyph_size calculation only correct for monospaced fonts
739 // so generally sum_glyph_size will be overestimated by various amounts
740 // depending on what glyphs are to be rendered, the font, etc. However,
741 // this correction is differential respect to the end points or the
742 // middle so you should be okay so long as you don't deviate too far
743 // from those anchor points.
744 if ( args->just < 0.33 )
745 {
746 svg_attr_value( aStream, "text-anchor", "start" ); // left justification
747 svg_attr_values( aStream, "x", "%f", (double) ( -args->just * sum_glyph_size ) );
748 }
749 else if ( args->just > 0.66 )
750 {
751 svg_attr_value( aStream, "text-anchor", "end" ); // right justification
752 svg_attr_values( aStream, "x", "%f", (double) ( ( 1. - args->just ) * sum_glyph_size ) );
753 }
754 else
755 {
756 svg_attr_value( aStream, "text-anchor", "middle" ); // center
757 svg_attr_values( aStream, "x", "%f", (double) ( ( 0.5 - args->just ) * sum_glyph_size ) );
758 }
759
760 // The text goes at zero in y since the above
761 // coordinate transform defines the y position of the text
762 svg_attr_values( aStream, "y", "%f",
763 FONT_SHIFT_RATIO * 0.5 * ftHt +
765
766 fprintf( aStream->svgFile, ">" );
767
768 // specify the initial font
769 specify_font( aStream->svgFile, fci );
770 }
771 i = 0;
772 scaled_ftHt = ftHt;
773 level = 0;
774 ddup = 0.;
775 while ( i < ucs4Len )
776 {
777 if ( ucs4[i] < PL_FCI_MARK ) // not a font change
778 {
779 if ( ucs4[i] != (PLUNICODE) plplot_esc ) // a character to display
780 {
781 if ( if_write )
782 {
783 write_unicode( aStream->svgFile, ucs4[i] );
784 }
785 else
786 {
787 sum_glyph_size += glyph_size;
788 }
789 i++;
790 continue;
791 }
792 i++;
793 if ( ucs4[i] == (PLUNICODE) plplot_esc ) // a escape character to display
794 {
795 if ( if_write )
796 {
797 write_unicode( aStream->svgFile, ucs4[i] );
798 }
799 else
800 {
801 sum_glyph_size += glyph_size;
802 }
803 i++;
804 continue;
805 }
806 else
807 {
808 // super/subscript logic follows that in plstr routine (plsym.c)
809 // for Hershey fonts. Factor of FONT_SHIFT_RATIO*0.80 is empirical
810 // adjustment.
811 if ( ucs4[i] == (PLUNICODE) 'u' ) // Superscript
812 {
813 plP_script_scale( TRUE, &level,
814 &old_sscale, &sscale, &old_soffset, &soffset );
815 // The correction for the difference in magnitude
816 // between the baseline and middle coordinate systems
817 // for superscripts should be
818 // 0.5*(base font size - superscript/subscript font size).
819 old_dup = ddup;
820 ddup = 0.5 * ( 1.0 - sscale );
821 if ( level <= 0 )
822 {
823 scaled_offset = FONT_SHIFT_RATIO * ftHt * ( 0.80 * ( soffset - old_soffset ) - ( ddup - old_dup ) );
824 }
825 else
826 {
827 scaled_offset = -FONT_SHIFT_RATIO * ftHt * ( 0.80 * ( soffset - old_soffset ) + ( ddup - old_dup ) );
828 }
829 scaled_ftHt = sscale * ftHt;
830 if ( if_write )
831 {
832 totalTags++;
833 fprintf( aStream->svgFile, "<tspan dy=\"%f\" font-size=\"%d\">", scaled_offset, (int) scaled_ftHt );
834 }
835 else
836 {
837 glyph_size = (int) scaled_ftHt;
838 }
839 }
840 if ( ucs4[i] == (PLUNICODE) 'd' ) // Subscript
841 {
842 plP_script_scale( FALSE, &level,
843 &old_sscale, &sscale, &old_soffset, &soffset );
844 // The correction for the difference in magnitude
845 // between the baseline and middle coordinate systems
846 // for superscripts should be
847 // 0.5*(base font size - superscript/subscript font size).
848 old_dup = ddup;
849 ddup = 0.5 * ( 1.0 - sscale );
850 if ( level < 0 )
851 {
852 scaled_offset = FONT_SHIFT_RATIO * ftHt * ( 0.80 * ( soffset - old_soffset ) - ( ddup - old_dup ) );
853 }
854 else
855 {
856 scaled_offset = -FONT_SHIFT_RATIO * ftHt * ( 0.80 * ( soffset - old_soffset ) + ( ddup - old_dup ) );
857 }
858 scaled_ftHt = sscale * ftHt;
859 if ( if_write )
860 {
861 totalTags++;
862 fprintf( aStream->svgFile, "<tspan dy=\"%f\" font-size=\"%d\">", scaled_offset, (int) scaled_ftHt );
863 }
864 else
865 {
866 glyph_size = (int) scaled_ftHt;
867 }
868 }
869 i++;
870 }
871 }
872 else // a font change
873 {
874 if ( if_write )
875 {
876 specify_font( aStream->svgFile, ucs4[i] );
877 totalTags++;
878 }
879 i++;
880 }
881 }
882 if_write++;
883 }
884
885 //----------------------------------------------
886 // close out all the tspan tags and the text tag
887 // ----------------------------------------------
888
889 for ( i = 0; i < totalTags; i++ )
890 {
891 fprintf( aStream->svgFile, "</tspan>" );
892 }
893 // The following commented out (by AWI) because it is a bad idea to
894 // put line ends in the middle of a text tag. This was the key to
895 // all the text rendering issues we had.
896 //fprintf(svgFile,"\n");
897 // For the same reason use fprintf and svgIndent -= 2;
898 // to close the text tag rather than svg_close("text"); since
899 // we don't want indentation spaces entering the text.
900 // svg_close("text");
901 fprintf( aStream->svgFile, "</text>\n" );
902 aStream->svgIndent -= 2;
903 if ( aStream->textClipping )
904 {
905 svg_close( aStream, "g" );
906 }
907}
908
909//--------------------------------------------------------------------------
910// svg_open ()
911//
912// Used to open a new XML expression, sets the indent level appropriately
913//--------------------------------------------------------------------------
914
915void svg_open( SVG *aStream, const char *tag )
916{
917 svg_indent( aStream );
918 fprintf( aStream->svgFile, "<%s\n", tag );
919 aStream->svgIndent += 2;
920}
921
922//--------------------------------------------------------------------------
923// svg_open_end ()
924//
925// Used to end the opening of a new XML expression i.e. add
926// the final ">".
927//--------------------------------------------------------------------------
928
929void svg_open_end( SVG *aStream )
930{
931 svg_indent( aStream );
932 fprintf( aStream->svgFile, "/>\n" );
933 aStream->svgIndent -= 2;
934}
935
936//--------------------------------------------------------------------------
937// svg_attr_value ()
938//
939// Prints two strings to svgFile as a XML attribute value pair
940// i.e. foo="bar"
941//--------------------------------------------------------------------------
942
943void svg_attr_value( SVG *aStream, const char *attribute, const char *value )
944{
945 svg_indent( aStream );
946 fprintf( aStream->svgFile, "%s=\"%s\"\n", attribute, value );
947}
948
949//--------------------------------------------------------------------------
950// svg_attr_values ()
951//
952// Prints a string and a bunch of numbers / strings as a XML attribute
953// value pair i.e. foo="0 10 1.0 5.3 bar"
954//
955// This function is derived from an example in
956// "The C Programming Language" by Kernighan and Ritchie.
957//
958//--------------------------------------------------------------------------
959
960void svg_attr_values( SVG *aStream, const char *attribute, const char *format, ... )
961{
962 va_list ap;
963 const char *p, *sval;
964 int ival;
965 double dval;
966
967 svg_indent( aStream );
968 fprintf( aStream->svgFile, "%s=\"", attribute );
969 va_start( ap, format );
970 for ( p = format; *p; p++ )
971 {
972 if ( *p != '%' )
973 {
974 fprintf( aStream->svgFile, "%c", *p );
975 continue;
976 }
977 switch ( *++p )
978 {
979 case 'd':
980 ival = va_arg( ap, int );
981 fprintf( aStream->svgFile, "%d", ival );
982 break;
983 case 'f':
984 dval = va_arg( ap, double );
985 fprintf( aStream->svgFile, "%f", dval );
986 break;
987 case 'r':
988 // r is non-standard, but use it here to format rounded value
989 dval = va_arg( ap, double );
990 fprintf( aStream->svgFile, "%.2f", dval );
991 break;
992 case 's':
993 sval = va_arg( ap, char * );
994 fprintf( aStream->svgFile, "%s", sval );
995 break;
996 default:
997 fprintf( aStream->svgFile, "%c", *p );
998 break;
999 }
1000 }
1001 fprintf( aStream->svgFile, "\"\n" );
1002 va_end( ap );
1003}
1004
1005//--------------------------------------------------------------------------
1006// svg_close ()
1007//
1008// Used to close a XML expression, sets the indent level appropriately
1009//--------------------------------------------------------------------------
1010
1011void svg_close( SVG *aStream, const char *tag )
1012{
1013 aStream->svgIndent -= 2;
1014 svg_indent( aStream );
1015 if ( strlen( tag ) > 0 )
1016 {
1017 fprintf( aStream->svgFile, "</%s>\n", tag );
1018 }
1019 else
1020 {
1021 fprintf( aStream->svgFile, "/>\n" );
1022 }
1023}
1024
1025//--------------------------------------------------------------------------
1026// svg_general ()
1027//
1028// Used to print any text into the svgFile
1029//--------------------------------------------------------------------------
1030
1031void svg_general( SVG *aStream, const char *text )
1032{
1033 svg_indent( aStream );
1034 fprintf( aStream->svgFile, "%s", text );
1035}
1036
1037//--------------------------------------------------------------------------
1038// svg_indent ()
1039//
1040// Indents properly based on the current indent level
1041//--------------------------------------------------------------------------
1042
1043void svg_indent( SVG *aStream )
1044{
1045 short i;
1046 for ( i = 0; i < aStream->svgIndent; i++ )
1047 {
1048 fprintf( aStream->svgFile, " " );
1049 }
1050}
1051
1052//--------------------------------------------------------------------------
1053// svg_stroke_width ()
1054//
1055// sets the stroke width based on the current width
1056//--------------------------------------------------------------------------
1057
1059{
1060 SVG *aStream;
1061
1062 aStream = pls->dev;
1063 svg_indent( aStream );
1064 fprintf( aStream->svgFile, "stroke-width=\"%e\"\n", pls->width );
1065}
1066
1067//--------------------------------------------------------------------------
1068// svg_stroke_color ()
1069//
1070// sets the stroke color based on the current color
1071//--------------------------------------------------------------------------
1072
1074{
1075 SVG *aStream;
1076
1077 aStream = pls->dev;
1078 svg_indent( aStream );
1079 fprintf( aStream->svgFile, "stroke=\"#" );
1080 write_hex( aStream->svgFile, pls->curcolor.r );
1081 write_hex( aStream->svgFile, pls->curcolor.g );
1082 write_hex( aStream->svgFile, pls->curcolor.b );
1083 fprintf( aStream->svgFile, "\"\n" );
1084 svg_indent( aStream );
1085 fprintf( aStream->svgFile, "stroke-opacity=\"%f\"\n", pls->curcolor.a );
1086}
1087
1088//--------------------------------------------------------------------------
1089// svg_fill_color ()
1090//
1091// sets the fill color based on the current color
1092//--------------------------------------------------------------------------
1093
1095{
1096 SVG *aStream;
1097
1098 aStream = pls->dev;
1099 svg_indent( aStream );
1100 fprintf( aStream->svgFile, "fill=\"#" );
1101 write_hex( aStream->svgFile, pls->curcolor.r );
1102 write_hex( aStream->svgFile, pls->curcolor.g );
1103 write_hex( aStream->svgFile, pls->curcolor.b );
1104 fprintf( aStream->svgFile, "\"\n" );
1105 svg_indent( aStream );
1106 fprintf( aStream->svgFile, "fill-opacity=\"%f\"\n", pls->curcolor.a );
1107}
1108
1109//--------------------------------------------------------------------------
1110// svg_fill_background_color ()
1111//
1112// sets the background fill color based on the current background color
1113//--------------------------------------------------------------------------
1114
1116{
1117 SVG *aStream;
1118
1119 aStream = pls->dev;
1120 svg_indent( aStream );
1121 fprintf( aStream->svgFile, "fill=\"#" );
1122 write_hex( aStream->svgFile, pls->cmap0[0].r );
1123 write_hex( aStream->svgFile, pls->cmap0[0].g );
1124 write_hex( aStream->svgFile, pls->cmap0[0].b );
1125 fprintf( aStream->svgFile, "\"\n" );
1126 svg_indent( aStream );
1127 fprintf( aStream->svgFile, "fill-opacity=\"%f\"\n", pls->cmap0[0].a );
1128}
1129
1130//--------------------------------------------------------------------------
1131// svg_family_check ()
1132//
1133// support function to help supress more than one page if family file
1134// output not specified by the user (e.g., with the -fam command-line option).
1135//--------------------------------------------------------------------------
1136
1138{
1139 if ( pls->family || pls->page == 1 )
1140 {
1141 return 0;
1142 }
1143 else
1144 {
1145 if ( !already_warned )
1146 {
1147 already_warned = 1;
1148 plwarn( "All pages after the first skipped because family file output not specified.\n" );
1149 }
1150 return 1;
1151 }
1152}
1153
1154//--------------------------------------------------------------------------
1155// write_hex ()
1156//
1157// writes a unsigned char as an appropriately formatted hex value
1158//--------------------------------------------------------------------------
1159
1160void write_hex( FILE *svgFile, unsigned char val )
1161{
1162 if ( val < 16 )
1163 {
1164 fprintf( svgFile, "0%X", val );
1165 }
1166 else
1167 {
1168 fprintf( svgFile, "%X", val );
1169 }
1170}
1171
1172//--------------------------------------------------------------------------
1173// write_unicode ()
1174//
1175// writes a unicode character, appropriately formatted (i.e. &#xNNN)
1176// with invalid xml characters replaced by ' '.
1177//--------------------------------------------------------------------------
1178
1179void write_unicode( FILE *svgFile, PLUNICODE ucs4_char )
1180{
1181 if ( ucs4_char >= ' ' || ucs4_char == '\t' || ucs4_char == '\n' || ucs4_char == '\r' )
1182 fprintf( svgFile, "&#x%x;", ucs4_char );
1183 else
1184 fprintf( svgFile, "&#x%x;", ' ' );
1185}
1186
1187//--------------------------------------------------------------------------
1188// specify_font ()
1189//
1190// Note:
1191// We don't actually specify a font, just the fonts properties.
1192// The hope is that this will give the display program the freedom
1193// to choose the font with the glyphs that it needs to display
1194// the text.
1195//
1196// Known Issues:
1197// (1) On OS-X 10.4 with Firefox and Camino the "serif" font-family
1198// looks more like the "italic" font-style.
1199//
1200//--------------------------------------------------------------------------
1201
1202void specify_font( FILE *svgFile, PLUNICODE ucs4_char )
1203{
1204 fprintf( svgFile, "<tspan " );
1205
1206 // sans, serif, mono, script, symbol
1207
1208 if ( ( ucs4_char & 0x00F ) == 0x000 )
1209 {
1210 fprintf( svgFile, "font-family=\"sans-serif\" " );
1211 }
1212 else if ( ( ucs4_char & 0x00F ) == 0x001 )
1213 {
1214 fprintf( svgFile, "font-family=\"serif\" " );
1215 }
1216 else if ( ( ucs4_char & 0x00F ) == 0x002 )
1217 {
1218 fprintf( svgFile, "font-family=\"mono-space\" " );
1219 }
1220 else if ( ( ucs4_char & 0x00F ) == 0x003 )
1221 {
1222 fprintf( svgFile, "font-family=\"cursive\" " );
1223 }
1224 else if ( ( ucs4_char & 0x00F ) == 0x004 )
1225 {
1226 // this should be symbol, but that doesn't seem to be available
1227 fprintf( svgFile, "font-family=\"sans-serif\" " );
1228 }
1229
1230 // normal, italic, oblique
1231
1232 if ( ( ucs4_char & 0x0F0 ) == 0x000 )
1233 {
1234 fprintf( svgFile, "font-style=\"normal\" " );
1235 }
1236 else if ( ( ucs4_char & 0x0F0 ) == 0x010 )
1237 {
1238 fprintf( svgFile, "font-style=\"italic\" " );
1239 }
1240 else if ( ( ucs4_char & 0x0F0 ) == 0x020 )
1241 {
1242 fprintf( svgFile, "font-style=\"oblique\" " );
1243 }
1244
1245 // normal, bold
1246
1247 if ( ( ucs4_char & 0xF00 ) == 0x000 )
1248 {
1249 fprintf( svgFile, "font-weight=\"normal\">" );
1250 }
1251 else if ( ( ucs4_char & 0xF00 ) == 0x100 )
1252 {
1253 fprintf( svgFile, "font-weight=\"bold\">" );
1254 }
1255}
@ plDevType_FileOriented
Definition disptab.h:13
void(* plD_line_fp)(struct PLStream_struct *, short, short, short, short)
Definition disptab.h:68
void(* plD_tidy_fp)(struct PLStream_struct *)
Definition disptab.h:72
void(* plD_bop_fp)(struct PLStream_struct *)
Definition disptab.h:71
void(* plD_state_fp)(struct PLStream_struct *, PLINT)
Definition disptab.h:73
void(* plD_eop_fp)(struct PLStream_struct *)
Definition disptab.h:70
void(* plD_init_fp)(struct PLStream_struct *)
Definition disptab.h:67
void(* plD_esc_fp)(struct PLStream_struct *, PLINT, void *)
Definition disptab.h:74
void(* plD_polyline_fp)(struct PLStream_struct *, short *, short *, PLINT)
Definition disptab.h:69
int plParseDrvOpts(DrvOpt *acc_opt)
Definition plargs.c:1461
void difilt_clip(PLINT *x_coords, PLINT *y_coords)
Definition plcore.c:1603
void plP_setpxl(PLFLT xpmm, PLFLT ypmm)
Definition plcore.c:4238
void plgesc(char *p_esc)
Definition plcore.c:3914
void plP_setphy(PLINT xmin, PLINT xmax, PLINT ymin, PLINT ymax)
Definition plcore.c:4249
static PLStream * pls[PL_NSTREAMS]
Definition plcore.h:88
void plFamInit(PLStream *pls)
Definition plctrl.c:2751
void plwarn(PLCHAR_VECTOR errormsg)
Definition plctrl.c:1863
static PLFLT value(double n1, double n2, double hue)
Definition plctrl.c:1219
void plCloseFile(PLStream *pls)
Definition plctrl.c:2635
void plOpenFile(PLStream *pls)
Definition plctrl.c:2571
void plexit(PLCHAR_VECTOR errormsg)
Definition plctrl.c:1958
void plGetFam(PLStream *pls)
Definition plctrl.c:2780
#define PLDLLIMPEXP_DRIVER
Definition pldll.h:81
static PLINT * buffer
Definition plfill.c:74
void plRotationShear(PLFLT *xFormMatrix, PLFLT *rotation, PLFLT *shear, PLFLT *stride)
Definition plot3d.c:2767
#define GRAPHICS_MODE
Definition plplotP.h:288
#define PI
Definition plplotP.h:290
#define PIXELS_X
Definition plplotP.h:304
@ DRV_INT
Definition plplotP.h:758
#define TRUE
Definition plplotP.h:176
#define FALSE
Definition plplotP.h:177
#define PIXELS_Y
Definition plplotP.h:305
#define plgfci
Definition plplot.h:735
#define PLESC_HAS_TEXT
Definition plplot.h:290
PLUINT PLUNICODE
Definition plplot.h:201
float PLFLT
Definition plplot.h:163
#define PLESC_GRADIENT
Definition plplot.h:305
#define PL_UNUSED(x)
Definition plplot.h:138
#define PLESC_FILL
Definition plplot.h:279
int PLINT
Definition plplot.h:181
#define PL_FCI_MARK
Definition plplot.h:370
void plP_script_scale(PLBOOL ifupper, PLINT *level, PLFLT *old_scale, PLFLT *scale, PLFLT *old_offset, PLFLT *offset)
Definition plsym.c:1302
static int text
Definition ps.c:77
unsigned short unicode_array_len
Definition plplotP.h:736
PLFLT just
Definition plplotP.h:708
PLINT x
Definition plplotP.h:712
PLUNICODE * unicode_array
Definition plplotP.h:735
PLINT y
Definition plplotP.h:713
PLFLT * xform
Definition plplotP.h:709
PLFLT a
Definition plplot.h:551
unsigned char r
Definition plplot.h:548
unsigned char g
Definition plplot.h:549
unsigned char b
Definition plplot.h:550
plD_eop_fp pl_eop
Definition disptab.h:86
const char * pl_DevName
Definition disptab.h:80
plD_esc_fp pl_esc
Definition disptab.h:90
plD_polyline_fp pl_polyline
Definition disptab.h:85
plD_state_fp pl_state
Definition disptab.h:89
plD_tidy_fp pl_tidy
Definition disptab.h:88
plD_line_fp pl_line
Definition disptab.h:84
plD_init_fp pl_init
Definition disptab.h:83
plD_bop_fp pl_bop
Definition disptab.h:87
const char * pl_MenuStr
Definition disptab.h:79
PLINT ncol1
Definition plstrm.h:539
PLINT famadv
Definition plstrm.h:570
PLINT verbose
Definition plstrm.h:527
PLINT ylength
Definition plstrm.h:617
PLINT bytecnt
Definition plstrm.h:578
PLColor * cmap0
Definition plstrm.h:544
PLINT dev_fill0
Definition plstrm.h:571
PLINT page
Definition plstrm.h:578
PLINT family
Definition plstrm.h:570
PLINT dev_npts
Definition plstrm.h:581
PLINT color
Definition plstrm.h:569
short * dev_y
Definition plstrm.h:582
PLFLT width
Definition plstrm.h:552
FILE * OutFile
Definition plstrm.h:575
short * dev_x
Definition plstrm.h:582
PLFLT chrht
Definition plstrm.h:686
PLINT dev_gradient
Definition plstrm.h:773
PLINT dev_unicode
Definition plstrm.h:747
PLColor curcolor
Definition plstrm.h:543
PLINT * xgradient
Definition plstrm.h:775
PLINT dev_text
Definition plstrm.h:572
PLINT termin
Definition plstrm.h:568
void * dev
Definition plstrm.h:594
PLColor * cmap1
Definition plstrm.h:545
PLINT xlength
Definition plstrm.h:617
PLINT graphx
Definition plstrm.h:568
PLINT dev_fill1
Definition plstrm.h:571
PLINT * ygradient
Definition plstrm.h:775
PLINT colorset
Definition plstrm.h:569
PLINT dev_eofill
Definition plstrm.h:788
PLFLT diorot
Definition plstrm.h:661
Definition svg.c:63
int gradient_index
Definition svg.c:71
int svgIndent
Definition svg.c:69
int canvasYSize
Definition svg.c:67
PLFLT scale
Definition svg.c:68
short textClipping
Definition svg.c:64
FILE * svgFile
Definition svg.c:70
int which_clip
Definition svg.c:65
int canvasXSize
Definition svg.c:66
static void svg_open_end(SVG *)
Definition svg.c:929
#define FONT_SHIFT_OFFSET
Definition svg.c:51
static void proc_str(PLStream *, EscText *)
Definition svg.c:562
static void svg_close(SVG *, const char *)
Definition svg.c:1011
static int svg_family_check(PLStream *)
Definition svg.c:1137
static void svg_open(SVG *, const char *)
Definition svg.c:915
static void svg_fill_color(PLStream *)
Definition svg.c:1094
void plD_bop_svg(PLStream *)
Definition svg.c:238
static int text_clipping
Definition svg.c:59
static void svg_indent(SVG *)
Definition svg.c:1043
static void svg_stroke_width(PLStream *)
Definition svg.c:1058
void plD_state_svg(PLStream *, PLINT)
static void svg_attr_value(SVG *, const char *, const char *)
Definition svg.c:943
void plD_tidy_svg(PLStream *)
Definition svg.c:356
static void svg_stroke_color(PLStream *)
Definition svg.c:1073
static void svg_fill_background_color(PLStream *)
Definition svg.c:1115
PLDLLIMPEXP_DRIVER const char * plD_DEVICE_INFO_svg
Definition svg.c:55
#define SVG_Default_Y
Definition svg.c:40
#define FONT_SHIFT_RATIO
Definition svg.c:50
static void write_hex(FILE *, unsigned char)
Definition svg.c:1160
static void write_unicode(FILE *, PLUNICODE)
Definition svg.c:1179
#define FONT_SIZE_RATIO
Definition svg.c:49
#define SVG_Default_X
Definition svg.c:39
void plD_init_svg(PLStream *)
Definition svg.c:153
static int already_warned
Definition svg.c:57
void plD_dispatch_init_svg(PLDispatchTable *pdt)
Definition svg.c:129
static void svg_general(SVG *, const char *)
Definition svg.c:1031
static void gradient(PLStream *, short *, short *, PLINT)
Definition svg.c:473
static void specify_font(FILE *, PLUNICODE)
Definition svg.c:1202
static DrvOpt svg_options[]
Definition svg.c:60
void plD_eop_svg(PLStream *)
Definition svg.c:334
void plD_esc_svg(PLStream *, PLINT, void *)
Definition svg.c:384
void plD_polyline_svg(PLStream *, short *, short *, PLINT)
Definition svg.c:319
#define POINTS_PER_INCH
Definition svg.c:42
void plD_line_svg(PLStream *, short, short, short, short)
Definition svg.c:294
static void svg_attr_values(SVG *, const char *, const char *,...)
Definition svg.c:960
static void poly_line(PLStream *, short *, short *, PLINT, short)
Definition svg.c:410