2
% Copyright (C) 2003 GraphicsMagick Group
3
% Copyright (C) 2002 ImageMagick Studio
5
% This program is covered by multiple licenses, which are described in
6
% Copyright.txt. You should have received a copy of Copyright.txt with this
7
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
9
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
20
% Read/Write Scalable Vector Graphics Format. %
30
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
38
#include "magick/studio.h"
39
#include "magick/attribute.h"
40
#include "magick/blob.h"
41
#include "magick/color.h"
42
#include "magick/constitute.h"
43
#include "magick/gem.h"
44
#include "magick/log.h"
45
#include "magick/magick.h"
46
#include "magick/render.h"
47
#include "magick/tempfile.h"
48
#include "magick/utility.h"
51
# if defined(__MINGW32__)
54
# include <win32config.h>
56
# include <libxml/parser.h>
57
# include <libxml/xmlmemory.h>
58
# include <libxml/parserInternals.h>
59
# include <libxml/xmlerror.h>
62
#if defined(HasAUTOTRACE)
64
#include "image-header.h"
67
#include "pxl-outline.h"
68
#include "atquantize.h"
69
#include "thin-image.h"
72
*version_string = "AutoTrace version 0.24a";
78
#define MVGPrintf (void) fprintf
83
typedef struct _BoundingBox
92
typedef struct _SVGInfo
155
Forward declarations.
158
WriteSVGImage(const ImageInfo *,Image *);
162
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
166
% R e a d S V G I m a g e %
170
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172
% Method ReadSVGImage reads a Scalable Vector Gaphics file and returns it. It
173
% allocates the memory necessary for the new Image structure and returns a
174
% pointer to the new image.
176
% The format of the ReadSVGImage method is:
178
% Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
180
% A description of each parameter follows:
182
% o image: Method ReadSVGImage returns a pointer to the image after
183
% reading. A null image is returned if there is a memory shortage or if
184
% the image cannot be read.
186
% o image_info: Specifies a pointer to a ImageInfo structure.
188
% o exception: return any errors or warnings in this structure.
193
static double GetUserSpaceCoordinateValue(const SVGInfo *svg_info,int type,
198
token[MaxTextExtent];
203
assert(string != (const char *) NULL);
205
GetToken(p,&p,token);
207
if (strchr(token,'%') != (char *) NULL)
214
return(svg_info->view_box.width*value/100.0);
216
return(svg_info->view_box.height*value/100.0);
217
alpha=value-svg_info->view_box.width;
218
beta=value-svg_info->view_box.height;
219
return(sqrt(alpha*alpha+beta*beta)/sqrt(2.0)/100.0);
221
GetToken(p,&p,token);
222
if (LocaleNCompare(token,"cm",2) == 0)
223
return(72.0*svg_info->scale[0]/2.54*value);
224
if (LocaleNCompare(token,"em",2) == 0)
225
return(svg_info->pointsize*value);
226
if (LocaleNCompare(token,"ex",2) == 0)
227
return(svg_info->pointsize*value/2.0);
228
if (LocaleNCompare(token,"in",2) == 0)
229
return(72.0*svg_info->scale[0]*value);
230
if (LocaleNCompare(token,"mm",2) == 0)
231
return(72.0*svg_info->scale[0]/25.4*value);
232
if (LocaleNCompare(token,"pc",2) == 0)
233
return(72.0*svg_info->scale[0]/6.0*value);
234
if (LocaleNCompare(token,"pt",2) == 0)
235
return(svg_info->scale[0]*value);
236
if (LocaleNCompare(token,"px",2) == 0)
241
static char **GetStyleTokens(void *context,const char *text,int *number_tokens)
256
svg_info=(SVGInfo *) context;
258
if (text == (const char *) NULL)
259
return((char **) NULL);
261
Determine the number of arguments.
263
for (p=text; *p != '\0'; p++)
266
tokens=MagickAllocateMemory(char **,(*number_tokens+2)*sizeof(*tokens));
267
if (tokens == (char **) NULL)
269
ThrowException3(svg_info->exception,ResourceLimitError,
270
MemoryAllocationFailed,UnableToConvertStringToTokens);
271
return((char **) NULL);
274
Convert string to an ASCII list.
278
for (q=p; *q != '\0'; q++)
280
if ((*q != ':') && (*q != ';') && (*q != '\0'))
282
tokens[i]=AllocateString(p);
283
(void) strncpy(tokens[i],p,q-p);
288
tokens[i]=AllocateString(p);
289
(void) strncpy(tokens[i],p,q-p);
292
tokens[i]=(char *) NULL;
296
static char **GetTransformTokens(void *context,const char *text,
312
svg_info=(SVGInfo *) context;
314
if (text == (const char *) NULL)
315
return((char **) NULL);
317
Determine the number of arguments.
319
for (p=text; *p != '\0'; p++)
324
tokens=MagickAllocateMemory(char **,(*number_tokens+2)*sizeof(*tokens));
325
if (tokens == (char **) NULL)
327
ThrowException3(svg_info->exception,ResourceLimitError,
328
MemoryAllocationFailed,UnableToConvertStringToTokens);
329
return((char **) NULL);
332
Convert string to an ASCII list.
336
for (q=p; *q != '\0'; q++)
338
if ((*q != '(') && (*q != ')') && (*q != '\0'))
340
tokens[i]=AllocateString(p);
341
(void) strncpy(tokens[i],p,q-p);
346
tokens[i]=AllocateString(p);
347
(void) strncpy(tokens[i],p,q-p);
350
tokens[i]=(char *) NULL;
354
#if defined(__cplusplus) || defined(c_plusplus)
358
static int SVGIsStandalone(void *context)
364
Is this document tagged standalone?
366
(void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGIsStandalone()");
367
svg_info=(SVGInfo *) context;
368
return(svg_info->document->standalone == 1);
371
static int SVGHasInternalSubset(void *context)
377
Does this document has an internal subset?
379
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
380
" SAX.SVGHasInternalSubset()");
381
svg_info=(SVGInfo *) context;
382
return(svg_info->document->intSubset != NULL);
385
static int SVGHasExternalSubset(void *context)
391
Does this document has an external subset?
393
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
394
" SAX.SVGHasExternalSubset()");
395
svg_info=(SVGInfo *) context;
396
return(svg_info->document->extSubset != NULL);
399
static void SVGInternalSubset(void *context,const xmlChar *name,
400
const xmlChar *external_id,const xmlChar *system_id)
406
Does this document has an internal subset?
408
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
409
" SAX.internalSubset(%.1024s, %.1024s, %.1024s)",(char *) name,
410
(external_id != (const xmlChar *) NULL ? (char *) external_id : "none"),
411
(system_id != (const xmlChar *) NULL ? (char *) system_id : "none"));
412
svg_info=(SVGInfo *) context;
413
(void) xmlCreateIntSubset(svg_info->document,name,external_id,system_id);
416
static xmlParserInputPtr SVGResolveEntity(void *context,
417
const xmlChar *public_id,const xmlChar *system_id)
426
Special entity resolver, better left to the parser, it has more
427
context than the application layer. The default behaviour is to
428
not resolve the entities, in that case the ENTITY_REF nodes are
429
built in the structure (and the parameter values).
431
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
432
" SAX.resolveEntity(%.1024s, %.1024s)",
433
(public_id != (const xmlChar *) NULL ? (char *) public_id : "none"),
434
(system_id != (const xmlChar *) NULL ? (char *) system_id : "none"));
435
svg_info=(SVGInfo *) context;
436
stream=xmlLoadExternalEntity((const char *) system_id,(const char *)
437
public_id,svg_info->parser);
441
static xmlEntityPtr SVGGetEntity(void *context,const xmlChar *name)
447
Get an entity by name.
449
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
450
" SAX.SVGGetEntity(%.1024s)",name);
451
svg_info=(SVGInfo *) context;
452
return(xmlGetDocEntity(svg_info->document,name));
455
static xmlEntityPtr SVGGetParameterEntity(void *context,const xmlChar *name)
461
Get a parameter entity by name.
463
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
464
" SAX.getParameterEntity(%.1024s)",name);
465
svg_info=(SVGInfo *) context;
466
return(xmlGetParameterEntity(svg_info->document,name));
469
static void SVGEntityDeclaration(void *context,const xmlChar *name,int type,
470
const xmlChar *public_id,const xmlChar *system_id,xmlChar *content)
476
An entity definition has been parsed.
478
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
479
" SAX.entityDecl(%.1024s, %d, %.1024s, %.1024s, %.1024s)",name,type,
480
public_id != (xmlChar *) NULL ? (char *) public_id : "none",
481
system_id != (xmlChar *) NULL ? (char *) system_id : "none",content);
482
svg_info=(SVGInfo *) context;
483
if (svg_info->parser->inSubset == 1)
484
(void) xmlAddDocEntity(svg_info->document,name,type,public_id,system_id,
487
if (svg_info->parser->inSubset == 2)
488
(void) xmlAddDtdEntity(svg_info->document,name,type,public_id,system_id,
492
static void SVGAttributeDeclaration(void *context,const xmlChar *element,
493
const xmlChar *name,int type,int value,const xmlChar *default_value,
494
xmlEnumerationPtr tree)
507
An attribute definition has been parsed.
509
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
510
" SAX.attributeDecl(%.1024s, %.1024s, %d, %d, %.1024s, ...)",element,
511
name,type,value,default_value);
512
svg_info=(SVGInfo *) context;
513
fullname=(xmlChar *) NULL;
514
prefix=(xmlChar *) NULL;
515
parser=svg_info->parser;
516
fullname=(xmlChar *) xmlSplitQName(parser,name,&prefix);
517
if (parser->inSubset == 1)
518
(void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->intSubset,
519
element,fullname,prefix,(xmlAttributeType) type,
520
(xmlAttributeDefault) value,default_value,tree);
522
if (parser->inSubset == 2)
523
(void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->extSubset,
524
element,fullname,prefix,(xmlAttributeType) type,
525
(xmlAttributeDefault) value,default_value,tree);
526
if (prefix != (xmlChar *) NULL)
528
if (fullname != (xmlChar *) NULL)
532
static void SVGElementDeclaration(void *context,const xmlChar *name,int type,
533
xmlElementContentPtr content)
542
An element definition has been parsed.
544
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
545
" SAX.elementDecl(%.1024s, %d, ...)",name,type);
546
svg_info=(SVGInfo *) context;
547
parser=svg_info->parser;
548
if (parser->inSubset == 1)
549
(void) xmlAddElementDecl(&parser->vctxt,svg_info->document->intSubset,
550
name,(xmlElementTypeVal) type,content);
552
if (parser->inSubset == 2)
553
(void) xmlAddElementDecl(&parser->vctxt,svg_info->document->extSubset,
554
name,(xmlElementTypeVal) type,content);
557
static void SVGNotationDeclaration(void *context,const xmlChar *name,
558
const xmlChar *public_id,const xmlChar *system_id)
567
What to do when a notation declaration has been parsed.
569
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
570
" SAX.notationDecl(%.1024s, %.1024s, %.1024s)",name,
571
public_id != (const xmlChar *) NULL ? (char *) public_id : "none",
572
system_id != (const xmlChar *) NULL ? (char *) system_id : "none");
573
svg_info=(SVGInfo *) context;
574
parser=svg_info->parser;
575
if (parser->inSubset == 1)
576
(void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
577
name,public_id,system_id);
579
if (parser->inSubset == 2)
580
(void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
581
name,public_id,system_id);
584
static void SVGUnparsedEntityDeclaration(void *context,const xmlChar *name,
585
const xmlChar *public_id,const xmlChar *system_id,const xmlChar *notation)
591
What to do when an unparsed entity declaration is parsed.
593
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
594
" SAX.unparsedEntityDecl(%.1024s, %.1024s, %.1024s, %.1024s)",name,
595
public_id != (xmlChar *) NULL ? (char *) public_id : "none",
596
system_id != (xmlChar *) NULL ? (char *) system_id : "none",notation);
597
svg_info=(SVGInfo *) context;
598
(void) xmlAddDocEntity(svg_info->document,name,
599
XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,public_id,system_id,notation);
603
static void SVGSetDocumentLocator(void *context,xmlSAXLocatorPtr location)
609
Receive the document locator at startup, actually xmlDefaultSAXLocator.
611
(void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.setDocumentLocator()");
612
/* svg_info=(SVGInfo *) context; */
615
static void SVGStartDocument(void *context)
624
Called when the document start being processed.
626
(void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startDocument()");
627
svg_info=(SVGInfo *) context;
628
GetExceptionInfo(svg_info->exception);
629
parser=svg_info->parser;
630
svg_info->document=xmlNewDoc(parser->version);
631
if (svg_info->document == (xmlDocPtr) NULL)
633
if (parser->encoding == NULL)
634
svg_info->document->encoding=(const xmlChar *) NULL;
636
svg_info->document->encoding=xmlStrdup(parser->encoding);
637
svg_info->document->standalone=parser->standalone;
640
static void SVGEndDocument(void *context)
646
Called when the document end has been detected.
648
(void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.endDocument()");
649
svg_info=(SVGInfo *) context;
650
MagickFreeMemory(svg_info->offset);
651
MagickFreeMemory(svg_info->stop_color);
652
MagickFreeMemory(svg_info->scale);
653
MagickFreeMemory(svg_info->text);
654
MagickFreeMemory(svg_info->vertices);
655
MagickFreeMemory(svg_info->url);
656
if (svg_info->document != (xmlDocPtr) NULL)
658
xmlFreeDoc(svg_info->document);
659
svg_info->document=(xmlDocPtr) NULL;
663
static void SVGStartElement(void *context,const xmlChar *name,
664
const xmlChar **attributes)
670
token[MaxTextExtent],
689
Called when an opening tag has been processed.
691
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
692
" SAX.startElement(%.1024s",name);
693
svg_info=(SVGInfo *) context;
695
MagickReallocMemory(svg_info->scale,(svg_info->n+1)*sizeof(double));
696
if (svg_info->scale == (double *) NULL)
698
ThrowException(svg_info->exception,ResourceLimitError,
699
MemoryAllocationFailed,"unable to convert SVG image");
702
svg_info->scale[svg_info->n]=svg_info->scale[svg_info->n-1];
703
color=AllocateString("none");
704
units=AllocateString("userSpaceOnUse");
705
value=(const char *) NULL;
706
if (attributes != (const xmlChar **) NULL)
707
for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
709
keyword=(const char *) attributes[i];
710
value=(const char *) attributes[i+1];
716
if (LocaleCompare(keyword,"cx") == 0)
718
svg_info->element.cx=
719
GetUserSpaceCoordinateValue(svg_info,1,value);
722
if (LocaleCompare(keyword,"cy") == 0)
724
svg_info->element.cy=
725
GetUserSpaceCoordinateValue(svg_info,-1,value);
733
if (LocaleCompare(keyword,"fx") == 0)
735
svg_info->element.major=
736
GetUserSpaceCoordinateValue(svg_info,1,value);
739
if (LocaleCompare(keyword,"fy") == 0)
741
svg_info->element.minor=
742
GetUserSpaceCoordinateValue(svg_info,-1,value);
750
if (LocaleCompare(keyword,"height") == 0)
752
svg_info->bounds.height=
753
GetUserSpaceCoordinateValue(svg_info,-1,value);
761
if (LocaleCompare(keyword,"id") == 0)
763
(void) strncpy(id,value,MaxTextExtent-1);
771
if (LocaleCompare(keyword,"r") == 0)
773
svg_info->element.angle=
774
GetUserSpaceCoordinateValue(svg_info,0,value);
782
if (LocaleCompare(keyword,"width") == 0)
784
svg_info->bounds.width=
785
GetUserSpaceCoordinateValue(svg_info,1,value);
793
if (LocaleCompare(keyword,"x") == 0)
795
svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value);
798
if (LocaleCompare(keyword,"x1") == 0)
800
svg_info->segment.x1=
801
GetUserSpaceCoordinateValue(svg_info,1,value);
804
if (LocaleCompare(keyword,"x2") == 0)
806
svg_info->segment.x2=
807
GetUserSpaceCoordinateValue(svg_info,1,value);
815
if (LocaleCompare(keyword,"y") == 0)
817
svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value);
820
if (LocaleCompare(keyword,"y1") == 0)
822
svg_info->segment.y1=
823
GetUserSpaceCoordinateValue(svg_info,-1,value);
826
if (LocaleCompare(keyword,"y2") == 0)
828
svg_info->segment.y2=
829
GetUserSpaceCoordinateValue(svg_info,-1,value);
843
if (LocaleCompare((char *) name,"circle") == 0)
845
MVGPrintf(svg_info->file,"push graphic-context\n");
848
if (LocaleCompare((char *) name,"clipPath") == 0)
850
MVGPrintf(svg_info->file,"push clip-path '%s'\n",id);
858
if (LocaleCompare((char *) name,"defs") == 0)
860
MVGPrintf(svg_info->file,"push defs\n");
868
if (LocaleCompare((char *) name,"ellipse") == 0)
870
MVGPrintf(svg_info->file,"push graphic-context\n");
878
if (LocaleCompare((char *) name,"g") == 0)
880
MVGPrintf(svg_info->file,"push graphic-context\n");
888
if (LocaleCompare((char *) name,"image") == 0)
890
MVGPrintf(svg_info->file,"push graphic-context\n");
898
if (LocaleCompare((char *) name,"line") == 0)
900
MVGPrintf(svg_info->file,"push graphic-context\n");
903
if (LocaleCompare((char *) name,"linearGradient") == 0)
905
MVGPrintf(svg_info->file,"push gradient '%s' linear %g,%g %g,%g\n",id,
906
svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
907
svg_info->segment.y2);
915
if (LocaleCompare((char *) name,"path") == 0)
917
MVGPrintf(svg_info->file,"push graphic-context\n");
920
if (LocaleCompare((char *) name,"pattern") == 0)
922
MVGPrintf(svg_info->file,"push pattern '%s' %g,%g %g,%g\n",id,
923
svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.width,
924
svg_info->bounds.height);
927
if (LocaleCompare((char *) name,"polygon") == 0)
929
MVGPrintf(svg_info->file,"push graphic-context\n");
932
if (LocaleCompare((char *) name,"polyline") == 0)
934
MVGPrintf(svg_info->file,"push graphic-context\n");
942
if (LocaleCompare((char *) name,"radialGradient") == 0)
944
MVGPrintf(svg_info->file,"push gradient '%s' radial %g,%g %g,%g %g\n",
945
id,svg_info->element.cx,svg_info->element.cy,
946
svg_info->element.major,svg_info->element.minor,
947
svg_info->element.angle);
950
if (LocaleCompare((char *) name,"rect") == 0)
952
MVGPrintf(svg_info->file,"push graphic-context\n");
960
if (LocaleCompare((char *) name,"svg") == 0)
962
MVGPrintf(svg_info->file,"push graphic-context\n");
970
if (LocaleCompare((char *) name,"text") == 0)
972
MVGPrintf(svg_info->file,"push graphic-context\n");
975
if (LocaleCompare((char *) name,"tspan") == 0)
977
Strip(svg_info->text);
978
if (*svg_info->text != '\0')
989
text=EscapeString(svg_info->text,'\'');
990
MVGPrintf(svg_info->file,"text %g,%g '%s'\n",svg_info->bounds.x,
991
svg_info->bounds.y,text);
992
MagickFreeMemory(text);
993
draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
994
draw_info->pointsize=svg_info->pointsize;
995
draw_info->text=AllocateString(svg_info->text);
996
(void) ConcatenateString(&draw_info->text," ");
997
GetTypeMetrics(svg_info->image,draw_info,&metrics);
998
svg_info->bounds.x+=metrics.width;
999
DestroyDrawInfo(draw_info);
1000
*svg_info->text='\0';
1002
MVGPrintf(svg_info->file,"push graphic-context\n");
1010
if (attributes != (const xmlChar **) NULL)
1011
for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
1013
keyword=(const char *) attributes[i];
1014
value=(const char *) attributes[i+1];
1015
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
1016
" %.1024s = %.1024s",keyword,value);
1022
if (LocaleCompare(keyword,"angle") == 0)
1024
MVGPrintf(svg_info->file,"angle %g\n",
1025
GetUserSpaceCoordinateValue(svg_info,0,value));
1033
if (LocaleCompare(keyword,"clip-path") == 0)
1035
MVGPrintf(svg_info->file,"clip-path '%s'\n",value);
1038
if (LocaleCompare(keyword,"clip-rule") == 0)
1040
MVGPrintf(svg_info->file,"clip-rule '%s'\n",value);
1043
if (LocaleCompare(keyword,"clipPathUnits") == 0)
1045
(void) CloneString(&units,value);
1046
MVGPrintf(svg_info->file,"clip-units '%s'\n",value);
1049
if (LocaleCompare(keyword,"color") == 0)
1051
(void) CloneString(&color,value);
1054
if (LocaleCompare(keyword,"cx") == 0)
1056
svg_info->element.cx=
1057
GetUserSpaceCoordinateValue(svg_info,1,value);
1060
if (LocaleCompare(keyword,"cy") == 0)
1062
svg_info->element.cy=
1063
GetUserSpaceCoordinateValue(svg_info,-1,value);
1071
if (LocaleCompare(keyword,"d") == 0)
1073
(void) CloneString(&svg_info->vertices,value);
1076
if (LocaleCompare(keyword,"dx") == 0)
1078
svg_info->bounds.x+=
1079
GetUserSpaceCoordinateValue(svg_info,1,value);
1082
if (LocaleCompare(keyword,"dy") == 0)
1084
svg_info->bounds.y+=
1085
GetUserSpaceCoordinateValue(svg_info,-1,value);
1093
if (LocaleCompare(keyword,"fill") == 0)
1095
if (LocaleCompare(value,"currentColor") == 0)
1097
MVGPrintf(svg_info->file,"fill '%s'\n",color);
1100
MVGPrintf(svg_info->file,"fill '%s'\n",value);
1103
if (LocaleCompare(keyword,"fillcolor") == 0)
1105
MVGPrintf(svg_info->file,"fill '%s'\n",value);
1108
if (LocaleCompare(keyword,"fill-rule") == 0)
1110
MVGPrintf(svg_info->file,"fill-rule '%s'\n",value);
1113
if (LocaleCompare(keyword,"fill-opacity") == 0)
1115
MVGPrintf(svg_info->file,"fill-opacity '%s'\n",value);
1118
if (LocaleCompare(keyword,"font-family") == 0)
1120
MVGPrintf(svg_info->file,"font-family '%s'\n",value);
1123
if (LocaleCompare(keyword,"font-stretch") == 0)
1125
MVGPrintf(svg_info->file,"font-stretch '%s'\n",value);
1128
if (LocaleCompare(keyword,"font-style") == 0)
1130
MVGPrintf(svg_info->file,"font-style '%s'\n",value);
1133
if (LocaleCompare(keyword,"font-size") == 0)
1135
svg_info->pointsize=
1136
GetUserSpaceCoordinateValue(svg_info,0,value);
1137
MVGPrintf(svg_info->file,"font-size %g\n",svg_info->pointsize);
1140
if (LocaleCompare(keyword,"font-weight") == 0)
1142
MVGPrintf(svg_info->file,"font-weight '%s'\n",value);
1150
if (LocaleCompare(keyword,"gradientTransform") == 0)
1157
IdentityAffine(&transform);
1158
(void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1159
tokens=GetTransformTokens(context,value,&number_tokens);
1160
for (j=0; j < (number_tokens-1); j+=2)
1162
keyword=(char *) tokens[j];
1163
value=(char *) tokens[j+1];
1164
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
1165
" %.1024s: %.1024s",keyword,value);
1167
IdentityAffine(&affine);
1173
if (LocaleCompare(keyword,"matrix") == 0)
1176
GetToken(p,&p,token);
1177
affine.sx=atof(value);
1178
GetToken(p,&p,token);
1180
GetToken(p,&p,token);
1181
affine.rx=atof(token);
1182
GetToken(p,&p,token);
1184
GetToken(p,&p,token);
1185
affine.ry=atof(token);
1186
GetToken(p,&p,token);
1188
GetToken(p,&p,token);
1189
affine.sy=atof(token);
1190
GetToken(p,&p,token);
1192
GetToken(p,&p,token);
1193
affine.tx=atof(token);
1194
GetToken(p,&p,token);
1196
GetToken(p,&p,token);
1197
affine.ty=atof(token);
1205
if (LocaleCompare(keyword,"rotate") == 0)
1210
angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1211
affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1212
affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1213
affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1214
affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1222
if (LocaleCompare(keyword,"scale") == 0)
1224
for (p=(char *) value; *p != '\0'; p++)
1225
if (isspace((int) (*p)) || (*p == ','))
1227
affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1228
affine.sy=affine.sx;
1231
GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1232
svg_info->scale[svg_info->n]=ExpandAffine(&affine);
1235
if (LocaleCompare(keyword,"skewX") == 0)
1237
affine.sx=svg_info->affine.sx;
1238
affine.ry=tan(DegreesToRadians(fmod(
1239
GetUserSpaceCoordinateValue(svg_info,1,value),
1241
affine.sy=svg_info->affine.sy;
1244
if (LocaleCompare(keyword,"skewY") == 0)
1246
affine.sx=svg_info->affine.sx;
1247
affine.rx=tan(DegreesToRadians(fmod(
1248
GetUserSpaceCoordinateValue(svg_info,-1,value),
1250
affine.sy=svg_info->affine.sy;
1258
if (LocaleCompare(keyword,"translate") == 0)
1260
for (p=(char *) value; *p != '\0'; p++)
1261
if (isspace((int) (*p)) || (*p == ','))
1263
affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
1264
affine.ty=affine.tx;
1267
GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1275
transform.sx=current.sx*affine.sx+current.ry*affine.rx;
1276
transform.rx=current.rx*affine.sx+current.sy*affine.rx;
1277
transform.ry=current.sx*affine.ry+current.ry*affine.sy;
1278
transform.sy=current.rx*affine.ry+current.sy*affine.sy;
1279
transform.tx=current.sx*affine.tx+current.ry*affine.ty+
1281
transform.ty=current.rx*affine.tx+current.sy*affine.ty+
1284
MVGPrintf(svg_info->file,"affine %g %g %g %g %g %g\n",
1285
transform.sx,transform.rx,transform.ry,transform.sy,
1286
transform.tx,transform.ty);
1287
for (j=0; tokens[j] != (char *) NULL; j++)
1288
MagickFreeMemory(tokens[j]);
1289
MagickFreeMemory(tokens);
1292
if (LocaleCompare(keyword,"gradientUnits") == 0)
1294
(void) CloneString(&units,value);
1295
MVGPrintf(svg_info->file,"gradient-units '%s'\n",value);
1303
if (LocaleCompare(keyword,"height") == 0)
1305
svg_info->bounds.height=
1306
GetUserSpaceCoordinateValue(svg_info,-1,value);
1309
if (LocaleCompare(keyword,"href") == 0)
1311
(void) CloneString(&svg_info->url,value);
1319
if (LocaleCompare(keyword,"major") == 0)
1321
svg_info->element.major=
1322
GetUserSpaceCoordinateValue(svg_info,1,value);
1325
if (LocaleCompare(keyword,"minor") == 0)
1327
svg_info->element.minor=
1328
GetUserSpaceCoordinateValue(svg_info,-1,value);
1336
if (LocaleCompare(keyword,"offset") == 0)
1338
(void) CloneString(&svg_info->offset,value);
1341
if (LocaleCompare(keyword,"opacity") == 0)
1343
MVGPrintf(svg_info->file,"opacity '%s'\n",value);
1351
if (LocaleCompare(keyword,"path") == 0)
1353
(void) CloneString(&svg_info->url,value);
1356
if (LocaleCompare(keyword,"points") == 0)
1358
(void) CloneString(&svg_info->vertices,value);
1366
if (LocaleCompare(keyword,"r") == 0)
1368
svg_info->element.major=
1369
GetUserSpaceCoordinateValue(svg_info,1,value);
1370
svg_info->element.minor=
1371
GetUserSpaceCoordinateValue(svg_info,-1,value);
1374
if (LocaleCompare(keyword,"rotate") == 0)
1379
angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1380
MVGPrintf(svg_info->file,"translate %g,%g\n",svg_info->bounds.x,
1381
svg_info->bounds.y);
1382
svg_info->bounds.x=0;
1383
svg_info->bounds.y=0;
1384
MVGPrintf(svg_info->file,"rotate %g\n",angle);
1387
if (LocaleCompare(keyword,"rx") == 0)
1389
if (LocaleCompare((char *) name,"ellipse") == 0)
1390
svg_info->element.major=
1391
GetUserSpaceCoordinateValue(svg_info,1,value);
1394
GetUserSpaceCoordinateValue(svg_info,1,value);
1397
if (LocaleCompare(keyword,"ry") == 0)
1399
if (LocaleCompare((char *) name,"ellipse") == 0)
1400
svg_info->element.minor=
1401
GetUserSpaceCoordinateValue(svg_info,-1,value);
1404
GetUserSpaceCoordinateValue(svg_info,-1,value);
1412
if (LocaleCompare(keyword,"stop-color") == 0)
1414
(void) CloneString(&svg_info->stop_color,value);
1417
if (LocaleCompare(keyword,"stroke") == 0)
1419
if (LocaleCompare(value,"currentColor") == 0)
1421
MVGPrintf(svg_info->file,"stroke '%s'\n",color);
1424
MVGPrintf(svg_info->file,"stroke '%s'\n",value);
1427
if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1429
MVGPrintf(svg_info->file,"stroke-antialias %d\n",
1430
LocaleCompare(value,"true") == 0);
1433
if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1435
MVGPrintf(svg_info->file,"stroke-dasharray %s\n",value);
1438
if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1440
MVGPrintf(svg_info->file,"stroke-dashoffset %s\n",value);
1443
if (LocaleCompare(keyword,"stroke-linecap") == 0)
1445
MVGPrintf(svg_info->file,"stroke-linecap '%s'\n",value);
1448
if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1450
MVGPrintf(svg_info->file,"stroke-linejoin '%s'\n",value);
1453
if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1455
MVGPrintf(svg_info->file,"stroke-miterlimit '%s'\n",value);
1458
if (LocaleCompare(keyword,"stroke-opacity") == 0)
1460
MVGPrintf(svg_info->file,"stroke-opacity '%s'\n",value);
1463
if (LocaleCompare(keyword,"stroke-width") == 0)
1465
MVGPrintf(svg_info->file,"stroke-width %g\n",
1466
GetUserSpaceCoordinateValue(svg_info,1,value));
1469
if (LocaleCompare(keyword,"style") == 0)
1471
(void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1472
tokens=GetStyleTokens(context,value,&number_tokens);
1473
for (j=0; j < (number_tokens-1); j+=2)
1475
keyword=(char *) tokens[j];
1476
value=(char *) tokens[j+1];
1477
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
1478
" %.1024s: %.1024s",keyword,value);
1484
if (LocaleCompare(keyword,"clip-path") == 0)
1486
MVGPrintf(svg_info->file,"clip-path '%s'\n",value);
1489
if (LocaleCompare(keyword,"clip-rule") == 0)
1491
MVGPrintf(svg_info->file,"clip-rule '%s'\n",value);
1494
if (LocaleCompare(keyword,"clipPathUnits") == 0)
1496
(void) CloneString(&units,value);
1497
MVGPrintf(svg_info->file,"clip-units '%s'\n",value);
1500
if (LocaleCompare(keyword,"color") == 0)
1502
(void) CloneString(&color,value);
1510
if (LocaleCompare(keyword,"fill") == 0)
1512
if (LocaleCompare(value,"currentColor") == 0)
1514
MVGPrintf(svg_info->file,"fill '%s'\n",color);
1517
MVGPrintf(svg_info->file,"fill '%s'\n",value);
1520
if (LocaleCompare(keyword,"fillcolor") == 0)
1522
MVGPrintf(svg_info->file,"fill '%s'\n",value);
1525
if (LocaleCompare(keyword,"fill-rule") == 0)
1527
MVGPrintf(svg_info->file,"fill-rule '%s'\n",value);
1530
if (LocaleCompare(keyword,"fill-opacity") == 0)
1532
MVGPrintf(svg_info->file,"fill-opacity '%s'\n",value);
1535
if (LocaleCompare(keyword,"font-family") == 0)
1537
MVGPrintf(svg_info->file,"font-family '%s'\n",value);
1540
if (LocaleCompare(keyword,"font-stretch") == 0)
1542
MVGPrintf(svg_info->file,"font-stretch '%s'\n",value);
1545
if (LocaleCompare(keyword,"font-style") == 0)
1547
MVGPrintf(svg_info->file,"font-style '%s'\n",value);
1550
if (LocaleCompare(keyword,"font-size") == 0)
1552
svg_info->pointsize=
1553
GetUserSpaceCoordinateValue(svg_info,0,value);
1554
MVGPrintf(svg_info->file,"font-size %g\n",
1555
svg_info->pointsize);
1558
if (LocaleCompare(keyword,"font-weight") == 0)
1560
MVGPrintf(svg_info->file,"font-weight '%s'\n",value);
1568
if (LocaleCompare(keyword,"offset") == 0)
1570
MVGPrintf(svg_info->file,"offset %g\n",
1571
GetUserSpaceCoordinateValue(svg_info,1,value));
1574
if (LocaleCompare(keyword,"opacity") == 0)
1576
MVGPrintf(svg_info->file,"opacity '%s'\n",value);
1584
if (LocaleCompare(keyword,"stop-color") == 0)
1586
(void) CloneString(&svg_info->stop_color,value);
1589
if (LocaleCompare(keyword,"stroke") == 0)
1591
if (LocaleCompare(value,"currentColor") == 0)
1593
MVGPrintf(svg_info->file,"stroke '%s'\n",color);
1596
MVGPrintf(svg_info->file,"stroke '%s'\n",value);
1599
if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1601
MVGPrintf(svg_info->file,"stroke-antialias %d\n",
1602
LocaleCompare(value,"true") == 0);
1605
if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1607
MVGPrintf(svg_info->file,"stroke-dasharray %s\n",value);
1610
if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1612
MVGPrintf(svg_info->file,"stroke-dashoffset %s\n",
1616
if (LocaleCompare(keyword,"stroke-linecap") == 0)
1618
MVGPrintf(svg_info->file,"stroke-linecap '%s'\n",value);
1621
if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1623
MVGPrintf(svg_info->file,"stroke-linejoin '%s'\n",
1627
if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1629
MVGPrintf(svg_info->file,"stroke-miterlimit '%s'\n",
1633
if (LocaleCompare(keyword,"stroke-opacity") == 0)
1635
MVGPrintf(svg_info->file,"stroke-opacity '%s'\n",value);
1638
if (LocaleCompare(keyword,"stroke-width") == 0)
1640
MVGPrintf(svg_info->file,"stroke-width %g\n",
1641
GetUserSpaceCoordinateValue(svg_info,1,value));
1649
if (LocaleCompare(keyword,"text-align") == 0)
1651
MVGPrintf(svg_info->file,"text-align '%s'\n",value);
1654
if (LocaleCompare(keyword,"text-anchor") == 0)
1656
MVGPrintf(svg_info->file,"text-anchor '%s'\n",value);
1659
if (LocaleCompare(keyword,"text-decoration") == 0)
1661
if (LocaleCompare(value,"underline") == 0)
1662
MVGPrintf(svg_info->file,"decorate underline\n");
1663
if (LocaleCompare(value,"line-through") == 0)
1664
MVGPrintf(svg_info->file,"decorate line-through\n");
1665
if (LocaleCompare(value,"overline") == 0)
1666
MVGPrintf(svg_info->file,"decorate overline\n");
1669
if (LocaleCompare(keyword,"text-antialiasing") == 0)
1671
MVGPrintf(svg_info->file,"text-antialias %d\n",
1672
LocaleCompare(value,"true") == 0);
1681
for (j=0; tokens[j] != (char *) NULL; j++)
1682
MagickFreeMemory(tokens[j]);
1683
MagickFreeMemory(tokens);
1691
if (LocaleCompare(keyword,"text-align") == 0)
1693
MVGPrintf(svg_info->file,"text-align '%s'\n",value);
1696
if (LocaleCompare(keyword,"text-anchor") == 0)
1698
MVGPrintf(svg_info->file,"text-anchor '%s'\n",value);
1701
if (LocaleCompare(keyword,"text-decoration") == 0)
1703
if (LocaleCompare(value,"underline") == 0)
1704
MVGPrintf(svg_info->file,"decorate underline\n");
1705
if (LocaleCompare(value,"line-through") == 0)
1706
MVGPrintf(svg_info->file,"decorate line-through\n");
1707
if (LocaleCompare(value,"overline") == 0)
1708
MVGPrintf(svg_info->file,"decorate overline\n");
1711
if (LocaleCompare(keyword,"text-antialiasing") == 0)
1713
MVGPrintf(svg_info->file,"text-antialias %d\n",
1714
LocaleCompare(value,"true") == 0);
1717
if (LocaleCompare(keyword,"transform") == 0)
1724
IdentityAffine(&transform);
1725
(void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1726
tokens=GetTransformTokens(context,value,&number_tokens);
1727
for (j=0; j < (number_tokens-1); j+=2)
1729
keyword=(char *) tokens[j];
1730
value=(char *) tokens[j+1];
1731
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
1732
" %.1024s: %.1024s",keyword,value);
1734
IdentityAffine(&affine);
1740
if (LocaleCompare(keyword,"matrix") == 0)
1743
GetToken(p,&p,token);
1744
affine.sx=atof(value);
1745
GetToken(p,&p,token);
1747
GetToken(p,&p,token);
1748
affine.rx=atof(token);
1749
GetToken(p,&p,token);
1751
GetToken(p,&p,token);
1752
affine.ry=atof(token);
1753
GetToken(p,&p,token);
1755
GetToken(p,&p,token);
1756
affine.sy=atof(token);
1757
GetToken(p,&p,token);
1759
GetToken(p,&p,token);
1760
affine.tx=atof(token);
1761
GetToken(p,&p,token);
1763
GetToken(p,&p,token);
1764
affine.ty=atof(token);
1772
if (LocaleCompare(keyword,"rotate") == 0)
1777
angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1778
affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1779
affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1780
affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1781
affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1789
if (LocaleCompare(keyword,"scale") == 0)
1791
for (p=(char *) value; *p != '\0'; p++)
1792
if (isspace((int) (*p)) || (*p == ','))
1794
affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1795
affine.sy=affine.sx;
1798
GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1799
svg_info->scale[svg_info->n]=ExpandAffine(&affine);
1802
if (LocaleCompare(keyword,"skewX") == 0)
1804
affine.sx=svg_info->affine.sx;
1805
affine.ry=tan(DegreesToRadians(fmod(
1806
GetUserSpaceCoordinateValue(svg_info,1,value),
1808
affine.sy=svg_info->affine.sy;
1811
if (LocaleCompare(keyword,"skewY") == 0)
1813
affine.sx=svg_info->affine.sx;
1814
affine.rx=tan(DegreesToRadians(fmod(
1815
GetUserSpaceCoordinateValue(svg_info,-1,value),
1817
affine.sy=svg_info->affine.sy;
1825
if (LocaleCompare(keyword,"translate") == 0)
1827
for (p=(char *) value; *p != '\0'; p++)
1828
if (isspace((int) (*p)) || (*p == ','))
1830
affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
1831
affine.ty=affine.tx;
1834
GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1842
transform.sx=current.sx*affine.sx+current.ry*affine.rx;
1843
transform.rx=current.rx*affine.sx+current.sy*affine.rx;
1844
transform.ry=current.sx*affine.ry+current.ry*affine.sy;
1845
transform.sy=current.rx*affine.ry+current.sy*affine.sy;
1846
transform.tx=current.sx*affine.tx+current.ry*affine.ty+
1848
transform.ty=current.rx*affine.tx+current.sy*affine.ty+
1851
MVGPrintf(svg_info->file,"affine %g %g %g %g %g %g\n",
1852
transform.sx,transform.rx,transform.ry,transform.sy,
1853
transform.tx,transform.ty);
1854
for (j=0; tokens[j] != (char *) NULL; j++)
1855
MagickFreeMemory(tokens[j]);
1856
MagickFreeMemory(tokens);
1864
if (LocaleCompare(keyword,"verts") == 0)
1866
(void) CloneString(&svg_info->vertices,value);
1869
if (LocaleCompare(keyword,"viewBox") == 0)
1872
GetToken(p,&p,token);
1873
svg_info->view_box.x=atof(token);
1874
GetToken(p,&p,token);
1876
GetToken(p,&p,token);
1877
svg_info->view_box.y=atof(token);
1878
GetToken(p,&p,token);
1880
GetToken(p,&p,token);
1881
svg_info->view_box.width=atof(token);
1882
if (svg_info->bounds.width == 0)
1883
svg_info->bounds.width=svg_info->view_box.width;
1884
GetToken(p,&p,token);
1886
GetToken(p,&p,token);
1887
svg_info->view_box.height=atof(token);
1888
if (svg_info->bounds.height == 0)
1889
svg_info->bounds.height=svg_info->view_box.height;
1897
if (LocaleCompare(keyword,"width") == 0)
1899
svg_info->bounds.width=
1900
GetUserSpaceCoordinateValue(svg_info,1,value);
1908
if (LocaleCompare(keyword,"x") == 0)
1910
svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value);
1913
if (LocaleCompare(keyword,"xlink:href") == 0)
1915
(void) CloneString(&svg_info->url,value);
1918
if (LocaleCompare(keyword,"x1") == 0)
1920
svg_info->segment.x1=
1921
GetUserSpaceCoordinateValue(svg_info,1,value);
1924
if (LocaleCompare(keyword,"x2") == 0)
1926
svg_info->segment.x2=
1927
GetUserSpaceCoordinateValue(svg_info,1,value);
1935
if (LocaleCompare(keyword,"y") == 0)
1937
svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value);
1940
if (LocaleCompare(keyword,"y1") == 0)
1942
svg_info->segment.y1=
1943
GetUserSpaceCoordinateValue(svg_info,-1,value);
1946
if (LocaleCompare(keyword,"y2") == 0)
1948
svg_info->segment.y2=
1949
GetUserSpaceCoordinateValue(svg_info,-1,value);
1958
#ifdef BROKEN_SIZE_OPTION
1959
if (LocaleCompare((char *) name,"svg") == 0)
1961
if (svg_info->document->encoding != (const xmlChar *) NULL)
1962
MVGPrintf(svg_info->file,"encoding %.1024s\n",
1963
(char *) svg_info->document->encoding);
1964
if (attributes != (const xmlChar **) NULL)
1970
if ((svg_info->view_box.width == 0.0) ||
1971
(svg_info->view_box.height == 0.0))
1972
svg_info->view_box=svg_info->bounds;
1973
svg_info->width=(unsigned long) svg_info->bounds.width;
1974
svg_info->height=(unsigned long) svg_info->bounds.height;
1975
MVGPrintf(svg_info->file,"viewbox 0 0 %lu %lu\n",svg_info->width,
1978
Set initial canvas background color to user specified value
1982
tuple[MaxTextExtent];
1984
GetColorTuple(&svg_info->image_info->background_color,8,True,True,
1987
MVGPrintf(svg_info->file,"push graphic-context\n");
1988
MVGPrintf(svg_info->file,"fill %s\n", tuple);
1989
MVGPrintf(svg_info->file,"rectangle 0,0 %g,%g\n",
1990
svg_info->view_box.width,svg_info->view_box.height);
1991
MVGPrintf(svg_info->file,"pop graphic-context\n");
1993
sx=(double) svg_info->width/svg_info->view_box.width;
1994
sy=(double) svg_info->height/svg_info->view_box.height;
1995
MVGPrintf(svg_info->file,"affine %g 0 0 %g %g %g\n",sx,sy,
1996
-sx*svg_info->view_box.x,-sy*svg_info->view_box.y);
2000
if (LocaleCompare((char *) name,"svg") == 0)
2002
if (svg_info->document->encoding != (const xmlChar *) NULL)
2003
(void) fprintf(svg_info->file,"encoding %.1024s\n",
2004
(char *) svg_info->document->encoding);
2005
if (attributes != (const xmlChar **) NULL)
2018
if ((svg_info->view_box.width == 0.0) ||
2019
(svg_info->view_box.height == 0.0))
2020
svg_info->view_box=svg_info->bounds;
2021
SetGeometry(svg_info->image,&page);
2022
page.width=(unsigned long) svg_info->bounds.width;
2023
page.height=(unsigned long) svg_info->bounds.height;
2024
geometry=(char *) NULL;
2025
/* at one point we use to try to use either page geometry
2026
or size to set the dimensions of the output page, but
2027
now we only look for size
2029
#ifdef PARSE_PAGE_FIRST
2030
if (svg_info->page != (char *) NULL)
2031
geometry=GetPageGeometry(svg_info->page);
2034
if (svg_info->size != (char *) NULL)
2035
geometry=GetPageGeometry(svg_info->size);
2036
if (geometry != (char *) NULL)
2038
p=strchr(geometry,'>');
2039
if (p != (char *) NULL)
2041
(void) GetMagickGeometry(geometry,&page.x,&page.y,
2042
&page.width,&page.height);
2043
MagickFreeMemory(geometry);
2045
if (svg_info->affine.sx != 1.0)
2046
page.width=(unsigned long)
2047
ceil(ExpandAffine(&svg_info->affine)*page.width-0.5);
2048
if (svg_info->affine.sy != 0.0)
2049
page.height=(unsigned long)
2050
ceil(ExpandAffine(&svg_info->affine)*page.height-0.5);
2051
(void) MVGPrintf(svg_info->file,"viewbox 0 0 %g %g\n",
2052
svg_info->view_box.width,svg_info->view_box.height);
2053
sx=(double) page.width/svg_info->view_box.width;
2054
sy=(double) page.height/svg_info->view_box.height;
2055
MVGPrintf(svg_info->file,"affine %g 0 0 %g %g %g\n",sx,sy,
2056
-sx*svg_info->view_box.x,-sy*svg_info->view_box.y);
2057
svg_info->width=page.width;
2058
svg_info->height=page.height;
2062
(void) LogMagickEvent(CoderEvent,GetMagickModule()," )");
2063
MagickFreeMemory(units);
2064
if (color != (char *) NULL)
2065
MagickFreeMemory(color);
2068
static void SVGEndElement(void *context,const xmlChar *name)
2074
Called when the end of an element has been detected.
2076
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
2077
" SAX.endElement(%.1024s)",name);
2078
svg_info=(SVGInfo *) context;
2084
if (LocaleCompare((char *) name,"circle") == 0)
2086
MVGPrintf(svg_info->file,"circle %g,%g %g,%g\n",svg_info->element.cx,
2087
svg_info->element.cy,svg_info->element.cx,svg_info->element.cy+
2088
svg_info->element.minor);
2089
MVGPrintf(svg_info->file,"pop graphic-context\n");
2092
if (LocaleCompare((char *) name,"clipPath") == 0)
2094
MVGPrintf(svg_info->file,"pop clip-path\n");
2102
if (LocaleCompare((char *) name,"defs") == 0)
2104
MVGPrintf(svg_info->file,"pop defs\n");
2107
if (LocaleCompare((char *) name,"desc") == 0)
2112
Strip(svg_info->text);
2113
if (*svg_info->text == '\0')
2115
(void) fputc('#',svg_info->file);
2116
for (p=svg_info->text; *p != '\0'; p++)
2118
(void) fputc(*p,svg_info->file);
2120
(void) fputc('#',svg_info->file);
2122
(void) fputc('\n',svg_info->file);
2123
*svg_info->text='\0';
2131
if (LocaleCompare((char *) name,"ellipse") == 0)
2136
angle=svg_info->element.angle;
2137
MVGPrintf(svg_info->file,"ellipse %g,%g %g,%g 0,360\n",
2138
svg_info->element.cx,svg_info->element.cy,
2139
angle == 0.0 ? svg_info->element.major : svg_info->element.minor,
2140
angle == 0.0 ? svg_info->element.minor : svg_info->element.major);
2141
MVGPrintf(svg_info->file,"pop graphic-context\n");
2149
if (LocaleCompare((char *) name,"g") == 0)
2151
MVGPrintf(svg_info->file,"pop graphic-context\n");
2159
if (LocaleCompare((char *) name,"image") == 0)
2161
MVGPrintf(svg_info->file,"image Copy %g,%g %g,%g '%s'\n",
2162
svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.width,
2163
svg_info->bounds.height,svg_info->url);
2164
MVGPrintf(svg_info->file,"pop graphic-context\n");
2172
if (LocaleCompare((char *) name,"line") == 0)
2174
MVGPrintf(svg_info->file,"line %g,%g %g,%g\n",svg_info->segment.x1,
2175
svg_info->segment.y1,svg_info->segment.x2,svg_info->segment.y2);
2176
MVGPrintf(svg_info->file,"pop graphic-context\n");
2179
if (LocaleCompare((char *) name,"linearGradient") == 0)
2181
MVGPrintf(svg_info->file,"pop gradient\n");
2189
if (LocaleCompare((char *) name,"pattern") == 0)
2191
MVGPrintf(svg_info->file,"pop pattern\n");
2194
if (LocaleCompare((char *) name,"path") == 0)
2196
MVGPrintf(svg_info->file,"path '%s'\n",svg_info->vertices);
2197
MVGPrintf(svg_info->file,"pop graphic-context\n");
2200
if (LocaleCompare((char *) name,"polygon") == 0)
2202
MVGPrintf(svg_info->file,"polygon %s\n",svg_info->vertices);
2203
MVGPrintf(svg_info->file,"pop graphic-context\n");
2206
if (LocaleCompare((char *) name,"polyline") == 0)
2208
MVGPrintf(svg_info->file,"polyline %s\n",svg_info->vertices);
2209
MVGPrintf(svg_info->file,"pop graphic-context\n");
2217
if (LocaleCompare((char *) name,"radialGradient") == 0)
2219
MVGPrintf(svg_info->file,"pop gradient\n");
2222
if (LocaleCompare((char *) name,"rect") == 0)
2224
if ((svg_info->radius.x == 0.0) && (svg_info->radius.y == 0.0))
2226
MVGPrintf(svg_info->file,"rectangle %g,%g %g,%g\n",
2227
svg_info->bounds.x,svg_info->bounds.y,
2228
svg_info->bounds.x+svg_info->bounds.width,
2229
svg_info->bounds.y+svg_info->bounds.height);
2230
MVGPrintf(svg_info->file,"pop graphic-context\n");
2233
if (svg_info->radius.x == 0.0)
2234
svg_info->radius.x=svg_info->radius.y;
2235
if (svg_info->radius.y == 0.0)
2236
svg_info->radius.y=svg_info->radius.x;
2237
MVGPrintf(svg_info->file,"roundRectangle %g,%g %g,%g %g,%g\n",
2238
svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.x+
2239
svg_info->bounds.width,svg_info->bounds.y+svg_info->bounds.height,
2240
svg_info->radius.x,svg_info->radius.y);
2241
svg_info->radius.x=0.0;
2242
svg_info->radius.y=0.0;
2243
MVGPrintf(svg_info->file,"pop graphic-context\n");
2251
if (LocaleCompare((char *) name,"stop") == 0)
2253
MVGPrintf(svg_info->file,"stop-color '%s' %s\n",svg_info->stop_color,
2257
if (LocaleCompare((char *) name,"svg") == 0)
2259
MVGPrintf(svg_info->file,"pop graphic-context\n");
2267
if (LocaleCompare((char *) name,"text") == 0)
2269
Strip(svg_info->text);
2270
if (*svg_info->text != '\0')
2275
text=EscapeString(svg_info->text,'\'');
2276
MVGPrintf(svg_info->file,"text %g,%g '%s'\n",svg_info->bounds.x,
2277
svg_info->bounds.y,text);
2278
MagickFreeMemory(text);
2279
*svg_info->text='\0';
2281
MVGPrintf(svg_info->file,"pop graphic-context\n");
2284
if (LocaleCompare((char *) name,"tspan") == 0)
2286
Strip(svg_info->text);
2287
if (*svg_info->text != '\0')
2298
text=EscapeString(svg_info->text,'\'');
2299
MVGPrintf(svg_info->file,"text %g,%g '%s'\n",svg_info->bounds.x,
2300
svg_info->bounds.y,text);
2301
MagickFreeMemory(text);
2302
draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
2303
draw_info->pointsize=svg_info->pointsize;
2304
draw_info->text=AllocateString(svg_info->text);
2305
(void) ConcatenateString(&draw_info->text," ");
2306
GetTypeMetrics(svg_info->image,draw_info,&metrics);
2307
svg_info->bounds.x+=metrics.width;
2308
DestroyDrawInfo(draw_info);
2309
*svg_info->text='\0';
2311
MVGPrintf(svg_info->file,"pop graphic-context\n");
2314
if (LocaleCompare((char *) name,"title") == 0)
2316
Strip(svg_info->text);
2317
if (*svg_info->text == '\0')
2319
(void) CloneString(&svg_info->title,svg_info->text);
2320
*svg_info->text='\0';
2328
(void) memset(&svg_info->segment,0,sizeof(svg_info->segment));
2332
static void SVGCharacters(void *context,const xmlChar *c,int length)
2344
Receiving some characters from the parser.
2346
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
2347
" SAX.characters(%.1024s,%d)",c,length);
2348
svg_info=(SVGInfo *) context;
2349
if (svg_info->text != (char *) NULL)
2351
MagickReallocMemory(svg_info->text,strlen(svg_info->text)+length+1);
2355
svg_info->text=MagickAllocateMemory(char *,length+1);
2356
if (svg_info->text != (char *) NULL)
2357
*svg_info->text='\0';
2359
if (svg_info->text == (char *) NULL)
2361
p=svg_info->text+strlen(svg_info->text);
2362
for (i=0; i < length; i++)
2367
static void SVGReference(void *context,const xmlChar *name)
2376
Called when an entity reference is detected.
2378
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
2379
" SAX.reference(%.1024s)",name);
2380
svg_info=(SVGInfo *) context;
2381
parser=svg_info->parser;
2383
(void) xmlAddChild(parser->node,xmlNewCharRef(svg_info->document,name));
2385
(void) xmlAddChild(parser->node,xmlNewReference(svg_info->document,name));
2388
static void SVGIgnorableWhitespace(void *context,const xmlChar *c,int length)
2394
Receiving some ignorable whitespaces from the parser.
2396
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
2397
" SAX.ignorableWhitespace(%.30s, %d)",c,length);
2398
/* svg_info=(SVGInfo *) context; */
2401
static void SVGProcessingInstructions(void *context,const xmlChar *target,
2402
const xmlChar *data)
2408
A processing instruction has been parsed.
2410
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
2411
" SAX.processingInstruction(%.1024s, %.1024s)",
2413
/* svg_info=(SVGInfo *) context; */
2416
static void SVGComment(void *context,const xmlChar *value)
2422
A comment has been parsed.
2424
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
2425
" SAX.comment(%.1024s)",value);
2426
svg_info=(SVGInfo *) context;
2427
if (svg_info->comment != (char *) NULL)
2428
(void) ConcatenateString(&svg_info->comment,"\n");
2429
(void) ConcatenateString(&svg_info->comment,(char *) value);
2432
static void SVGWarning(void *context,const char *format,...)
2435
reason[MaxTextExtent];
2444
Display and format a warning messages, gives file, line, position and
2447
va_start(operands,format);
2448
svg_info=(SVGInfo *) context;
2449
(void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.warning: ");
2450
(void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2451
#if !defined(HAVE_VSNPRINTF)
2452
(void) vsprintf(reason,format,operands);
2454
(void) vsnprintf(reason,MaxTextExtent,format,operands);
2456
ThrowException2(svg_info->exception,DelegateWarning,reason,(char *) NULL);
2460
static void SVGError(void *context,const char *format,...)
2463
reason[MaxTextExtent];
2472
Display and format a error formats, gives file, line, position and
2475
va_start(operands,format);
2476
svg_info=(SVGInfo *) context;
2477
(void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.error: ");
2478
(void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2479
#if !defined(HAVE_VSNPRINTF)
2480
(void) vsprintf(reason,format,operands);
2482
(void) vsnprintf(reason,MaxTextExtent,format,operands);
2484
ThrowException2(svg_info->exception,CoderError,reason,(char *) NULL);
2488
static void SVGCDataBlock(void *context,const xmlChar *value,int length)
2500
Called when a pcdata block has been parsed.
2502
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
2503
" SAX.pcdata(%.1024s, %d)",value,length);
2504
svg_info=(SVGInfo *) context;
2505
parser=svg_info->parser;
2506
child=xmlGetLastChild(parser->node);
2507
if ((child != (xmlNodePtr) NULL) && (child->type == XML_CDATA_SECTION_NODE))
2509
xmlTextConcat(child,value,length);
2512
(void) xmlAddChild(parser->node,xmlNewCDataBlock(parser->myDoc,value,length));
2515
static void SVGExternalSubset(void *context,const xmlChar *name,
2516
const xmlChar *external_id,const xmlChar *system_id)
2531
Does this document has an external subset?
2533
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
2534
" SAX.externalSubset(%.1024s, %.1024s, %.1024s)",name,
2535
(external_id != (const xmlChar *) NULL ? (char *) external_id : "none"),
2536
(system_id != (const xmlChar *) NULL ? (char *) system_id : "none"));
2537
svg_info=(SVGInfo *) context;
2538
parser=svg_info->parser;
2539
if (((external_id == NULL) && (system_id == NULL)) ||
2540
(!parser->validate || !parser->wellFormed || !svg_info->document))
2542
input=SVGResolveEntity(context,external_id,system_id);
2545
(void) xmlNewDtd(svg_info->document,name,external_id,system_id);
2546
parser_context=(*parser);
2547
parser->inputTab=(xmlParserInputPtr *) xmlMalloc(5*sizeof(*parser->inputTab));
2548
if (parser->inputTab == (xmlParserInputPtr *) NULL)
2550
parser->errNo=XML_ERR_NO_MEMORY;
2551
parser->input=parser_context.input;
2552
parser->inputNr=parser_context.inputNr;
2553
parser->inputMax=parser_context.inputMax;
2554
parser->inputTab=parser_context.inputTab;
2560
xmlPushInput(parser,input);
2561
(void) xmlSwitchEncoding(parser,xmlDetectCharEncoding(parser->input->cur,4));
2562
if (input->filename == (char *) NULL)
2563
input->filename=(char *) xmlStrdup(system_id);
2566
input->base=parser->input->cur;
2567
input->cur=parser->input->cur;
2569
xmlParseExternalSubset(parser,external_id,system_id);
2570
while (parser->inputNr > 1)
2571
(void) xmlPopInput(parser);
2572
xmlFreeInputStream(parser->input);
2573
xmlFree(parser->inputTab);
2574
parser->input=parser_context.input;
2575
parser->inputNr=parser_context.inputNr;
2576
parser->inputMax=parser_context.inputMax;
2577
parser->inputTab=parser_context.inputTab;
2580
#if defined(__cplusplus) || defined(c_plusplus)
2584
static Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
2591
SVGHasInternalSubset,
2592
SVGHasExternalSubset,
2595
SVGEntityDeclaration,
2596
SVGNotationDeclaration,
2597
SVGAttributeDeclaration,
2598
SVGElementDeclaration,
2599
SVGUnparsedEntityDeclaration,
2600
SVGSetDocumentLocator,
2607
SVGIgnorableWhitespace,
2608
SVGProcessingInstructions,
2613
SVGGetParameterEntity,
2619
filename[MaxTextExtent],
2620
geometry[MaxTextExtent],
2621
message[MaxTextExtent];
2644
assert(image_info != (const ImageInfo *) NULL);
2645
assert(image_info->signature == MagickSignature);
2646
assert(exception != (ExceptionInfo *) NULL);
2647
assert(exception->signature == MagickSignature);
2648
image=AllocateImage(image_info);
2649
status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2650
if (status == False)
2651
ThrowReaderException(FileOpenError,UnableToOpenFile,image);
2655
file=AcquireTemporaryFileStream(filename,TextFileIOMode);
2656
if (file == (FILE *) NULL)
2657
ThrowReaderTemporaryFileException(filename);
2661
(void) memset(&svg_info,0,sizeof(SVGInfo));
2663
svg_info.exception=exception;
2664
svg_info.image=image;
2665
svg_info.image_info=image_info;
2666
svg_info.text=AllocateString("");
2667
svg_info.scale=MagickAllocateMemory(double *,sizeof(double));
2668
if (svg_info.scale == (double *) NULL)
2670
(void) fclose(file);
2671
LiberateTemporaryFile(filename);
2672
ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
2674
IdentityAffine(&svg_info.affine);
2676
image->x_resolution == 0.0 ? 1.0 : image->x_resolution/72.0;
2678
image->y_resolution == 0.0 ? 1.0 : image->y_resolution/72.0;
2679
svg_info.scale[0]=ExpandAffine(&svg_info.affine);
2680
svg_info.bounds.width=image->columns;
2681
svg_info.bounds.height=image->rows;
2682
if (image_info->size != (char *) NULL)
2683
(void) CloneString(&svg_info.size,image_info->size);
2684
(void) LogMagickEvent(CoderEvent,GetMagickModule(),"begin SAX");
2685
(void) xmlSubstituteEntitiesDefault(1);
2686
SAXHandler=(&SAXModules);
2687
svg_info.parser=xmlCreatePushParserCtxt(SAXHandler,&svg_info,(char *) NULL,0,
2689
while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
2691
status=xmlParseChunk(svg_info.parser,message,(int) n,False);
2695
(void) xmlParseChunk(svg_info.parser,message,0,True);
2696
xmlFreeParserCtxt(svg_info.parser);
2697
(void) LogMagickEvent(CoderEvent,GetMagickModule(),"end SAX");
2699
(void) fclose(file);
2701
DestroyImage(image);
2702
image=(Image *) NULL;
2703
if (!image_info->ping && (exception->severity == UndefinedException))
2711
clone_info=CloneImageInfo(image_info);
2712
clone_info->blob=(void *) NULL;
2713
clone_info->length=0;
2714
FormatString(geometry,"%ldx%ld",svg_info.width,svg_info.height);
2715
(void) CloneString(&clone_info->size,geometry);
2716
FormatString(clone_info->filename,"mvg:%.1024s",filename);
2717
if (clone_info->density != (char *) NULL)
2718
MagickFreeMemory(clone_info->density);
2719
image=ReadImage(clone_info,exception);
2720
DestroyImageInfo(clone_info);
2721
if (image != (Image *) NULL)
2722
(void) strncpy(image->filename,image_info->filename,MaxTextExtent-1);
2727
if (svg_info.title != (char *) NULL)
2729
if (image != (Image *) NULL)
2730
(void) SetImageAttribute(image,"title",svg_info.title);
2731
MagickFreeMemory(svg_info.title);
2733
if (svg_info.comment != (char *) NULL)
2735
if (image != (Image *) NULL)
2736
(void) SetImageAttribute(image,"comment",svg_info.comment);
2737
MagickFreeMemory(svg_info.comment);
2739
LiberateTemporaryFile(filename);
2745
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2749
% R e g i s t e r S V G I m a g e %
2753
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2755
% Method RegisterSVGImage adds attributes for the SVG image format to
2756
% the list of supported formats. The attributes include the image format
2757
% tag, a method to read and/or write the format, whether the format
2758
% supports the saving of more than one frame to the same file or blob,
2759
% whether the format supports native in-memory I/O, and a brief
2760
% description of the format.
2762
% The format of the RegisterSVGImage method is:
2764
% RegisterSVGImage(void)
2767
ModuleExport void RegisterSVGImage(void)
2770
version[MaxTextExtent];
2776
#if defined(LIBXML_DOTTED_VERSION)
2777
(void) strncpy(version,"XML " LIBXML_DOTTED_VERSION,MaxTextExtent-1);
2779
entry=SetMagickInfo("SVG");
2781
entry->decoder=(DecoderHandler) ReadSVGImage;
2783
entry->encoder=(EncoderHandler) WriteSVGImage;
2784
entry->description=AcquireString("Scalable Vector Gaphics");
2785
if (*version != '\0')
2786
entry->version=AcquireString(version);
2787
entry->module=AcquireString("SVG");
2788
(void) RegisterMagickInfo(entry);
2790
entry=SetMagickInfo("SVGZ");
2792
entry->decoder=(DecoderHandler) ReadSVGImage;
2794
entry->encoder=(EncoderHandler) WriteSVGImage;
2795
entry->description=AcquireString("Scalable Vector Gaphics (ZIP compressed)");
2796
if (*version != '\0')
2797
entry->version=AcquireString(version);
2798
entry->module=AcquireString("SVG");
2799
(void) RegisterMagickInfo(entry);
2803
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2807
% U n r e g i s t e r S V G I m a g e %
2811
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2813
% Method UnregisterSVGImage removes format registrations made by the
2814
% SVG module from the list of supported formats.
2816
% The format of the UnregisterSVGImage method is:
2818
% UnregisterSVGImage(void)
2821
ModuleExport void UnregisterSVGImage(void)
2823
(void) UnregisterMagickInfo("SVG");
2824
(void) UnregisterMagickInfo("SVGZ");
2828
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2832
% W r i t e S V G I m a g e %
2836
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2838
% Method WriteSVGImage writes a image in the SVG - XML based W3C standard
2841
% The format of the WriteSVGImage method is:
2843
% unsigned int WriteSVGImage(const ImageInfo *image_info,Image *image)
2845
% A description of each parameter follows.
2847
% o status: Method WriteSVGImage return True if the image is written.
2848
% False is returned is there is a memory shortage or if the image file
2851
% o image_info: Specifies a pointer to a ImageInfo structure.
2853
% o image: A pointer to an Image structure.
2858
#if defined(HasAUTOTRACE)
2859
static unsigned int WriteSVGImage(const ImageInfo *image_info,Image *image)
2879
pixel_outline_list_type
2891
spline_list_array_type
2907
quantize_info=(QuantizeObj *) NULL;
2909
fit_info=new_fitting_opts();
2910
output_writer=output_get_handler("svg");
2911
if (output_writer == NULL)
2912
ThrowWriterException(DelegateError,UnableToWriteSVGFormat,image);
2913
image_type=GetImageType(image);
2915
if ((image_type == BilevelType) || (image_type == GrayscaleType))
2917
bitmap.np=number_planes;
2918
bitmap.dimensions.width=image->columns;
2919
bitmap.dimensions.height=image->rows;
2920
number_pixels=image->columns*image->rows;
2921
bitmap.bitmap=MagickAllocateMemory(unsigned char *,number_planes*number_pixels);
2922
if (bitmap.bitmap == (unsigned char *) NULL)
2923
ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image);
2925
for (j=0; j < image->rows; j++)
2927
for (i=0; i < image->columns; i++)
2929
p=GetOnePixel(image,i,j);
2930
bitmap.bitmap[point++]=pixel->red;
2931
if (number_planes == 3)
2933
bitmap.bitmap[point++]=pixel->green;
2934
bitmap.bitmap[point++]=pixel->blue;
2938
image_header.width=DIMENSIONS_WIDTH(bitmap.dimensions);
2939
image_header.height=DIMENSIONS_HEIGHT(bitmap.dimensions);
2940
if ((fit_info.color_count > 0) && (BITMAP_PLANES(bitmap) == 3))
2941
quantize(bitmap.bitmap,bitmap.bitmap,DIMENSIONS_WIDTH(bitmap.dimensions),
2942
DIMENSIONS_HEIGHT(bitmap.dimensions),fit_info.color_count,
2943
fit_info.bgColor,&quantize_info);
2945
thin_image(&bitmap);
2946
pixels=find_outline_pixels (bitmap);
2947
MagickFreeMemory((bitmap.bitmap));
2948
splines=fitted_splines(pixels,&fit_info);
2949
output_file=fopen(image->filename,"w");
2950
if (output_file == (FILE *) NULL)
2951
ThrowWriterException(FileOpenError,UnableOpenFile,image);
2952
output_writer(output_file,image->filename,0,0,image_header.width,
2953
image_header.height,splines);
2957
static void AffineToTransform(Image *image,AffineMatrix *affine)
2960
transform[MaxTextExtent];
2962
if ((fabs(affine->tx) < MagickEpsilon) && (fabs(affine->ty) < MagickEpsilon))
2964
if ((fabs(affine->rx) < MagickEpsilon) &&
2965
(fabs(affine->ry) < MagickEpsilon))
2967
if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
2968
(fabs(affine->sy-1.0) < MagickEpsilon))
2970
(void) WriteBlobString(image,"\">\n");
2973
FormatString(transform,"\" transform=\"scale(%g,%g)\">\n",
2974
affine->sx,affine->sy);
2975
(void) WriteBlobString(image,transform);
2980
if ((fabs(affine->sx-affine->sy) < MagickEpsilon) &&
2981
(fabs(affine->rx+affine->ry) < MagickEpsilon) &&
2982
(fabs(affine->sx*affine->sx+affine->rx*affine->rx-1.0) <
2988
theta=(180.0/MagickPI)*atan2(affine->rx,affine->sx);
2989
FormatString(transform,"\" transform=\"rotate(%g)\">\n",theta);
2990
(void) WriteBlobString(image,transform);
2997
if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
2998
(fabs(affine->rx) < MagickEpsilon) &&
2999
(fabs(affine->ry) < MagickEpsilon) &&
3000
(fabs(affine->sy-1.0) < MagickEpsilon))
3002
FormatString(transform,"\" transform=\"translate(%g,%g)\">\n",
3003
affine->tx,affine->ty);
3004
(void) WriteBlobString(image,transform);
3008
FormatString(transform,"\" transform=\"matrix(%g %g %g %g %g %g)\">\n",
3009
affine->sx,affine->rx,affine->ry,affine->sy,affine->tx,affine->ty);
3010
(void) WriteBlobString(image,transform);
3013
static inline unsigned int IsPoint(const char *point)
3018
(void) strtol(point,&p,10);
3022
static unsigned int WriteSVGImage(const ImageInfo *image_info,Image *image)
3024
#define BezierQuantum 200
3030
keyword[MaxTextExtent],
3031
message[MaxTextExtent],
3032
name[MaxTextExtent],
3036
type[MaxTextExtent];
3038
const ImageAttribute
3076
Open output image file.
3078
assert(image_info != (const ImageInfo *) NULL);
3079
assert(image_info->signature == MagickSignature);
3080
assert(image != (Image *) NULL);
3081
assert(image->signature == MagickSignature);
3082
attribute=GetImageAttribute(image,"[MVG]");
3083
if ((attribute == (ImageAttribute *) NULL) ||
3084
(attribute->value == (char *) NULL))
3085
ThrowWriterException(CoderError,NoImageVectorGraphics,image);
3086
status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
3087
if (status == False)
3088
ThrowWriterException(FileOpenError,UnableToOpenFile,image);
3092
(void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3093
(void) WriteBlobString(image,
3094
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3095
(void) WriteBlobString(image,
3096
" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3097
(void) FormatString(message,"<svg width=\"%lu\" height=\"%lu\">\n",
3098
image->columns,image->rows);
3099
(void) WriteBlobString(image,message);
3101
Allocate primitive info memory.
3104
primitive_info=MagickAllocateMemory(PrimitiveInfo *,
3105
number_points*sizeof(PrimitiveInfo));
3106
if (primitive_info == (PrimitiveInfo *) NULL)
3107
ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image);
3108
IdentityAffine(&affine);
3109
token=AllocateString(attribute->value);
3113
for (q=attribute->value; *q != '\0'; )
3116
Interpret graphic primitive.
3118
GetToken(q,&q,keyword);
3119
if (*keyword == '\0')
3121
if (*keyword == '#')
3128
AffineToTransform(image,&affine);
3131
(void) WriteBlobString(image,"<desc>");
3132
(void) WriteBlobString(image,keyword+1);
3133
for ( ; (*q != '\n') && (*q != '\0'); q++)
3136
case '<': (void) WriteBlobString(image,"<"); break;
3137
case '>': (void) WriteBlobString(image,">"); break;
3138
case '&': (void) WriteBlobString(image,"&"); break;
3139
default: (void) WriteBlobByte(image,*q); break;
3141
(void) WriteBlobString(image,"</desc>\n");
3144
primitive_type=UndefinedPrimitive;
3152
if (LocaleCompare("affine",keyword) == 0)
3154
GetToken(q,&q,token);
3155
affine.sx=atof(token);
3156
GetToken(q,&q,token);
3158
GetToken(q,&q,token);
3159
affine.rx=atof(token);
3160
GetToken(q,&q,token);
3162
GetToken(q,&q,token);
3163
affine.ry=atof(token);
3164
GetToken(q,&q,token);
3166
GetToken(q,&q,token);
3167
affine.sy=atof(token);
3168
GetToken(q,&q,token);
3170
GetToken(q,&q,token);
3171
affine.tx=atof(token);
3172
GetToken(q,&q,token);
3174
GetToken(q,&q,token);
3175
affine.ty=atof(token);
3178
if (LocaleCompare("angle",keyword) == 0)
3180
GetToken(q,&q,token);
3181
affine.rx=atof(token);
3182
affine.ry=atof(token);
3185
if (LocaleCompare("arc",keyword) == 0)
3187
primitive_type=ArcPrimitive;
3196
if (LocaleCompare("bezier",keyword) == 0)
3198
primitive_type=BezierPrimitive;
3207
if (LocaleCompare("clip-path",keyword) == 0)
3209
GetToken(q,&q,token);
3210
FormatString(message,"clip-path:url(#%.1024s);",token);
3211
(void) WriteBlobString(image,message);
3214
if (LocaleCompare("clip-rule",keyword) == 0)
3216
GetToken(q,&q,token);
3217
FormatString(message,"clip-rule:%.1024s;",token);
3218
(void) WriteBlobString(image,message);
3221
if (LocaleCompare("clip-units",keyword) == 0)
3223
GetToken(q,&q,token);
3224
FormatString(message,"clipPathUnits=%.1024s;",token);
3225
(void) WriteBlobString(image,message);
3228
if (LocaleCompare("circle",keyword) == 0)
3230
primitive_type=CirclePrimitive;
3233
if (LocaleCompare("color",keyword) == 0)
3235
primitive_type=ColorPrimitive;
3244
if (LocaleCompare("decorate",keyword) == 0)
3246
GetToken(q,&q,token);
3247
FormatString(message,"text-decoration:%.1024s;",token);
3248
(void) WriteBlobString(image,message);
3257
if (LocaleCompare("ellipse",keyword) == 0)
3259
primitive_type=EllipsePrimitive;
3268
if (LocaleCompare("fill",keyword) == 0)
3270
GetToken(q,&q,token);
3271
FormatString(message,"fill:%.1024s;",token);
3272
(void) WriteBlobString(image,message);
3275
if (LocaleCompare("fill-rule",keyword) == 0)
3277
GetToken(q,&q,token);
3278
FormatString(message,"fill-rule:%.1024s;",token);
3279
(void) WriteBlobString(image,message);
3282
if (LocaleCompare("fill-opacity",keyword) == 0)
3284
GetToken(q,&q,token);
3285
FormatString(message,"fill-opacity:%.1024s;",token);
3286
(void) WriteBlobString(image,message);
3289
if (LocaleCompare("font-family",keyword) == 0)
3291
GetToken(q,&q,token);
3292
FormatString(message,"font-family:%.1024s;",token);
3293
(void) WriteBlobString(image,message);
3296
if (LocaleCompare("font-stretch",keyword) == 0)
3298
GetToken(q,&q,token);
3299
FormatString(message,"font-stretch:%.1024s;",token);
3300
(void) WriteBlobString(image,message);
3303
if (LocaleCompare("font-style",keyword) == 0)
3305
GetToken(q,&q,token);
3306
FormatString(message,"font-style:%.1024s;",token);
3307
(void) WriteBlobString(image,message);
3310
if (LocaleCompare("font-size",keyword) == 0)
3312
GetToken(q,&q,token);
3313
FormatString(message,"font-size:%.1024s;",token);
3314
(void) WriteBlobString(image,message);
3317
if (LocaleCompare("font-weight",keyword) == 0)
3319
GetToken(q,&q,token);
3320
FormatString(message,"font-weight:%.1024s;",token);
3321
(void) WriteBlobString(image,message);
3330
if (LocaleCompare("gradient-units",keyword) == 0)
3332
GetToken(q,&q,token);
3335
if (LocaleCompare("text-align",keyword) == 0)
3337
GetToken(q,&q,token);
3338
FormatString(message,"text-align %.1024s ",token);
3339
(void) WriteBlobString(image,message);
3342
if (LocaleCompare("text-anchor",keyword) == 0)
3344
GetToken(q,&q,token);
3345
FormatString(message,"text-anchor %.1024s ",token);
3346
(void) WriteBlobString(image,message);
3355
if (LocaleCompare("image",keyword) == 0)
3357
GetToken(q,&q,token);
3358
primitive_type=ImagePrimitive;
3367
if (LocaleCompare("line",keyword) == 0)
3369
primitive_type=LinePrimitive;
3378
if (LocaleCompare("matte",keyword) == 0)
3380
primitive_type=MattePrimitive;
3389
if (LocaleCompare("opacity",keyword) == 0)
3391
GetToken(q,&q,token);
3392
FormatString(message,"opacity %.1024s ",token);
3393
(void) WriteBlobString(image,message);
3402
if (LocaleCompare("path",keyword) == 0)
3404
primitive_type=PathPrimitive;
3407
if (LocaleCompare("point",keyword) == 0)
3409
primitive_type=PointPrimitive;
3412
if (LocaleCompare("polyline",keyword) == 0)
3414
primitive_type=PolylinePrimitive;
3417
if (LocaleCompare("polygon",keyword) == 0)
3419
primitive_type=PolygonPrimitive;
3422
if (LocaleCompare("pop",keyword) == 0)
3424
GetToken(q,&q,token);
3425
if (LocaleCompare("clip-path",token) == 0)
3427
(void) WriteBlobString(image,"</clipPath>\n");
3430
if (LocaleCompare("defs",token) == 0)
3432
(void) WriteBlobString(image,"</defs>\n");
3435
if (LocaleCompare("gradient",token) == 0)
3437
FormatString(message,"</%sGradient>\n",type);
3438
(void) WriteBlobString(image,message);
3441
if (LocaleCompare("graphic-context",token) == 0)
3445
ThrowWriterException(DrawError,
3446
UnbalancedGraphicContextPushPop,image);
3447
(void) WriteBlobString(image,"</g>\n");
3449
if (LocaleCompare("pattern",token) == 0)
3451
(void) WriteBlobString(image,"</pattern>\n");
3454
if (LocaleCompare("defs",token) == 0)
3455
(void) WriteBlobString(image,"</g>\n");
3458
if (LocaleCompare("push",keyword) == 0)
3460
GetToken(q,&q,token);
3461
if (LocaleCompare("clip-path",token) == 0)
3463
GetToken(q,&q,token);
3464
FormatString(message,"<clipPath id=\"%s\">\n",token);
3465
(void) WriteBlobString(image,message);
3468
if (LocaleCompare("defs",token) == 0)
3470
(void) WriteBlobString(image,"<defs>\n");
3473
if (LocaleCompare("gradient",token) == 0)
3475
GetToken(q,&q,token);
3476
(void) strncpy(name,token,MaxTextExtent-1);
3477
GetToken(q,&q,token);
3478
(void) strncpy(type,token,MaxTextExtent-1);
3479
GetToken(q,&q,token);
3480
svg_info.segment.x1=atof(token);
3481
svg_info.element.cx=atof(token);
3482
GetToken(q,&q,token);
3484
GetToken(q,&q,token);
3485
svg_info.segment.y1=atof(token);
3486
svg_info.element.cy=atof(token);
3487
GetToken(q,&q,token);
3489
GetToken(q,&q,token);
3490
svg_info.segment.x2=atof(token);
3491
svg_info.element.major=atof(token);
3492
GetToken(q,&q,token);
3494
GetToken(q,&q,token);
3495
svg_info.segment.y2=atof(token);
3496
svg_info.element.minor=atof(token);
3497
FormatString(message,"<%sGradient id=\"%s\" x1=\"%g\" "
3498
"y1=\"%g\" x2=\"%g\" y2=\"%g\">\n",type,name,
3499
svg_info.segment.x1,svg_info.segment.y1,svg_info.segment.x2,
3500
svg_info.segment.y2);
3501
if (LocaleCompare(type,"radial") == 0)
3503
GetToken(q,&q,token);
3505
GetToken(q,&q,token);
3506
svg_info.element.angle=atof(token);
3507
FormatString(message,"<%sGradient id=\"%s\" cx=\"%g\" "
3508
"cy=\"%g\" r=\"%g\" fx=\"%g\" fy=\"%g\">\n",type,name,
3509
svg_info.element.cx,svg_info.element.cy,
3510
svg_info.element.angle,svg_info.element.major,
3511
svg_info.element.minor);
3513
(void) WriteBlobString(image,message);
3516
if (LocaleCompare("graphic-context",token) == 0)
3521
AffineToTransform(image,&affine);
3524
(void) WriteBlobString(image,"<g style=\"");
3527
if (LocaleCompare("pattern",token) == 0)
3529
GetToken(q,&q,token);
3530
(void) strncpy(name,token,MaxTextExtent-1);
3531
GetToken(q,&q,token);
3532
svg_info.bounds.x=atof(token);
3533
GetToken(q,&q,token);
3535
GetToken(q,&q,token);
3536
svg_info.bounds.y=atof(token);
3537
GetToken(q,&q,token);
3539
GetToken(q,&q,token);
3540
svg_info.bounds.width=atof(token);
3541
GetToken(q,&q,token);
3543
GetToken(q,&q,token);
3544
svg_info.bounds.height=atof(token);
3545
FormatString(message,"<pattern id=\"%s\" x=\"%g\" y=\"%g\" "
3546
"width=\"%g\" height=\"%g\">\n",name,svg_info.bounds.x,
3547
svg_info.bounds.y,svg_info.bounds.width,
3548
svg_info.bounds.height);
3549
(void) WriteBlobString(image,message);
3560
if (LocaleCompare("rectangle",keyword) == 0)
3562
primitive_type=RectanglePrimitive;
3565
if (LocaleCompare("roundRectangle",keyword) == 0)
3567
primitive_type=RoundRectanglePrimitive;
3570
if (LocaleCompare("rotate",keyword) == 0)
3572
GetToken(q,&q,token);
3573
FormatString(message,"rotate(%.1024s) ",token);
3574
(void) WriteBlobString(image,message);
3583
if (LocaleCompare("scale",keyword) == 0)
3585
GetToken(q,&q,token);
3586
affine.sx=atof(token);
3587
GetToken(q,&q,token);
3589
GetToken(q,&q,token);
3590
affine.sy=atof(token);
3593
if (LocaleCompare("skewX",keyword) == 0)
3595
GetToken(q,&q,token);
3596
FormatString(message,"skewX(%.1024s) ",token);
3597
(void) WriteBlobString(image,message);
3600
if (LocaleCompare("skewY",keyword) == 0)
3602
GetToken(q,&q,token);
3603
FormatString(message,"skewY(%.1024s) ",token);
3604
(void) WriteBlobString(image,message);
3607
if (LocaleCompare("stop-color",keyword) == 0)
3610
color[MaxTextExtent];
3612
GetToken(q,&q,token);
3613
(void) strncpy(color,token,MaxTextExtent-1);
3614
GetToken(q,&q,token);
3615
FormatString(message,
3616
" <stop offset=\"%s\" stop-color=\"%s\" />\n",token,color);
3617
(void) WriteBlobString(image,message);
3620
if (LocaleCompare("stroke",keyword) == 0)
3622
GetToken(q,&q,token);
3623
FormatString(message,"stroke:%.1024s;",token);
3624
(void) WriteBlobString(image,message);
3627
if (LocaleCompare("stroke-antialias",keyword) == 0)
3629
GetToken(q,&q,token);
3630
FormatString(message,"stroke-antialias:%.1024s;",token);
3631
(void) WriteBlobString(image,message);
3634
if (LocaleCompare("stroke-dasharray",keyword) == 0)
3642
GetToken(p,&p,token);
3643
for (k=0; IsPoint(token); k++)
3644
GetToken(p,&p,token);
3645
(void) WriteBlobString(image,"stroke-dasharray:");
3646
for (j=0; j < k; j++)
3648
GetToken(q,&q,token);
3649
FormatString(message,"%.1024s ",token);
3650
(void) WriteBlobString(image,message);
3652
(void) WriteBlobString(image,";");
3655
GetToken(q,&q,token);
3656
FormatString(message,"stroke-dasharray:%.1024s;",token);
3657
(void) WriteBlobString(image,message);
3660
if (LocaleCompare("stroke-dashoffset",keyword) == 0)
3662
GetToken(q,&q,token);
3663
FormatString(message,"stroke-dashoffset:%.1024s;",token);
3664
(void) WriteBlobString(image,message);
3667
if (LocaleCompare("stroke-linecap",keyword) == 0)
3669
GetToken(q,&q,token);
3670
FormatString(message,"stroke-linecap:%.1024s;",token);
3671
(void) WriteBlobString(image,message);
3674
if (LocaleCompare("stroke-linejoin",keyword) == 0)
3676
GetToken(q,&q,token);
3677
FormatString(message,"stroke-linejoin:%.1024s;",token);
3678
(void) WriteBlobString(image,message);
3681
if (LocaleCompare("stroke-miterlimit",keyword) == 0)
3683
GetToken(q,&q,token);
3684
FormatString(message,"stroke-miterlimit:%.1024s;",token);
3685
(void) WriteBlobString(image,message);
3688
if (LocaleCompare("stroke-opacity",keyword) == 0)
3690
GetToken(q,&q,token);
3691
FormatString(message,"stroke-opacity:%.1024s;",token);
3692
(void) WriteBlobString(image,message);
3695
if (LocaleCompare("stroke-width",keyword) == 0)
3697
GetToken(q,&q,token);
3698
FormatString(message,"stroke-width:%.1024s;",token);
3699
(void) WriteBlobString(image,message);
3708
if (LocaleCompare("text",keyword) == 0)
3710
primitive_type=TextPrimitive;
3713
if (LocaleCompare("text-antialias",keyword) == 0)
3715
GetToken(q,&q,token);
3716
FormatString(message,"text-antialias:%.1024s;",token);
3717
(void) WriteBlobString(image,message);
3720
if (LocaleCompare("tspan",keyword) == 0)
3722
primitive_type=TextPrimitive;
3725
if (LocaleCompare("translate",keyword) == 0)
3727
GetToken(q,&q,token);
3728
affine.tx=atof(token);
3729
GetToken(q,&q,token);
3731
GetToken(q,&q,token);
3732
affine.ty=atof(token);
3741
if (LocaleCompare("viewbox",keyword) == 0)
3743
GetToken(q,&q,token);
3745
GetToken(q,&q,token);
3746
GetToken(q,&q,token);
3748
GetToken(q,&q,token);
3749
GetToken(q,&q,token);
3751
GetToken(q,&q,token);
3752
GetToken(q,&q,token);
3764
if (status == False)
3766
if (primitive_type == UndefinedPrimitive)
3769
Parse the primitive attributes.
3773
for (x=0; *q != '\0'; x++)
3780
GetToken(q,&q,token);
3781
point.x=atof(token);
3782
GetToken(q,&q,token);
3784
GetToken(q,&q,token);
3785
point.y=atof(token);
3786
GetToken(q,(char **) NULL,token);
3788
GetToken(q,&q,token);
3789
primitive_info[i].primitive=primitive_type;
3790
primitive_info[i].point=point;
3791
primitive_info[i].coordinates=0;
3792
primitive_info[i].method=FloodfillMethod;
3794
if (i < (long) (number_points-6*BezierQuantum-360))
3796
number_points+=6*BezierQuantum+360;
3797
MagickReallocMemory(primitive_info,
3798
number_points*sizeof(PrimitiveInfo));
3799
if (primitive_info == (PrimitiveInfo *) NULL)
3801
ThrowException3(&image->exception,ResourceLimitError,
3802
MemoryAllocationFailed,UnableToDrawOnImage);
3806
primitive_info[j].primitive=primitive_type;
3807
primitive_info[j].coordinates=x;
3808
primitive_info[j].method=FloodfillMethod;
3809
primitive_info[j].text=(char *) NULL;
3812
AffineToTransform(image,&affine);
3816
switch (primitive_type)
3818
case PointPrimitive:
3821
if (primitive_info[j].coordinates != 1)
3830
if (primitive_info[j].coordinates != 2)
3835
(void) FormatString(message,
3836
" <line x1=\"%g\" y1=\"%g\" x2=\"%g\" y2=\"%g\"/>\n",
3837
primitive_info[j].point.x,primitive_info[j].point.y,
3838
primitive_info[j+1].point.x,primitive_info[j+1].point.y);
3839
(void) WriteBlobString(image,message);
3842
case RectanglePrimitive:
3844
if (primitive_info[j].coordinates != 2)
3849
(void) FormatString(message,
3850
" <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"/>\n",
3851
primitive_info[j].point.x,primitive_info[j].point.y,
3852
primitive_info[j+1].point.x-primitive_info[j].point.x,
3853
primitive_info[j+1].point.y-primitive_info[j].point.y);
3854
(void) WriteBlobString(image,message);
3857
case RoundRectanglePrimitive:
3859
if (primitive_info[j].coordinates != 3)
3864
(void) FormatString(message," <rect x=\"%g\" y=\"%g\" "
3865
"width=\"%g\" height=\"%g\" rx=\"%g\" ry=\"%g\"/>\n",
3866
primitive_info[j].point.x,primitive_info[j].point.y,
3867
primitive_info[j+1].point.x-primitive_info[j].point.x,
3868
primitive_info[j+1].point.y-primitive_info[j].point.y,
3869
primitive_info[j+2].point.x,primitive_info[j+2].point.y);
3870
(void) WriteBlobString(image,message);
3875
if (primitive_info[j].coordinates != 3)
3882
case EllipsePrimitive:
3884
if (primitive_info[j].coordinates != 3)
3889
(void) FormatString(message,
3890
" <ellipse cx=\"%g\" cy=\"%g\" rx=\"%g\" ry=\"%g\"/>\n",
3891
primitive_info[j].point.x,primitive_info[j].point.y,
3892
primitive_info[j+1].point.x,primitive_info[j+1].point.y);
3893
(void) WriteBlobString(image,message);
3896
case CirclePrimitive:
3902
if (primitive_info[j].coordinates != 2)
3907
alpha=primitive_info[j+1].point.x-primitive_info[j].point.x;
3908
beta=primitive_info[j+1].point.y-primitive_info[j].point.y;
3909
(void) FormatString(message," <circle cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
3910
primitive_info[j].point.x,primitive_info[j].point.y,
3911
sqrt(alpha*alpha+beta*beta));
3912
(void) WriteBlobString(image,message);
3915
case PolylinePrimitive:
3917
if (primitive_info[j].coordinates < 2)
3922
(void) strcpy(message," <polyline points=\"");
3923
(void) WriteBlobString(image,message);
3924
length=strlen(message);
3927
FormatString(message,"%g,%g ",primitive_info[j].point.x,
3928
primitive_info[j].point.y);
3929
length+=strlen(message);
3932
(void) WriteBlobString(image,"\n ");
3933
length=strlen(message)+5;
3935
(void) WriteBlobString(image,message);
3937
(void) WriteBlobString(image,"\"/>\n");
3940
case PolygonPrimitive:
3942
if (primitive_info[j].coordinates < 3)
3947
primitive_info[i]=primitive_info[j];
3948
primitive_info[i].coordinates=0;
3949
primitive_info[j].coordinates++;
3951
(void) strcpy(message," <polygon points=\"");
3952
(void) WriteBlobString(image,message);
3953
length=strlen(message);
3956
FormatString(message,"%g,%g ",primitive_info[j].point.x,
3957
primitive_info[j].point.y);
3958
length+=strlen(message);
3961
(void) WriteBlobString(image,"\n ");
3962
length=strlen(message)+5;
3964
(void) WriteBlobString(image,message);
3966
(void) WriteBlobString(image,"\"/>\n");
3969
case BezierPrimitive:
3971
if (primitive_info[j].coordinates < 3)
3983
GetToken(q,&q,token);
3984
number_attributes=1;
3985
for (p=token; *p != '\0'; p++)
3986
if (isalpha((int) *p))
3987
number_attributes++;
3988
if (i > (long) (number_points-6*BezierQuantum*number_attributes-1))
3990
number_points+=6*BezierQuantum*number_attributes;
3991
MagickReallocMemory(primitive_info,
3992
number_points*sizeof(PrimitiveInfo));
3993
if (primitive_info == (PrimitiveInfo *) NULL)
3995
ThrowException3(&image->exception,ResourceLimitError,
3996
MemoryAllocationFailed,UnableToDrawOnImage);
4000
(void) WriteBlobString(image," <path d=\"");
4001
(void) WriteBlobString(image,token);
4002
(void) WriteBlobString(image,"\"/>\n");
4005
case ColorPrimitive:
4006
case MattePrimitive:
4008
if (primitive_info[j].coordinates != 1)
4013
GetToken(q,&q,token);
4014
if (LocaleCompare("point",token) == 0)
4015
primitive_info[j].method=PointMethod;
4016
if (LocaleCompare("replace",token) == 0)
4017
primitive_info[j].method=ReplaceMethod;
4018
if (LocaleCompare("floodfill",token) == 0)
4019
primitive_info[j].method=FloodfillMethod;
4020
if (LocaleCompare("filltoborder",token) == 0)
4021
primitive_info[j].method=FillToBorderMethod;
4022
if (LocaleCompare("reset",token) == 0)
4023
primitive_info[j].method=ResetMethod;
4031
if (primitive_info[j].coordinates != 1)
4036
GetToken(q,&q,token);
4037
(void) FormatString(message," <text x=\"%g\" y=\"%g\">",
4038
primitive_info[j].point.x,primitive_info[j].point.y);
4039
(void) WriteBlobString(image,message);
4040
for (p=token; *p != '\0'; p++)
4043
case '<': (void) WriteBlobString(image,"<"); break;
4044
case '>': (void) WriteBlobString(image,">"); break;
4045
case '&': (void) WriteBlobString(image,"&"); break;
4046
default: (void) WriteBlobByte(image,*p); break;
4048
(void) WriteBlobString(image,"</text>\n");
4051
case ImagePrimitive:
4053
if (primitive_info[j].coordinates != 2)
4058
GetToken(q,&q,token);
4059
(void) FormatString(message," <image x=\"%g\" y=\"%g\" "
4060
"width=\"%g\" height=\"%g\" xlink:href=\"%.1024s\"/>\n",
4061
primitive_info[j].point.x,primitive_info[j].point.y,
4062
primitive_info[j+1].point.x,primitive_info[j+1].point.y,token);
4063
(void) WriteBlobString(image,message);
4067
if (primitive_info == (PrimitiveInfo *) NULL)
4069
primitive_info[i].primitive=UndefinedPrimitive;
4070
if (status == False)
4073
(void) WriteBlobString(image,"</svg>\n");
4077
MagickFreeMemory(token);
4078
if (primitive_info != (PrimitiveInfo *) NULL)
4079
MagickFreeMemory(primitive_info);