2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Scalable Vector Graphics Format %
21 % Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
22 % dedicated to making software imaging solutions freely available. %
24 % You may not use this file except in compliance with the License. You may %
25 % obtain a copy of the License at %
27 % http://www.imagemagick.org/script/license.php %
29 % Unless required by applicable law or agreed to in writing, software %
30 % distributed under the License is distributed on an "AS IS" BASIS, %
31 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
32 % See the License for the specific language governing permissions and %
33 % limitations under the License. %
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/annotate.h"
45 #include "MagickCore/artifact.h"
46 #include "MagickCore/attribute.h"
47 #include "MagickCore/blob.h"
48 #include "MagickCore/blob-private.h"
49 #include "MagickCore/cache.h"
50 #include "MagickCore/constitute.h"
51 #include "MagickCore/composite-private.h"
52 #include "MagickCore/delegate.h"
53 #include "MagickCore/delegate-private.h"
54 #include "MagickCore/draw.h"
55 #include "MagickCore/exception.h"
56 #include "MagickCore/exception-private.h"
57 #include "MagickCore/gem.h"
58 #include "MagickCore/image.h"
59 #include "MagickCore/image-private.h"
60 #include "MagickCore/list.h"
61 #include "MagickCore/log.h"
62 #include "MagickCore/magick.h"
63 #include "MagickCore/memory_.h"
64 #include "MagickCore/module.h"
65 #include "MagickCore/monitor.h"
66 #include "MagickCore/monitor-private.h"
67 #include "MagickCore/quantum-private.h"
68 #include "MagickCore/pixel-accessor.h"
69 #include "MagickCore/property.h"
70 #include "MagickCore/resource_.h"
71 #include "MagickCore/static.h"
72 #include "MagickCore/string_.h"
73 #include "MagickCore/string-private.h"
74 #include "MagickCore/token.h"
75 #include "MagickCore/utility.h"
76 #if defined(MAGICKCORE_XML_DELEGATE)
77 # if defined(MAGICKCORE_WINDOWS_SUPPORT)
78 # if defined(__MINGW32__) || defined(__MINGW64__)
81 # include <win32config.h>
84 # include <libxml/parser.h>
85 # include <libxml/xmlmemory.h>
86 # include <libxml/parserInternals.h>
87 # include <libxml/xmlerror.h>
90 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
91 #include "autotrace/autotrace.h"
94 #if defined(MAGICKCORE_RSVG_DELEGATE)
95 #include "librsvg/rsvg.h"
96 #if !defined(LIBRSVG_CHECK_VERSION)
97 #include "librsvg/rsvg-cairo.h"
98 #include "librsvg/librsvg-features.h"
99 #elif !LIBRSVG_CHECK_VERSION(2,36,2)
100 #include "librsvg/rsvg-cairo.h"
101 #include "librsvg/librsvg-features.h"
106 Typedef declarations.
108 typedef struct _BoundingBox
117 typedef struct _ElementInfo
127 typedef struct _SVGInfo
181 #if defined(MAGICKCORE_XML_DELEGATE)
191 Forward declarations.
193 static MagickBooleanType
194 WriteSVGImage(const ImageInfo *,Image *,ExceptionInfo *);
197 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
205 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
207 % IsSVG()() returns MagickTrue if the image format type, identified by the
208 % magick string, is SVG.
210 % The format of the IsSVG method is:
212 % MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
214 % A description of each parameter follows:
216 % o magick: compare image format pattern against these bytes.
218 % o length: Specifies the length of the magick string.
221 static MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
225 if (LocaleNCompare((const char *) magick,"?xml",4) == 0)
230 #if defined(MAGICKCORE_XML_DELEGATE)
232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
236 % R e a d S V G I m a g e %
240 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
242 % ReadSVGImage() reads a Scalable Vector Gaphics file and returns it. It
243 % allocates the memory necessary for the new Image structure and returns a
244 % pointer to the new image.
246 % The format of the ReadSVGImage method is:
248 % Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
250 % A description of each parameter follows:
252 % o image_info: the image info.
254 % o exception: return any errors or warnings in this structure.
258 static SVGInfo *AcquireSVGInfo(void)
263 svg_info=(SVGInfo *) AcquireMagickMemory(sizeof(*svg_info));
264 if (svg_info == (SVGInfo *) NULL)
265 return((SVGInfo *) NULL);
266 (void) ResetMagickMemory(svg_info,0,sizeof(*svg_info));
267 svg_info->text=AcquireString("");
268 svg_info->scale=(double *) AcquireMagickMemory(sizeof(*svg_info->scale));
269 if (svg_info->scale == (double *) NULL)
270 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
271 GetAffineMatrix(&svg_info->affine);
272 svg_info->scale[0]=ExpandAffine(&svg_info->affine);
276 static SVGInfo *DestroySVGInfo(SVGInfo *svg_info)
278 if (svg_info->text != (char *) NULL)
279 svg_info->text=DestroyString(svg_info->text);
280 if (svg_info->scale != (double *) NULL)
281 svg_info->scale=(double *) (svg_info->scale);
282 if (svg_info->title != (char *) NULL)
283 svg_info->title=DestroyString(svg_info->title);
284 if (svg_info->comment != (char *) NULL)
285 svg_info->comment=DestroyString(svg_info->comment);
286 return((SVGInfo *) RelinquishMagickMemory(svg_info));
289 static double GetUserSpaceCoordinateValue(const SVGInfo *svg_info,int type,
293 token[MaxTextExtent];
301 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",string);
302 assert(string != (const char *) NULL);
303 p=(const char *) string;
304 GetMagickToken(p,&p,token);
305 value=StringToDouble(token,(char **) NULL);
306 if (strchr(token,'%') != (char *) NULL)
314 if (svg_info->view_box.width == 0.0)
316 return(svg_info->view_box.width*value/100.0);
320 if (svg_info->view_box.height == 0.0)
322 return(svg_info->view_box.height*value/100.0);
324 alpha=value-svg_info->view_box.width;
325 beta=value-svg_info->view_box.height;
326 return(hypot(alpha,beta)/sqrt(2.0)/100.0);
328 GetMagickToken(p,&p,token);
329 if (LocaleNCompare(token,"cm",2) == 0)
330 return(DefaultResolution*svg_info->scale[0]/2.54*value);
331 if (LocaleNCompare(token,"em",2) == 0)
332 return(svg_info->pointsize*value);
333 if (LocaleNCompare(token,"ex",2) == 0)
334 return(svg_info->pointsize*value/2.0);
335 if (LocaleNCompare(token,"in",2) == 0)
336 return(DefaultResolution*svg_info->scale[0]*value);
337 if (LocaleNCompare(token,"mm",2) == 0)
338 return(DefaultResolution*svg_info->scale[0]/25.4*value);
339 if (LocaleNCompare(token,"pc",2) == 0)
340 return(DefaultResolution*svg_info->scale[0]/6.0*value);
341 if (LocaleNCompare(token,"pt",2) == 0)
342 return(1.25*svg_info->scale[0]*value);
343 if (LocaleNCompare(token,"px",2) == 0)
348 static void StripStyleTokens(char *message)
357 assert(message != (char *) NULL);
358 if (*message == '\0')
360 length=strlen(message);
362 while (isspace((int) ((unsigned char) *p)) != 0)
365 while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
367 (void) CopyMagickMemory(message,p,(size_t) (q-p+1));
369 StripString(message);
372 static char **GetStyleTokens(void *context,const char *style,int *number_tokens)
384 svg_info=(SVGInfo *) context;
387 if (style == (const char *) NULL)
388 return((char **) NULL);
389 text=AcquireString(style);
390 (void) SubstituteString(&text,":","\n");
391 (void) SubstituteString(&text,";","\n");
392 tokens=StringToList(text);
393 text=DestroyString(text);
394 for (i=0; tokens[i] != (char *) NULL; i++)
395 StripStyleTokens(tokens[i]);
400 static char **GetTransformTokens(void *context,const char *text,
416 svg_info=(SVGInfo *) context;
418 if (text == (const char *) NULL)
419 return((char **) NULL);
421 Determine the number of arguments.
423 for (p=text; *p != '\0'; p++)
428 tokens=(char **) AcquireQuantumMemory(*number_tokens+2UL,sizeof(*tokens));
429 if (tokens == (char **) NULL)
431 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
432 ResourceLimitError,"MemoryAllocationFailed","`%s'",text);
433 return((char **) NULL);
436 Convert string to an ASCII list.
440 for (q=p; *q != '\0'; q++)
442 if ((*q != '(') && (*q != ')') && (*q != '\0'))
444 tokens[i]=AcquireString(p);
445 (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
446 StripString(tokens[i++]);
449 tokens[i]=AcquireString(p);
450 (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
451 StripString(tokens[i++]);
452 tokens[i]=(char *) NULL;
456 #if defined(__cplusplus) || defined(c_plusplus)
460 static int SVGIsStandalone(void *context)
466 Is this document tagged standalone?
468 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGIsStandalone()");
469 svg_info=(SVGInfo *) context;
470 return(svg_info->document->standalone == 1);
473 static int SVGHasInternalSubset(void *context)
479 Does this document has an internal subset?
481 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
482 " SAX.SVGHasInternalSubset()");
483 svg_info=(SVGInfo *) context;
484 return(svg_info->document->intSubset != NULL);
487 static int SVGHasExternalSubset(void *context)
493 Does this document has an external subset?
495 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
496 " SAX.SVGHasExternalSubset()");
497 svg_info=(SVGInfo *) context;
498 return(svg_info->document->extSubset != NULL);
501 static void SVGInternalSubset(void *context,const xmlChar *name,
502 const xmlChar *external_id,const xmlChar *system_id)
508 Does this document has an internal subset?
510 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
511 " SAX.internalSubset(%s, %s, %s)",(const char *) name,
512 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
513 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
514 svg_info=(SVGInfo *) context;
515 (void) xmlCreateIntSubset(svg_info->document,name,external_id,system_id);
518 static xmlParserInputPtr SVGResolveEntity(void *context,
519 const xmlChar *public_id,const xmlChar *system_id)
528 Special entity resolver, better left to the parser, it has more
529 context than the application layer. The default behaviour is to
530 not resolve the entities, in that case the ENTITY_REF nodes are
531 built in the structure (and the parameter values).
533 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
534 " SAX.resolveEntity(%s, %s)",
535 (public_id != (const xmlChar *) NULL ? (const char *) public_id : "none"),
536 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
537 svg_info=(SVGInfo *) context;
538 stream=xmlLoadExternalEntity((const char *) system_id,(const char *)
539 public_id,svg_info->parser);
543 static xmlEntityPtr SVGGetEntity(void *context,const xmlChar *name)
549 Get an entity by name.
551 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGGetEntity(%s)",
553 svg_info=(SVGInfo *) context;
554 return(xmlGetDocEntity(svg_info->document,name));
557 static xmlEntityPtr SVGGetParameterEntity(void *context,const xmlChar *name)
563 Get a parameter entity by name.
565 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
566 " SAX.getParameterEntity(%s)",name);
567 svg_info=(SVGInfo *) context;
568 return(xmlGetParameterEntity(svg_info->document,name));
571 static void SVGEntityDeclaration(void *context,const xmlChar *name,int type,
572 const xmlChar *public_id,const xmlChar *system_id,xmlChar *content)
578 An entity definition has been parsed.
580 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
581 " SAX.entityDecl(%s, %d, %s, %s, %s)",name,type,
582 public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
583 system_id != (xmlChar *) NULL ? (const char *) system_id : "none",content);
584 svg_info=(SVGInfo *) context;
585 if (svg_info->parser->inSubset == 1)
586 (void) xmlAddDocEntity(svg_info->document,name,type,public_id,system_id,
589 if (svg_info->parser->inSubset == 2)
590 (void) xmlAddDtdEntity(svg_info->document,name,type,public_id,system_id,
594 static void SVGAttributeDeclaration(void *context,const xmlChar *element,
595 const xmlChar *name,int type,int value,const xmlChar *default_value,
596 xmlEnumerationPtr tree)
609 An attribute definition has been parsed.
611 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
612 " SAX.attributeDecl(%s, %s, %d, %d, %s, ...)",element,name,type,value,
614 svg_info=(SVGInfo *) context;
615 fullname=(xmlChar *) NULL;
616 prefix=(xmlChar *) NULL;
617 parser=svg_info->parser;
618 fullname=(xmlChar *) xmlSplitQName(parser,name,&prefix);
619 if (parser->inSubset == 1)
620 (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->intSubset,
621 element,fullname,prefix,(xmlAttributeType) type,
622 (xmlAttributeDefault) value,default_value,tree);
624 if (parser->inSubset == 2)
625 (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->extSubset,
626 element,fullname,prefix,(xmlAttributeType) type,
627 (xmlAttributeDefault) value,default_value,tree);
628 if (prefix != (xmlChar *) NULL)
630 if (fullname != (xmlChar *) NULL)
634 static void SVGElementDeclaration(void *context,const xmlChar *name,int type,
635 xmlElementContentPtr content)
644 An element definition has been parsed.
646 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
647 " SAX.elementDecl(%s, %d, ...)",name,type);
648 svg_info=(SVGInfo *) context;
649 parser=svg_info->parser;
650 if (parser->inSubset == 1)
651 (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->intSubset,
652 name,(xmlElementTypeVal) type,content);
654 if (parser->inSubset == 2)
655 (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->extSubset,
656 name,(xmlElementTypeVal) type,content);
659 static void SVGNotationDeclaration(void *context,const xmlChar *name,
660 const xmlChar *public_id,const xmlChar *system_id)
669 What to do when a notation declaration has been parsed.
671 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
672 " SAX.notationDecl(%s, %s, %s)",name,
673 public_id != (const xmlChar *) NULL ? (const char *) public_id : "none",
674 system_id != (const xmlChar *) NULL ? (const char *) system_id : "none");
675 svg_info=(SVGInfo *) context;
676 parser=svg_info->parser;
677 if (parser->inSubset == 1)
678 (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
679 name,public_id,system_id);
681 if (parser->inSubset == 2)
682 (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
683 name,public_id,system_id);
686 static void SVGUnparsedEntityDeclaration(void *context,const xmlChar *name,
687 const xmlChar *public_id,const xmlChar *system_id,const xmlChar *notation)
693 What to do when an unparsed entity declaration is parsed.
695 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
696 " SAX.unparsedEntityDecl(%s, %s, %s, %s)",name,
697 public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
698 system_id != (xmlChar *) NULL ? (const char *) system_id : "none",notation);
699 svg_info=(SVGInfo *) context;
700 (void) xmlAddDocEntity(svg_info->document,name,
701 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,public_id,system_id,notation);
705 static void SVGSetDocumentLocator(void *context,xmlSAXLocatorPtr location)
711 Receive the document locator at startup, actually xmlDefaultSAXLocator.
714 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
715 " SAX.setDocumentLocator()");
716 svg_info=(SVGInfo *) context;
720 static void SVGStartDocument(void *context)
729 Called when the document start being processed.
731 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startDocument()");
732 svg_info=(SVGInfo *) context;
733 GetExceptionInfo(svg_info->exception);
734 parser=svg_info->parser;
735 svg_info->document=xmlNewDoc(parser->version);
736 if (svg_info->document == (xmlDocPtr) NULL)
738 if (parser->encoding == NULL)
739 svg_info->document->encoding=(const xmlChar *) NULL;
741 svg_info->document->encoding=xmlStrdup(parser->encoding);
742 svg_info->document->standalone=parser->standalone;
745 static void SVGEndDocument(void *context)
751 Called when the document end has been detected.
753 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.endDocument()");
754 svg_info=(SVGInfo *) context;
755 if (svg_info->offset != (char *) NULL)
756 svg_info->offset=DestroyString(svg_info->offset);
757 if (svg_info->stop_color != (char *) NULL)
758 svg_info->stop_color=DestroyString(svg_info->stop_color);
759 if (svg_info->scale != (double *) NULL)
760 svg_info->scale=(double *) RelinquishMagickMemory(svg_info->scale);
761 if (svg_info->text != (char *) NULL)
762 svg_info->text=DestroyString(svg_info->text);
763 if (svg_info->vertices != (char *) NULL)
764 svg_info->vertices=DestroyString(svg_info->vertices);
765 if (svg_info->url != (char *) NULL)
766 svg_info->url=DestroyString(svg_info->url);
767 #if defined(MAGICKCORE_XML_DELEGATE)
768 if (svg_info->document != (xmlDocPtr) NULL)
770 xmlFreeDoc(svg_info->document);
771 svg_info->document=(xmlDocPtr) NULL;
776 static void SVGStartElement(void *context,const xmlChar *name,
777 const xmlChar **attributes)
782 token[MaxTextExtent],
802 Called when an opening tag has been processed.
804 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startElement(%s",
806 svg_info=(SVGInfo *) context;
808 svg_info->scale=(double *) ResizeQuantumMemory(svg_info->scale,
809 svg_info->n+1UL,sizeof(*svg_info->scale));
810 if (svg_info->scale == (double *) NULL)
812 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
813 ResourceLimitError,"MemoryAllocationFailed","`%s'",name);
816 svg_info->scale[svg_info->n]=svg_info->scale[svg_info->n-1];
817 color=AcquireString("none");
818 units=AcquireString("userSpaceOnUse");
819 value=(const char *) NULL;
820 if (attributes != (const xmlChar **) NULL)
821 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
823 keyword=(const char *) attributes[i];
824 value=(const char *) attributes[i+1];
830 if (LocaleCompare(keyword,"cx") == 0)
832 svg_info->element.cx=
833 GetUserSpaceCoordinateValue(svg_info,1,value);
836 if (LocaleCompare(keyword,"cy") == 0)
838 svg_info->element.cy=
839 GetUserSpaceCoordinateValue(svg_info,-1,value);
847 if (LocaleCompare(keyword,"fx") == 0)
849 svg_info->element.major=
850 GetUserSpaceCoordinateValue(svg_info,1,value);
853 if (LocaleCompare(keyword,"fy") == 0)
855 svg_info->element.minor=
856 GetUserSpaceCoordinateValue(svg_info,-1,value);
864 if (LocaleCompare(keyword,"height") == 0)
866 svg_info->bounds.height=
867 GetUserSpaceCoordinateValue(svg_info,-1,value);
875 if (LocaleCompare(keyword,"id") == 0)
877 (void) CopyMagickString(id,value,MaxTextExtent);
885 if (LocaleCompare(keyword,"r") == 0)
887 svg_info->element.angle=
888 GetUserSpaceCoordinateValue(svg_info,0,value);
896 if (LocaleCompare(keyword,"width") == 0)
898 svg_info->bounds.width=
899 GetUserSpaceCoordinateValue(svg_info,1,value);
907 if (LocaleCompare(keyword,"x") == 0)
909 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value)-
913 if (LocaleCompare(keyword,"x1") == 0)
915 svg_info->segment.x1=GetUserSpaceCoordinateValue(svg_info,1,
919 if (LocaleCompare(keyword,"x2") == 0)
921 svg_info->segment.x2=GetUserSpaceCoordinateValue(svg_info,1,
930 if (LocaleCompare(keyword,"y") == 0)
932 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value)-
936 if (LocaleCompare(keyword,"y1") == 0)
938 svg_info->segment.y1=
939 GetUserSpaceCoordinateValue(svg_info,-1,value);
942 if (LocaleCompare(keyword,"y2") == 0)
944 svg_info->segment.y2=
945 GetUserSpaceCoordinateValue(svg_info,-1,value);
954 if (strchr((char *) name,':') != (char *) NULL)
959 for ( ; *name != ':'; name++) ;
967 if (LocaleCompare((const char *) name,"circle") == 0)
969 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
972 if (LocaleCompare((const char *) name,"clipPath") == 0)
974 (void) FormatLocaleFile(svg_info->file,"push clip-path '%s'\n",id);
982 if (LocaleCompare((const char *) name,"defs") == 0)
984 (void) FormatLocaleFile(svg_info->file,"push defs\n");
992 if (LocaleCompare((const char *) name,"ellipse") == 0)
994 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1002 if (LocaleCompare((const char *) name,"g") == 0)
1004 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1012 if (LocaleCompare((const char *) name,"image") == 0)
1014 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1022 if (LocaleCompare((const char *) name,"line") == 0)
1024 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1027 if (LocaleCompare((const char *) name,"linearGradient") == 0)
1029 (void) FormatLocaleFile(svg_info->file,
1030 "push gradient '%s' linear %g,%g %g,%g\n",id,
1031 svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
1032 svg_info->segment.y2);
1040 if (LocaleCompare((const char *) name,"path") == 0)
1042 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1045 if (LocaleCompare((const char *) name,"pattern") == 0)
1047 (void) FormatLocaleFile(svg_info->file,
1048 "push pattern '%s' %g,%g %g,%g\n",id,
1049 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.width,
1050 svg_info->bounds.height);
1053 if (LocaleCompare((const char *) name,"polygon") == 0)
1055 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1058 if (LocaleCompare((const char *) name,"polyline") == 0)
1060 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1068 if (LocaleCompare((const char *) name,"radialGradient") == 0)
1070 (void) FormatLocaleFile(svg_info->file,
1071 "push gradient '%s' radial %g,%g %g,%g %g\n",
1072 id,svg_info->element.cx,svg_info->element.cy,
1073 svg_info->element.major,svg_info->element.minor,
1074 svg_info->element.angle);
1077 if (LocaleCompare((const char *) name,"rect") == 0)
1079 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1087 if (LocaleCompare((const char *) name,"svg") == 0)
1089 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1097 if (LocaleCompare((const char *) name,"text") == 0)
1099 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1100 svg_info->bounds.x=0.0;
1101 svg_info->bounds.y=0.0;
1102 svg_info->bounds.width=0.0;
1103 svg_info->bounds.height=0.0;
1106 if (LocaleCompare((const char *) name,"tspan") == 0)
1108 if (*svg_info->text != '\0')
1119 text=EscapeString(svg_info->text,'\'');
1120 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
1121 svg_info->bounds.x-svg_info->center.x,svg_info->bounds.y-
1122 svg_info->center.y,text);
1123 text=DestroyString(text);
1124 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
1125 draw_info->pointsize=svg_info->pointsize;
1126 draw_info->text=AcquireString(svg_info->text);
1127 (void) ConcatenateString(&draw_info->text," ");
1128 (void) GetTypeMetrics(svg_info->image,draw_info,
1129 &metrics,svg_info->exception);
1130 svg_info->bounds.x+=metrics.width;
1131 draw_info=DestroyDrawInfo(draw_info);
1132 *svg_info->text='\0';
1134 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1142 if (attributes != (const xmlChar **) NULL)
1143 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
1145 keyword=(const char *) attributes[i];
1146 value=(const char *) attributes[i+1];
1147 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1148 " %s = %s",keyword,value);
1154 if (LocaleCompare(keyword,"angle") == 0)
1156 (void) FormatLocaleFile(svg_info->file,"angle %g\n",
1157 GetUserSpaceCoordinateValue(svg_info,0,value));
1165 if (LocaleCompare(keyword,"clip-path") == 0)
1167 (void) FormatLocaleFile(svg_info->file,"clip-path '%s'\n",value);
1170 if (LocaleCompare(keyword,"clip-rule") == 0)
1172 (void) FormatLocaleFile(svg_info->file,"clip-rule '%s'\n",value);
1175 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1177 (void) CloneString(&units,value);
1178 (void) FormatLocaleFile(svg_info->file,"clip-units '%s'\n",value);
1181 if (LocaleCompare(keyword,"color") == 0)
1183 (void) CloneString(&color,value);
1186 if (LocaleCompare(keyword,"cx") == 0)
1188 svg_info->element.cx=
1189 GetUserSpaceCoordinateValue(svg_info,1,value);
1192 if (LocaleCompare(keyword,"cy") == 0)
1194 svg_info->element.cy=
1195 GetUserSpaceCoordinateValue(svg_info,-1,value);
1203 if (LocaleCompare(keyword,"d") == 0)
1205 (void) CloneString(&svg_info->vertices,value);
1208 if (LocaleCompare(keyword,"dx") == 0)
1210 svg_info->bounds.x+=GetUserSpaceCoordinateValue(svg_info,1,value);
1213 if (LocaleCompare(keyword,"dy") == 0)
1215 svg_info->bounds.y+=
1216 GetUserSpaceCoordinateValue(svg_info,-1,value);
1224 if (LocaleCompare(keyword,"fill") == 0)
1226 if (LocaleCompare(value,"currentColor") == 0)
1228 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",color);
1231 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",value);
1234 if (LocaleCompare(keyword,"fillcolor") == 0)
1236 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",value);
1239 if (LocaleCompare(keyword,"fill-rule") == 0)
1241 (void) FormatLocaleFile(svg_info->file,"fill-rule '%s'\n",value);
1244 if (LocaleCompare(keyword,"fill-alpha") == 0)
1246 (void) FormatLocaleFile(svg_info->file,"fill-alpha '%s'\n",
1250 if (LocaleCompare(keyword,"font-family") == 0)
1252 (void) FormatLocaleFile(svg_info->file,"font-family '%s'\n",
1256 if (LocaleCompare(keyword,"font-stretch") == 0)
1258 (void) FormatLocaleFile(svg_info->file,"font-stretch '%s'\n",
1262 if (LocaleCompare(keyword,"font-style") == 0)
1264 (void) FormatLocaleFile(svg_info->file,"font-style '%s'\n",value);
1267 if (LocaleCompare(keyword,"font-size") == 0)
1269 svg_info->pointsize=GetUserSpaceCoordinateValue(svg_info,0,value);
1270 (void) FormatLocaleFile(svg_info->file,"font-size %g\n",
1271 svg_info->pointsize);
1274 if (LocaleCompare(keyword,"font-weight") == 0)
1276 (void) FormatLocaleFile(svg_info->file,"font-weight '%s'\n",
1285 if (LocaleCompare(keyword,"gradientTransform") == 0)
1292 GetAffineMatrix(&transform);
1293 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1294 tokens=GetTransformTokens(context,value,&number_tokens);
1295 for (j=0; j < (number_tokens-1); j+=2)
1297 keyword=(char *) tokens[j];
1298 if (keyword == (char *) NULL)
1300 value=(char *) tokens[j+1];
1301 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1302 " %s: %s",keyword,value);
1304 GetAffineMatrix(&affine);
1310 if (LocaleCompare(keyword,"matrix") == 0)
1312 p=(const char *) value;
1313 GetMagickToken(p,&p,token);
1314 affine.sx=StringToDouble(value,(char **) NULL);
1315 GetMagickToken(p,&p,token);
1317 GetMagickToken(p,&p,token);
1318 affine.rx=StringToDouble(token,(char **) NULL);
1319 GetMagickToken(p,&p,token);
1321 GetMagickToken(p,&p,token);
1322 affine.ry=StringToDouble(token,(char **) NULL);
1323 GetMagickToken(p,&p,token);
1325 GetMagickToken(p,&p,token);
1326 affine.sy=StringToDouble(token,(char **) NULL);
1327 GetMagickToken(p,&p,token);
1329 GetMagickToken(p,&p,token);
1330 affine.tx=StringToDouble(token,(char **) NULL);
1331 GetMagickToken(p,&p,token);
1333 GetMagickToken(p,&p,token);
1334 affine.ty=StringToDouble(token,(char **) NULL);
1342 if (LocaleCompare(keyword,"rotate") == 0)
1347 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1348 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1349 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1350 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1351 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1359 if (LocaleCompare(keyword,"scale") == 0)
1361 for (p=(const char *) value; *p != '\0'; p++)
1362 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1365 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1366 affine.sy=affine.sx;
1369 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1370 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
1373 if (LocaleCompare(keyword,"skewX") == 0)
1375 affine.sx=svg_info->affine.sx;
1376 affine.ry=tan(DegreesToRadians(fmod(
1377 GetUserSpaceCoordinateValue(svg_info,1,value),
1379 affine.sy=svg_info->affine.sy;
1382 if (LocaleCompare(keyword,"skewY") == 0)
1384 affine.sx=svg_info->affine.sx;
1385 affine.rx=tan(DegreesToRadians(fmod(
1386 GetUserSpaceCoordinateValue(svg_info,-1,value),
1388 affine.sy=svg_info->affine.sy;
1396 if (LocaleCompare(keyword,"translate") == 0)
1398 for (p=(const char *) value; *p != '\0'; p++)
1399 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1402 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
1403 affine.ty=affine.tx;
1406 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1414 transform.sx=affine.sx*current.sx+affine.ry*current.rx;
1415 transform.rx=affine.rx*current.sx+affine.sy*current.rx;
1416 transform.ry=affine.sx*current.ry+affine.ry*current.sy;
1417 transform.sy=affine.rx*current.ry+affine.sy*current.sy;
1418 transform.tx=affine.tx*current.sx+affine.ty*current.ry+
1420 transform.ty=affine.tx*current.rx+affine.ty*current.sy+
1423 (void) FormatLocaleFile(svg_info->file,
1424 "affine %g %g %g %g %g %g\n",transform.sx,
1425 transform.rx,transform.ry,transform.sy,transform.tx,
1427 for (j=0; tokens[j] != (char *) NULL; j++)
1428 tokens[j]=DestroyString(tokens[j]);
1429 tokens=(char **) RelinquishMagickMemory(tokens);
1432 if (LocaleCompare(keyword,"gradientUnits") == 0)
1434 (void) CloneString(&units,value);
1435 (void) FormatLocaleFile(svg_info->file,"gradient-units '%s'\n",
1444 if (LocaleCompare(keyword,"height") == 0)
1446 svg_info->bounds.height=
1447 GetUserSpaceCoordinateValue(svg_info,-1,value);
1450 if (LocaleCompare(keyword,"href") == 0)
1452 (void) CloneString(&svg_info->url,value);
1460 if (LocaleCompare(keyword,"major") == 0)
1462 svg_info->element.major=
1463 GetUserSpaceCoordinateValue(svg_info,1,value);
1466 if (LocaleCompare(keyword,"minor") == 0)
1468 svg_info->element.minor=
1469 GetUserSpaceCoordinateValue(svg_info,-1,value);
1477 if (LocaleCompare(keyword,"offset") == 0)
1479 (void) CloneString(&svg_info->offset,value);
1482 if (LocaleCompare(keyword,"opacity") == 0)
1484 (void) FormatLocaleFile(svg_info->file,"opacity '%s'\n",value);
1492 if (LocaleCompare(keyword,"path") == 0)
1494 (void) CloneString(&svg_info->url,value);
1497 if (LocaleCompare(keyword,"points") == 0)
1499 (void) CloneString(&svg_info->vertices,value);
1507 if (LocaleCompare(keyword,"r") == 0)
1509 svg_info->element.major=
1510 GetUserSpaceCoordinateValue(svg_info,1,value);
1511 svg_info->element.minor=
1512 GetUserSpaceCoordinateValue(svg_info,-1,value);
1515 if (LocaleCompare(keyword,"rotate") == 0)
1520 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1521 (void) FormatLocaleFile(svg_info->file,"translate %g,%g\n",
1522 svg_info->bounds.x,svg_info->bounds.y);
1523 svg_info->bounds.x=0;
1524 svg_info->bounds.y=0;
1525 (void) FormatLocaleFile(svg_info->file,"rotate %g\n",angle);
1528 if (LocaleCompare(keyword,"rx") == 0)
1530 if (LocaleCompare((const char *) name,"ellipse") == 0)
1531 svg_info->element.major=
1532 GetUserSpaceCoordinateValue(svg_info,1,value);
1535 GetUserSpaceCoordinateValue(svg_info,1,value);
1538 if (LocaleCompare(keyword,"ry") == 0)
1540 if (LocaleCompare((const char *) name,"ellipse") == 0)
1541 svg_info->element.minor=
1542 GetUserSpaceCoordinateValue(svg_info,-1,value);
1545 GetUserSpaceCoordinateValue(svg_info,-1,value);
1553 if (LocaleCompare(keyword,"stop-color") == 0)
1555 (void) CloneString(&svg_info->stop_color,value);
1558 if (LocaleCompare(keyword,"stroke") == 0)
1560 if (LocaleCompare(value,"currentColor") == 0)
1562 (void) FormatLocaleFile(svg_info->file,"stroke '%s'\n",color);
1565 (void) FormatLocaleFile(svg_info->file,"stroke '%s'\n",value);
1568 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1570 (void) FormatLocaleFile(svg_info->file,"stroke-antialias %d\n",
1571 LocaleCompare(value,"true") == 0);
1574 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1576 (void) FormatLocaleFile(svg_info->file,"stroke-dasharray %s\n",
1580 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1582 (void) FormatLocaleFile(svg_info->file,"stroke-dashoffset %s\n",
1586 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1588 (void) FormatLocaleFile(svg_info->file,"stroke-linecap '%s'\n",
1592 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1594 (void) FormatLocaleFile(svg_info->file,"stroke-linejoin '%s'\n",
1598 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1600 (void) FormatLocaleFile(svg_info->file,"stroke-miterlimit '%s'\n",
1604 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1606 (void) FormatLocaleFile(svg_info->file,"stroke-opacity '%s'\n",
1610 if (LocaleCompare(keyword,"stroke-width") == 0)
1612 (void) FormatLocaleFile(svg_info->file,"stroke-width %g\n",
1613 GetUserSpaceCoordinateValue(svg_info,1,value));
1616 if (LocaleCompare(keyword,"style") == 0)
1618 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1619 tokens=GetStyleTokens(context,value,&number_tokens);
1620 for (j=0; j < (number_tokens-1); j+=2)
1622 keyword=(char *) tokens[j];
1623 value=(char *) tokens[j+1];
1624 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1625 " %s: %s",keyword,value);
1631 if (LocaleCompare(keyword,"clip-path") == 0)
1633 (void) FormatLocaleFile(svg_info->file,
1634 "clip-path '%s'\n",value);
1637 if (LocaleCompare(keyword,"clip-rule") == 0)
1639 (void) FormatLocaleFile(svg_info->file,
1640 "clip-rule '%s'\n",value);
1643 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1645 (void) CloneString(&units,value);
1646 (void) FormatLocaleFile(svg_info->file,
1647 "clip-units '%s'\n",value);
1650 if (LocaleCompare(keyword,"color") == 0)
1652 (void) CloneString(&color,value);
1660 if (LocaleCompare(keyword,"fill") == 0)
1662 if (LocaleCompare(value,"currentColor") == 0)
1664 (void) FormatLocaleFile(svg_info->file,
1665 "fill '%s'\n",color);
1668 if (LocaleCompare(value,"#000000ff") == 0)
1669 (void) FormatLocaleFile(svg_info->file,
1670 "fill '#000000'\n");
1672 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",
1676 if (LocaleCompare(keyword,"fillcolor") == 0)
1678 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",
1682 if (LocaleCompare(keyword,"fill-rule") == 0)
1684 (void) FormatLocaleFile(svg_info->file,
1685 "fill-rule '%s'\n",value);
1688 if (LocaleCompare(keyword,"fill-alpha") == 0)
1690 (void) FormatLocaleFile(svg_info->file,
1691 "fill-alpha '%s'\n",value);
1694 if (LocaleCompare(keyword,"font-family") == 0)
1696 (void) FormatLocaleFile(svg_info->file,
1697 "font-family '%s'\n",value);
1700 if (LocaleCompare(keyword,"font-stretch") == 0)
1702 (void) FormatLocaleFile(svg_info->file,
1703 "font-stretch '%s'\n",value);
1706 if (LocaleCompare(keyword,"font-style") == 0)
1708 (void) FormatLocaleFile(svg_info->file,
1709 "font-style '%s'\n",value);
1712 if (LocaleCompare(keyword,"font-size") == 0)
1714 svg_info->pointsize=GetUserSpaceCoordinateValue(
1716 (void) FormatLocaleFile(svg_info->file,"font-size %g\n",
1717 svg_info->pointsize);
1720 if (LocaleCompare(keyword,"font-weight") == 0)
1722 (void) FormatLocaleFile(svg_info->file,
1723 "font-weight '%s'\n",value);
1731 if (LocaleCompare(keyword,"offset") == 0)
1733 (void) FormatLocaleFile(svg_info->file,"offset %g\n",
1734 GetUserSpaceCoordinateValue(svg_info,1,value));
1737 if (LocaleCompare(keyword,"opacity") == 0)
1739 (void) FormatLocaleFile(svg_info->file,
1740 "opacity '%s'\n",value);
1748 if (LocaleCompare(keyword,"stop-color") == 0)
1750 (void) CloneString(&svg_info->stop_color,value);
1753 if (LocaleCompare(keyword,"stroke") == 0)
1755 if (LocaleCompare(value,"currentColor") == 0)
1757 (void) FormatLocaleFile(svg_info->file,
1758 "stroke '%s'\n",color);
1761 if (LocaleCompare(value,"#000000ff") == 0)
1762 (void) FormatLocaleFile(svg_info->file,
1763 "fill '#000000'\n");
1765 (void) FormatLocaleFile(svg_info->file,
1766 "stroke '%s'\n",value);
1769 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1771 (void) FormatLocaleFile(svg_info->file,
1772 "stroke-antialias %d\n",
1773 LocaleCompare(value,"true") == 0);
1776 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1778 (void) FormatLocaleFile(svg_info->file,
1779 "stroke-dasharray %s\n",value);
1782 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1784 (void) FormatLocaleFile(svg_info->file,
1785 "stroke-dashoffset %s\n",
1789 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1791 (void) FormatLocaleFile(svg_info->file,
1792 "stroke-linecap '%s'\n",value);
1795 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1797 (void) FormatLocaleFile(svg_info->file,
1798 "stroke-linejoin '%s'\n",
1802 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1804 (void) FormatLocaleFile(svg_info->file,
1805 "stroke-miterlimit '%s'\n",
1809 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1811 (void) FormatLocaleFile(svg_info->file,
1812 "stroke-opacity '%s'\n",value);
1815 if (LocaleCompare(keyword,"stroke-width") == 0)
1817 (void) FormatLocaleFile(svg_info->file,
1818 "stroke-width %g\n",
1819 GetUserSpaceCoordinateValue(svg_info,1,value));
1827 if (LocaleCompare(keyword,"text-align") == 0)
1829 (void) FormatLocaleFile(svg_info->file,
1830 "text-align '%s'\n",value);
1833 if (LocaleCompare(keyword,"text-anchor") == 0)
1835 (void) FormatLocaleFile(svg_info->file,
1836 "text-anchor '%s'\n",value);
1839 if (LocaleCompare(keyword,"text-decoration") == 0)
1841 if (LocaleCompare(value,"underline") == 0)
1842 (void) FormatLocaleFile(svg_info->file,
1843 "decorate underline\n");
1844 if (LocaleCompare(value,"line-through") == 0)
1845 (void) FormatLocaleFile(svg_info->file,
1846 "decorate line-through\n");
1847 if (LocaleCompare(value,"overline") == 0)
1848 (void) FormatLocaleFile(svg_info->file,
1849 "decorate overline\n");
1852 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1854 (void) FormatLocaleFile(svg_info->file,
1855 "text-antialias %d\n",
1856 LocaleCompare(value,"true") == 0);
1865 for (j=0; tokens[j] != (char *) NULL; j++)
1866 tokens[j]=DestroyString(tokens[j]);
1867 tokens=(char **) RelinquishMagickMemory(tokens);
1875 if (LocaleCompare(keyword,"text-align") == 0)
1877 (void) FormatLocaleFile(svg_info->file,"text-align '%s'\n",
1881 if (LocaleCompare(keyword,"text-anchor") == 0)
1883 (void) FormatLocaleFile(svg_info->file,"text-anchor '%s'\n",
1887 if (LocaleCompare(keyword,"text-decoration") == 0)
1889 if (LocaleCompare(value,"underline") == 0)
1890 (void) FormatLocaleFile(svg_info->file,"decorate underline\n");
1891 if (LocaleCompare(value,"line-through") == 0)
1892 (void) FormatLocaleFile(svg_info->file,
1893 "decorate line-through\n");
1894 if (LocaleCompare(value,"overline") == 0)
1895 (void) FormatLocaleFile(svg_info->file,"decorate overline\n");
1898 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1900 (void) FormatLocaleFile(svg_info->file,"text-antialias %d\n",
1901 LocaleCompare(value,"true") == 0);
1904 if (LocaleCompare(keyword,"transform") == 0)
1911 GetAffineMatrix(&transform);
1912 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1913 tokens=GetTransformTokens(context,value,&number_tokens);
1914 for (j=0; j < (number_tokens-1); j+=2)
1916 keyword=(char *) tokens[j];
1917 value=(char *) tokens[j+1];
1918 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1919 " %s: %s",keyword,value);
1921 GetAffineMatrix(&affine);
1927 if (LocaleCompare(keyword,"matrix") == 0)
1929 p=(const char *) value;
1930 GetMagickToken(p,&p,token);
1931 affine.sx=StringToDouble(value,(char **) NULL);
1932 GetMagickToken(p,&p,token);
1934 GetMagickToken(p,&p,token);
1935 affine.rx=StringToDouble(token,(char **) NULL);
1936 GetMagickToken(p,&p,token);
1938 GetMagickToken(p,&p,token);
1939 affine.ry=StringToDouble(token,(char **) NULL);
1940 GetMagickToken(p,&p,token);
1942 GetMagickToken(p,&p,token);
1943 affine.sy=StringToDouble(token,(char **) NULL);
1944 GetMagickToken(p,&p,token);
1946 GetMagickToken(p,&p,token);
1947 affine.tx=StringToDouble(token,(char **) NULL);
1948 GetMagickToken(p,&p,token);
1950 GetMagickToken(p,&p,token);
1951 affine.ty=StringToDouble(token,(char **) NULL);
1959 if (LocaleCompare(keyword,"rotate") == 0)
1966 p=(const char *) value;
1967 GetMagickToken(p,&p,token);
1968 angle=StringToDouble(value,(char **) NULL);
1969 GetMagickToken(p,&p,token);
1971 GetMagickToken(p,&p,token);
1972 x=StringToDouble(token,(char **) NULL);
1973 GetMagickToken(p,&p,token);
1975 GetMagickToken(p,&p,token);
1976 y=StringToDouble(token,(char **) NULL);
1977 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1978 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1979 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1980 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1983 svg_info->center.x=x;
1984 svg_info->center.y=y;
1992 if (LocaleCompare(keyword,"scale") == 0)
1994 for (p=(const char *) value; *p != '\0'; p++)
1995 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1998 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1999 affine.sy=affine.sx;
2001 affine.sy=GetUserSpaceCoordinateValue(svg_info,-1,
2003 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
2006 if (LocaleCompare(keyword,"skewX") == 0)
2008 affine.sx=svg_info->affine.sx;
2009 affine.ry=tan(DegreesToRadians(fmod(
2010 GetUserSpaceCoordinateValue(svg_info,1,value),
2012 affine.sy=svg_info->affine.sy;
2015 if (LocaleCompare(keyword,"skewY") == 0)
2017 affine.sx=svg_info->affine.sx;
2018 affine.rx=tan(DegreesToRadians(fmod(
2019 GetUserSpaceCoordinateValue(svg_info,-1,value),
2021 affine.sy=svg_info->affine.sy;
2029 if (LocaleCompare(keyword,"translate") == 0)
2031 for (p=(const char *) value; *p != '\0'; p++)
2032 if ((isspace((int) ((unsigned char) *p)) != 0) ||
2035 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
2036 affine.ty=affine.tx;
2038 affine.ty=GetUserSpaceCoordinateValue(svg_info,-1,
2047 transform.sx=affine.sx*current.sx+affine.ry*current.rx;
2048 transform.rx=affine.rx*current.sx+affine.sy*current.rx;
2049 transform.ry=affine.sx*current.ry+affine.ry*current.sy;
2050 transform.sy=affine.rx*current.ry+affine.sy*current.sy;
2051 transform.tx=affine.tx*current.sx+affine.ty*current.ry+
2053 transform.ty=affine.tx*current.rx+affine.ty*current.sy+
2056 (void) FormatLocaleFile(svg_info->file,
2057 "affine %g %g %g %g %g %g\n",transform.sx,transform.rx,
2058 transform.ry,transform.sy,transform.tx,transform.ty);
2059 for (j=0; tokens[j] != (char *) NULL; j++)
2060 tokens[j]=DestroyString(tokens[j]);
2061 tokens=(char **) RelinquishMagickMemory(tokens);
2069 if (LocaleCompare(keyword,"verts") == 0)
2071 (void) CloneString(&svg_info->vertices,value);
2074 if (LocaleCompare(keyword,"viewBox") == 0)
2076 p=(const char *) value;
2077 GetMagickToken(p,&p,token);
2078 svg_info->view_box.x=StringToDouble(token,(char **) NULL);
2079 GetMagickToken(p,&p,token);
2081 GetMagickToken(p,&p,token);
2082 svg_info->view_box.y=StringToDouble(token,(char **) NULL);
2083 GetMagickToken(p,&p,token);
2085 GetMagickToken(p,&p,token);
2086 svg_info->view_box.width=StringToDouble(token,
2088 if (svg_info->bounds.width == 0)
2089 svg_info->bounds.width=svg_info->view_box.width;
2090 GetMagickToken(p,&p,token);
2092 GetMagickToken(p,&p,token);
2093 svg_info->view_box.height=StringToDouble(token,
2095 if (svg_info->bounds.height == 0)
2096 svg_info->bounds.height=svg_info->view_box.height;
2104 if (LocaleCompare(keyword,"width") == 0)
2106 svg_info->bounds.width=
2107 GetUserSpaceCoordinateValue(svg_info,1,value);
2115 if (LocaleCompare(keyword,"x") == 0)
2117 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value);
2120 if (LocaleCompare(keyword,"xlink:href") == 0)
2122 (void) CloneString(&svg_info->url,value);
2125 if (LocaleCompare(keyword,"x1") == 0)
2127 svg_info->segment.x1=
2128 GetUserSpaceCoordinateValue(svg_info,1,value);
2131 if (LocaleCompare(keyword,"x2") == 0)
2133 svg_info->segment.x2=
2134 GetUserSpaceCoordinateValue(svg_info,1,value);
2142 if (LocaleCompare(keyword,"y") == 0)
2144 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value);
2147 if (LocaleCompare(keyword,"y1") == 0)
2149 svg_info->segment.y1=
2150 GetUserSpaceCoordinateValue(svg_info,-1,value);
2153 if (LocaleCompare(keyword,"y2") == 0)
2155 svg_info->segment.y2=
2156 GetUserSpaceCoordinateValue(svg_info,-1,value);
2165 if (LocaleCompare((const char *) name,"svg") == 0)
2167 if (svg_info->document->encoding != (const xmlChar *) NULL)
2168 (void) FormatLocaleFile(svg_info->file,"encoding \"%s\"\n",
2169 (const char *) svg_info->document->encoding);
2170 if (attributes != (const xmlChar **) NULL)
2178 if ((svg_info->view_box.width == 0.0) ||
2179 (svg_info->view_box.height == 0.0))
2180 svg_info->view_box=svg_info->bounds;
2181 svg_info->width=(size_t) floor(svg_info->bounds.width+0.5);
2182 svg_info->height=(size_t) floor(svg_info->bounds.height+0.5);
2183 (void) FormatLocaleFile(svg_info->file,"viewbox 0 0 %.20g %.20g\n",
2184 (double) svg_info->width,(double) svg_info->height);
2185 sx=(double) svg_info->width/svg_info->view_box.width;
2186 sy=(double) svg_info->height/svg_info->view_box.height;
2187 tx=svg_info->view_box.x != 0.0 ? (double) -sx*svg_info->view_box.x :
2189 ty=svg_info->view_box.y != 0.0 ? (double) -sy*svg_info->view_box.y :
2191 (void) FormatLocaleFile(svg_info->file,"affine %g 0 0 %g %g %g\n",
2195 (void) LogMagickEvent(CoderEvent,GetMagickModule()," )");
2196 units=DestroyString(units);
2197 if (color != (char *) NULL)
2198 color=DestroyString(color);
2201 static void SVGEndElement(void *context,const xmlChar *name)
2207 Called when the end of an element has been detected.
2209 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2210 " SAX.endElement(%s)",name);
2211 svg_info=(SVGInfo *) context;
2212 if (strchr((char *) name,':') != (char *) NULL)
2215 Skip over namespace.
2217 for ( ; *name != ':'; name++) ;
2225 if (LocaleCompare((const char *) name,"circle") == 0)
2227 (void) FormatLocaleFile(svg_info->file,"circle %g,%g %g,%g\n",
2228 svg_info->element.cx,svg_info->element.cy,svg_info->element.cx,
2229 svg_info->element.cy+svg_info->element.minor);
2230 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2233 if (LocaleCompare((const char *) name,"clipPath") == 0)
2235 (void) FormatLocaleFile(svg_info->file,"pop clip-path\n");
2243 if (LocaleCompare((const char *) name,"defs") == 0)
2245 (void) FormatLocaleFile(svg_info->file,"pop defs\n");
2248 if (LocaleCompare((const char *) name,"desc") == 0)
2253 if (*svg_info->text == '\0')
2255 (void) fputc('#',svg_info->file);
2256 for (p=svg_info->text; *p != '\0'; p++)
2258 (void) fputc(*p,svg_info->file);
2260 (void) fputc('#',svg_info->file);
2262 (void) fputc('\n',svg_info->file);
2263 *svg_info->text='\0';
2271 if (LocaleCompare((const char *) name,"ellipse") == 0)
2276 angle=svg_info->element.angle;
2277 (void) FormatLocaleFile(svg_info->file,"ellipse %g,%g %g,%g 0,360\n",
2278 svg_info->element.cx,svg_info->element.cy,
2279 angle == 0.0 ? svg_info->element.major : svg_info->element.minor,
2280 angle == 0.0 ? svg_info->element.minor : svg_info->element.major);
2281 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2289 if (LocaleCompare((const char *) name,"g") == 0)
2291 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2299 if (LocaleCompare((const char *) name,"image") == 0)
2301 (void) FormatLocaleFile(svg_info->file,
2302 "image Over %g,%g %g,%g '%s'\n",svg_info->bounds.x,
2303 svg_info->bounds.y,svg_info->bounds.width,svg_info->bounds.height,
2305 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2313 if (LocaleCompare((const char *) name,"line") == 0)
2315 (void) FormatLocaleFile(svg_info->file,"line %g,%g %g,%g\n",
2316 svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
2317 svg_info->segment.y2);
2318 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2321 if (LocaleCompare((const char *) name,"linearGradient") == 0)
2323 (void) FormatLocaleFile(svg_info->file,"pop gradient\n");
2331 if (LocaleCompare((const char *) name,"pattern") == 0)
2333 (void) FormatLocaleFile(svg_info->file,"pop pattern\n");
2336 if (LocaleCompare((const char *) name,"path") == 0)
2338 (void) FormatLocaleFile(svg_info->file,"path '%s'\n",
2339 svg_info->vertices);
2340 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2343 if (LocaleCompare((const char *) name,"polygon") == 0)
2345 (void) FormatLocaleFile(svg_info->file,"polygon %s\n",
2346 svg_info->vertices);
2347 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2350 if (LocaleCompare((const char *) name,"polyline") == 0)
2352 (void) FormatLocaleFile(svg_info->file,"polyline %s\n",
2353 svg_info->vertices);
2354 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2362 if (LocaleCompare((const char *) name,"radialGradient") == 0)
2364 (void) FormatLocaleFile(svg_info->file,"pop gradient\n");
2367 if (LocaleCompare((const char *) name,"rect") == 0)
2369 if ((svg_info->radius.x == 0.0) && (svg_info->radius.y == 0.0))
2371 (void) FormatLocaleFile(svg_info->file,"rectangle %g,%g %g,%g\n",
2372 svg_info->bounds.x,svg_info->bounds.y,
2373 svg_info->bounds.x+svg_info->bounds.width,
2374 svg_info->bounds.y+svg_info->bounds.height);
2375 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2378 if (svg_info->radius.x == 0.0)
2379 svg_info->radius.x=svg_info->radius.y;
2380 if (svg_info->radius.y == 0.0)
2381 svg_info->radius.y=svg_info->radius.x;
2382 (void) FormatLocaleFile(svg_info->file,
2383 "roundRectangle %g,%g %g,%g %g,%g\n",
2384 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.x+
2385 svg_info->bounds.width,svg_info->bounds.y+svg_info->bounds.height,
2386 svg_info->radius.x,svg_info->radius.y);
2387 svg_info->radius.x=0.0;
2388 svg_info->radius.y=0.0;
2389 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2397 if (LocaleCompare((const char *) name,"stop") == 0)
2399 (void) FormatLocaleFile(svg_info->file,"stop-color '%s' %s\n",
2400 svg_info->stop_color,svg_info->offset);
2403 if (LocaleCompare((const char *) name,"svg") == 0)
2405 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2413 if (LocaleCompare((const char *) name,"text") == 0)
2415 if (*svg_info->text != '\0')
2420 text=EscapeString(svg_info->text,'\'');
2421 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
2422 svg_info->bounds.x,svg_info->bounds.y,text);
2423 text=DestroyString(text);
2424 *svg_info->text='\0';
2426 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2429 if (LocaleCompare((const char *) name,"tspan") == 0)
2431 if (*svg_info->text != '\0')
2442 text=EscapeString(svg_info->text,'\'');
2443 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
2444 svg_info->bounds.x,svg_info->bounds.y,text);
2445 text=DestroyString(text);
2446 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
2447 draw_info->pointsize=svg_info->pointsize;
2448 draw_info->text=AcquireString(svg_info->text);
2449 (void) ConcatenateString(&draw_info->text," ");
2450 (void) GetTypeMetrics(svg_info->image,draw_info,&metrics,
2451 svg_info->exception);
2452 svg_info->bounds.x+=metrics.width;
2453 draw_info=DestroyDrawInfo(draw_info);
2454 *svg_info->text='\0';
2456 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2459 if (LocaleCompare((const char *) name,"title") == 0)
2461 if (*svg_info->text == '\0')
2463 (void) CloneString(&svg_info->title,svg_info->text);
2464 *svg_info->text='\0';
2472 *svg_info->text='\0';
2473 (void) ResetMagickMemory(&svg_info->element,0,sizeof(svg_info->element));
2474 (void) ResetMagickMemory(&svg_info->segment,0,sizeof(svg_info->segment));
2478 static void SVGCharacters(void *context,const xmlChar *c,int length)
2493 Receiving some characters from the parser.
2495 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2496 " SAX.characters(%s,%.20g)",c,(double) length);
2497 svg_info=(SVGInfo *) context;
2498 text=(char *) AcquireQuantumMemory(length+1,sizeof(*text));
2499 if (text == (char *) NULL)
2502 for (i=0; i < (ssize_t) length; i++)
2506 if (svg_info->text == (char *) NULL)
2507 svg_info->text=text;
2510 (void) ConcatenateString(&svg_info->text,text);
2511 text=DestroyString(text);
2515 static void SVGReference(void *context,const xmlChar *name)
2524 Called when an entity reference is detected.
2526 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.reference(%s)",
2528 svg_info=(SVGInfo *) context;
2529 parser=svg_info->parser;
2530 if (parser == (xmlParserCtxtPtr) NULL)
2532 if (parser->node == (xmlNodePtr) NULL)
2535 (void) xmlAddChild(parser->node,xmlNewCharRef(svg_info->document,name));
2537 (void) xmlAddChild(parser->node,xmlNewReference(svg_info->document,name));
2540 static void SVGIgnorableWhitespace(void *context,const xmlChar *c,int length)
2546 Receiving some ignorable whitespaces from the parser.
2548 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2549 " SAX.ignorableWhitespace(%.30s, %d)",c,length);
2550 svg_info=(SVGInfo *) context;
2554 static void SVGProcessingInstructions(void *context,const xmlChar *target,
2555 const xmlChar *data)
2561 A processing instruction has been parsed.
2563 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2564 " SAX.processingInstruction(%s, %s)",target,data);
2565 svg_info=(SVGInfo *) context;
2569 static void SVGComment(void *context,const xmlChar *value)
2575 A comment has been parsed.
2577 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.comment(%s)",
2579 svg_info=(SVGInfo *) context;
2580 if (svg_info->comment != (char *) NULL)
2581 (void) ConcatenateString(&svg_info->comment,"\n");
2582 (void) ConcatenateString(&svg_info->comment,(const char *) value);
2585 static void SVGWarning(void *context,const char *format,...)
2589 reason[MaxTextExtent];
2598 Display and format a warning messages, gives file, line, position and
2601 va_start(operands,format);
2602 svg_info=(SVGInfo *) context;
2603 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.warning: ");
2604 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2605 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2606 (void) vsprintf(reason,format,operands);
2608 (void) vsnprintf(reason,MaxTextExtent,format,operands);
2610 message=GetExceptionMessage(errno);
2611 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
2612 DelegateWarning,reason,"`%s`",message);
2613 message=DestroyString(message);
2617 static void SVGError(void *context,const char *format,...)
2621 reason[MaxTextExtent];
2630 Display and format a error formats, gives file, line, position and
2633 va_start(operands,format);
2634 svg_info=(SVGInfo *) context;
2635 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.error: ");
2636 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2637 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2638 (void) vsprintf(reason,format,operands);
2640 (void) vsnprintf(reason,MaxTextExtent,format,operands);
2642 message=GetExceptionMessage(errno);
2643 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),CoderError,
2644 reason,"`%s`",message);
2645 message=DestroyString(message);
2649 static void SVGCDataBlock(void *context,const xmlChar *value,int length)
2661 Called when a pcdata block has been parsed.
2663 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.pcdata(%s, %d)",
2665 svg_info=(SVGInfo *) context;
2666 parser=svg_info->parser;
2667 child=xmlGetLastChild(parser->node);
2668 if ((child != (xmlNodePtr) NULL) && (child->type == XML_CDATA_SECTION_NODE))
2670 xmlTextConcat(child,value,length);
2673 (void) xmlAddChild(parser->node,xmlNewCDataBlock(parser->myDoc,value,length));
2676 static void SVGExternalSubset(void *context,const xmlChar *name,
2677 const xmlChar *external_id,const xmlChar *system_id)
2692 Does this document has an external subset?
2694 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2695 " SAX.externalSubset(%s, %s, %s)",name,
2696 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
2697 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
2698 svg_info=(SVGInfo *) context;
2699 parser=svg_info->parser;
2700 if (((external_id == NULL) && (system_id == NULL)) ||
2701 ((parser->validate == 0) || (parser->wellFormed == 0) ||
2702 (svg_info->document == 0)))
2704 input=SVGResolveEntity(context,external_id,system_id);
2707 (void) xmlNewDtd(svg_info->document,name,external_id,system_id);
2708 parser_context=(*parser);
2709 parser->inputTab=(xmlParserInputPtr *) xmlMalloc(5*sizeof(*parser->inputTab));
2710 if (parser->inputTab == (xmlParserInputPtr *) NULL)
2712 parser->errNo=XML_ERR_NO_MEMORY;
2713 parser->input=parser_context.input;
2714 parser->inputNr=parser_context.inputNr;
2715 parser->inputMax=parser_context.inputMax;
2716 parser->inputTab=parser_context.inputTab;
2722 xmlPushInput(parser,input);
2723 (void) xmlSwitchEncoding(parser,xmlDetectCharEncoding(parser->input->cur,4));
2724 if (input->filename == (char *) NULL)
2725 input->filename=(char *) xmlStrdup(system_id);
2728 input->base=parser->input->cur;
2729 input->cur=parser->input->cur;
2731 xmlParseExternalSubset(parser,external_id,system_id);
2732 while (parser->inputNr > 1)
2733 (void) xmlPopInput(parser);
2734 xmlFreeInputStream(parser->input);
2735 xmlFree(parser->inputTab);
2736 parser->input=parser_context.input;
2737 parser->inputNr=parser_context.inputNr;
2738 parser->inputMax=parser_context.inputMax;
2739 parser->inputTab=parser_context.inputTab;
2742 #if defined(__cplusplus) || defined(c_plusplus)
2747 Static declarations.
2750 SVGDensityGeometry[] = "90.0x90.0";
2753 static Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
2756 filename[MaxTextExtent];
2775 message[MaxTextExtent];
2786 assert(image_info != (const ImageInfo *) NULL);
2787 assert(image_info->signature == MagickSignature);
2788 assert(exception != (ExceptionInfo *) NULL);
2789 if (image_info->debug != MagickFalse)
2790 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2791 image_info->filename);
2792 assert(exception->signature == MagickSignature);
2793 image=AcquireImage(image_info,exception);
2794 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2795 if (status == MagickFalse)
2797 image=DestroyImageList(image);
2798 return((Image *) NULL);
2800 if ((image->resolution.x == 0.0) || (image->resolution.y == 0.0))
2808 flags=ParseGeometry(SVGDensityGeometry,&geometry_info);
2809 image->resolution.x=geometry_info.rho;
2810 image->resolution.y=geometry_info.sigma;
2811 if ((flags & SigmaValue) == 0)
2812 image->resolution.y=image->resolution.x;
2814 if (LocaleCompare(image_info->magick,"MSVG") != 0)
2819 delegate_info=GetDelegateInfo("svg:decode",(char *) NULL,exception);
2820 if (delegate_info != (const DelegateInfo *) NULL)
2823 background[MaxTextExtent],
2824 command[MaxTextExtent],
2825 density[MaxTextExtent],
2826 filename[MaxTextExtent],
2827 opacity[MaxTextExtent],
2828 unique[MaxTextExtent];
2834 Our best hope for compliance to the SVG standard.
2836 (void) AcquireUniqueFilename(filename);
2837 (void) AcquireUniqueFilename(unique);
2838 (void) FormatLocaleString(density,MaxTextExtent,"%.20g,%.20g",
2839 image->resolution.x,image->resolution.y);
2840 (void) FormatLocaleString(background,MaxTextExtent,
2841 "rgb(%.20g%%,%.20g%%,%.20g%%)",
2842 100.0*QuantumScale*image->background_color.red,
2843 100.0*QuantumScale*image->background_color.green,
2844 100.0*QuantumScale*image->background_color.blue);
2845 (void) FormatLocaleString(opacity,MaxTextExtent,"%.20g",
2846 QuantumScale*image->background_color.alpha);
2847 (void) FormatLocaleString(command,MaxTextExtent,
2848 GetDelegateCommands(delegate_info),image->filename,filename,density,
2849 background,opacity,unique);
2850 status=SystemCommand(MagickFalse,image_info->verbose,command,
2852 (void) RelinquishUniqueFileResource(unique);
2858 read_info=CloneImageInfo(image_info);
2859 (void) CopyMagickString(read_info->filename,filename,
2861 image=ReadImage(read_info,exception);
2862 read_info=DestroyImageInfo(read_info);
2863 (void) RelinquishUniqueFileResource(filename);
2864 if (image != (Image *) NULL)
2867 (void) RelinquishUniqueFileResource(filename);
2870 #if defined(MAGICKCORE_RSVG_DELEGATE)
2871 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2881 register unsigned char
2894 register const guchar
2917 svg_handle=rsvg_handle_new();
2918 if (svg_handle == (RsvgHandle *) NULL)
2919 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2920 rsvg_handle_set_base_uri(svg_handle,image_info->filename);
2921 rsvg_handle_set_dpi_x_y(svg_handle,image->resolution.x,
2922 image->resolution.y);
2923 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
2925 error=(GError *) NULL;
2926 (void) rsvg_handle_write(svg_handle,message,n,&error);
2927 if (error != (GError *) NULL)
2928 g_error_free(error);
2930 error=(GError *) NULL;
2931 rsvg_handle_close(svg_handle,&error);
2932 if (error != (GError *) NULL)
2933 g_error_free(error);
2934 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2935 rsvg_handle_get_dimensions(svg_handle,&dimension_info);
2936 image->columns=image->resolution.x*dimension_info.width/72.0;
2937 image->rows=image->resolution.y*dimension_info.height/72.0;
2938 pixel_info=(MemoryInfo *) NULL;
2940 pixel_buffer=rsvg_handle_get_pixbuf(svg_handle);
2941 rsvg_handle_free(svg_handle);
2942 image->columns=gdk_pixbuf_get_width(pixel_buffer);
2943 image->rows=gdk_pixbuf_get_height(pixel_buffer);
2945 image->alpha_trait=BlendPixelTrait;
2946 SetImageProperty(image,"svg:base-uri",
2947 rsvg_handle_get_base_uri(svg_handle),exception);
2948 if ((image->columns == 0) || (image->rows == 0))
2950 #if !defined(MAGICKCORE_CAIRO_DELEGATE)
2951 g_object_unref(G_OBJECT(pixel_buffer));
2953 g_object_unref(svg_handle);
2954 ThrowReaderException(MissingDelegateError,
2955 "NoDecodeDelegateForThisImageFormat");
2957 if (image_info->ping == MagickFalse)
2962 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2963 stride=4*image->columns;
2964 #if defined(MAGICKCORE_PANGOCAIRO_DELEGATE)
2965 stride=(size_t) cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32,
2968 pixel_info=AcquireVirtualMemory(stride,image->rows*sizeof(*pixels));
2969 if (pixel_info == (MemoryInfo *) NULL)
2971 g_object_unref(svg_handle);
2972 ThrowReaderException(ResourceLimitError,
2973 "MemoryAllocationFailed");
2975 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
2977 (void) SetImageBackgroundColor(image,exception);
2978 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2979 cairo_surface=cairo_image_surface_create_for_data(pixels,
2980 CAIRO_FORMAT_ARGB32,image->columns,image->rows,stride);
2981 if (cairo_surface == (cairo_surface_t *) NULL)
2983 pixel_info=RelinquishVirtualMemory(pixel_info);
2984 g_object_unref(svg_handle);
2985 ThrowReaderException(ResourceLimitError,
2986 "MemoryAllocationFailed");
2988 cairo_image=cairo_create(cairo_surface);
2989 cairo_set_operator(cairo_image,CAIRO_OPERATOR_CLEAR);
2990 cairo_paint(cairo_image);
2991 cairo_set_operator(cairo_image,CAIRO_OPERATOR_OVER);
2992 cairo_scale(cairo_image,image->resolution.x/72.0,
2993 image->resolution.y/72.0);
2994 rsvg_handle_render_cairo(svg_handle,cairo_image);
2995 cairo_destroy(cairo_image);
2996 cairo_surface_destroy(cairo_surface);
2997 g_object_unref(svg_handle);
3000 p=gdk_pixbuf_get_pixels(pixel_buffer);
3002 GetPixelInfo(image,&fill_color);
3003 for (y=0; y < (ssize_t) image->rows; y++)
3005 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3006 if (q == (Quantum *) NULL)
3008 for (x=0; x < (ssize_t) image->columns; x++)
3010 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3011 fill_color.blue=ScaleCharToQuantum(*p++);
3012 fill_color.green=ScaleCharToQuantum(*p++);
3013 fill_color.red=ScaleCharToQuantum(*p++);
3015 fill_color.red=ScaleCharToQuantum(*p++);
3016 fill_color.green=ScaleCharToQuantum(*p++);
3017 fill_color.blue=ScaleCharToQuantum(*p++);
3019 fill_color.alpha=ScaleCharToQuantum(*p++);
3020 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3025 gamma=QuantumScale*fill_color.alpha;
3026 gamma=PerceptibleReciprocal(gamma);
3027 fill_color.blue*=gamma;
3028 fill_color.green*=gamma;
3029 fill_color.red*=gamma;
3032 CompositePixelOver(image,&fill_color,fill_color.alpha,q,(double)
3033 GetPixelAlpha(image,q),q);
3034 q+=GetPixelChannels(image);
3036 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3038 if (image->previous == (Image *) NULL)
3040 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
3042 if (status == MagickFalse)
3047 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3048 if (pixel_info != (MemoryInfo *) NULL)
3049 pixel_info=RelinquishVirtualMemory(pixel_info);
3051 g_object_unref(G_OBJECT(pixel_buffer));
3053 (void) CloseBlob(image);
3054 return(GetFirstImageInList(image));
3062 unique_file=AcquireUniqueFileResource(filename);
3063 if (unique_file != -1)
3064 file=fdopen(unique_file,"w");
3065 if ((unique_file == -1) || (file == (FILE *) NULL))
3067 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
3068 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
3070 image=DestroyImageList(image);
3071 return((Image *) NULL);
3076 svg_info=AcquireSVGInfo();
3077 if (svg_info == (SVGInfo *) NULL)
3078 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3079 svg_info->file=file;
3080 svg_info->exception=exception;
3081 svg_info->image=image;
3082 svg_info->image_info=image_info;
3083 svg_info->bounds.width=image->columns;
3084 svg_info->bounds.height=image->rows;
3085 if (image_info->size != (char *) NULL)
3086 (void) CloneString(&svg_info->size,image_info->size);
3087 if (image->debug != MagickFalse)
3088 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"begin SAX");
3090 (void) xmlSubstituteEntitiesDefault(1);
3091 (void) ResetMagickMemory(&sax_modules,0,sizeof(sax_modules));
3092 sax_modules.internalSubset=SVGInternalSubset;
3093 sax_modules.isStandalone=SVGIsStandalone;
3094 sax_modules.hasInternalSubset=SVGHasInternalSubset;
3095 sax_modules.hasExternalSubset=SVGHasExternalSubset;
3096 sax_modules.resolveEntity=SVGResolveEntity;
3097 sax_modules.getEntity=SVGGetEntity;
3098 sax_modules.entityDecl=SVGEntityDeclaration;
3099 sax_modules.notationDecl=SVGNotationDeclaration;
3100 sax_modules.attributeDecl=SVGAttributeDeclaration;
3101 sax_modules.elementDecl=SVGElementDeclaration;
3102 sax_modules.unparsedEntityDecl=SVGUnparsedEntityDeclaration;
3103 sax_modules.setDocumentLocator=SVGSetDocumentLocator;
3104 sax_modules.startDocument=SVGStartDocument;
3105 sax_modules.endDocument=SVGEndDocument;
3106 sax_modules.startElement=SVGStartElement;
3107 sax_modules.endElement=SVGEndElement;
3108 sax_modules.reference=SVGReference;
3109 sax_modules.characters=SVGCharacters;
3110 sax_modules.ignorableWhitespace=SVGIgnorableWhitespace;
3111 sax_modules.processingInstruction=SVGProcessingInstructions;
3112 sax_modules.comment=SVGComment;
3113 sax_modules.warning=SVGWarning;
3114 sax_modules.error=SVGError;
3115 sax_modules.fatalError=SVGError;
3116 sax_modules.getParameterEntity=SVGGetParameterEntity;
3117 sax_modules.cdataBlock=SVGCDataBlock;
3118 sax_modules.externalSubset=SVGExternalSubset;
3119 sax_handler=(&sax_modules);
3120 n=ReadBlob(image,MaxTextExtent,message);
3123 svg_info->parser=xmlCreatePushParserCtxt(sax_handler,svg_info,(char *)
3124 message,n,image->filename);
3125 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
3127 status=xmlParseChunk(svg_info->parser,(char *) message,(int) n,0);
3132 (void) xmlParseChunk(svg_info->parser,(char *) message,0,1);
3133 xmlFreeParserCtxt(svg_info->parser);
3134 if (image->debug != MagickFalse)
3135 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"end SAX");
3137 (void) fclose(file);
3138 (void) CloseBlob(image);
3139 image->columns=svg_info->width;
3140 image->rows=svg_info->height;
3141 if (exception->severity >= ErrorException)
3143 image=DestroyImage(image);
3144 return((Image *) NULL);
3146 if (image_info->ping == MagickFalse)
3154 image=DestroyImage(image);
3155 image=(Image *) NULL;
3156 read_info=CloneImageInfo(image_info);
3157 SetImageInfoBlob(read_info,(void *) NULL,0);
3158 if (read_info->density != (char *) NULL)
3159 read_info->density=DestroyString(read_info->density);
3160 (void) FormatLocaleString(read_info->filename,MaxTextExtent,"mvg:%s",
3162 image=ReadImage(read_info,exception);
3163 read_info=DestroyImageInfo(read_info);
3164 if (image != (Image *) NULL)
3165 (void) CopyMagickString(image->filename,image_info->filename,
3169 Relinquish resources.
3171 if (image != (Image *) NULL)
3173 if (svg_info->title != (char *) NULL)
3174 (void) SetImageProperty(image,"svg:title",svg_info->title,exception);
3175 if (svg_info->comment != (char *) NULL)
3176 (void) SetImageProperty(image,"svg:comment",svg_info->comment,
3179 svg_info=DestroySVGInfo(svg_info);
3180 (void) RelinquishUniqueFileResource(filename);
3181 return(GetFirstImageInList(image));
3186 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3190 % R e g i s t e r S V G I m a g e %
3194 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3196 % RegisterSVGImage() adds attributes for the SVG image format to
3197 % the list of supported formats. The attributes include the image format
3198 % tag, a method to read and/or write the format, whether the format
3199 % supports the saving of more than one frame to the same file or blob,
3200 % whether the format supports native in-memory I/O, and a brief
3201 % description of the format.
3203 % The format of the RegisterSVGImage method is:
3205 % size_t RegisterSVGImage(void)
3208 ModuleExport size_t RegisterSVGImage(void)
3211 version[MaxTextExtent];
3217 #if defined(LIBXML_DOTTED_VERSION)
3218 (void) CopyMagickString(version,"XML " LIBXML_DOTTED_VERSION,MaxTextExtent);
3220 #if defined(MAGICKCORE_RSVG_DELEGATE)
3221 #if !GLIB_CHECK_VERSION(2,5,0)
3224 (void) FormatLocaleString(version,MaxTextExtent,"RSVG %d.%d.%d",
3225 LIBRSVG_MAJOR_VERSION,LIBRSVG_MINOR_VERSION,LIBRSVG_MICRO_VERSION);
3227 entry=SetMagickInfo("SVG");
3228 #if defined(MAGICKCORE_XML_DELEGATE)
3229 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3231 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3232 entry->blob_support=MagickFalse;
3233 entry->seekable_stream=MagickFalse;
3234 entry->description=ConstantString("Scalable Vector Graphics");
3235 if (*version != '\0')
3236 entry->version=ConstantString(version);
3237 entry->magick=(IsImageFormatHandler *) IsSVG;
3238 entry->module=ConstantString("SVG");
3239 (void) RegisterMagickInfo(entry);
3240 entry=SetMagickInfo("SVGZ");
3241 #if defined(MAGICKCORE_XML_DELEGATE)
3242 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3244 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3245 entry->blob_support=MagickFalse;
3246 entry->seekable_stream=MagickFalse;
3247 entry->description=ConstantString("Compressed Scalable Vector Graphics");
3248 if (*version != '\0')
3249 entry->version=ConstantString(version);
3250 entry->magick=(IsImageFormatHandler *) IsSVG;
3251 entry->module=ConstantString("SVG");
3252 (void) RegisterMagickInfo(entry);
3253 entry=SetMagickInfo("MSVG");
3254 #if defined(MAGICKCORE_XML_DELEGATE)
3255 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3257 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3258 entry->blob_support=MagickFalse;
3259 entry->seekable_stream=MagickFalse;
3260 entry->description=ConstantString("ImageMagick's own SVG internal renderer");
3261 entry->magick=(IsImageFormatHandler *) IsSVG;
3262 entry->module=ConstantString("SVG");
3263 (void) RegisterMagickInfo(entry);
3264 return(MagickImageCoderSignature);
3268 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3272 % U n r e g i s t e r S V G I m a g e %
3276 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3278 % UnregisterSVGImage() removes format registrations made by the
3279 % SVG module from the list of supported formats.
3281 % The format of the UnregisterSVGImage method is:
3283 % UnregisterSVGImage(void)
3286 ModuleExport void UnregisterSVGImage(void)
3288 (void) UnregisterMagickInfo("SVGZ");
3289 (void) UnregisterMagickInfo("SVG");
3290 (void) UnregisterMagickInfo("MSVG");
3294 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3298 % W r i t e S V G I m a g e %
3302 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3304 % WriteSVGImage() writes a image in the SVG - XML based W3C standard
3307 % The format of the WriteSVGImage method is:
3309 % MagickBooleanType WriteSVGImage(const ImageInfo *image_info,
3310 % Image *image,ExceptionInfo *exception)
3312 % A description of each parameter follows.
3314 % o image_info: the image info.
3316 % o image: The image.
3318 % o exception: return any errors or warnings in this structure.
3322 static void AffineToTransform(Image *image,AffineMatrix *affine)
3325 transform[MaxTextExtent];
3327 if ((fabs(affine->tx) < MagickEpsilon) && (fabs(affine->ty) < MagickEpsilon))
3329 if ((fabs(affine->rx) < MagickEpsilon) &&
3330 (fabs(affine->ry) < MagickEpsilon))
3332 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3333 (fabs(affine->sy-1.0) < MagickEpsilon))
3335 (void) WriteBlobString(image,"\">\n");
3338 (void) FormatLocaleString(transform,MaxTextExtent,
3339 "\" transform=\"scale(%g,%g)\">\n",affine->sx,affine->sy);
3340 (void) WriteBlobString(image,transform);
3345 if ((fabs(affine->sx-affine->sy) < MagickEpsilon) &&
3346 (fabs(affine->rx+affine->ry) < MagickEpsilon) &&
3347 (fabs(affine->sx*affine->sx+affine->rx*affine->rx-1.0) <
3353 theta=(180.0/MagickPI)*atan2(affine->rx,affine->sx);
3354 (void) FormatLocaleString(transform,MaxTextExtent,
3355 "\" transform=\"rotate(%g)\">\n",theta);
3356 (void) WriteBlobString(image,transform);
3363 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3364 (fabs(affine->rx) < MagickEpsilon) &&
3365 (fabs(affine->ry) < MagickEpsilon) &&
3366 (fabs(affine->sy-1.0) < MagickEpsilon))
3368 (void) FormatLocaleString(transform,MaxTextExtent,
3369 "\" transform=\"translate(%g,%g)\">\n",affine->tx,affine->ty);
3370 (void) WriteBlobString(image,transform);
3374 (void) FormatLocaleString(transform,MaxTextExtent,
3375 "\" transform=\"matrix(%g %g %g %g %g %g)\">\n",
3376 affine->sx,affine->rx,affine->ry,affine->sy,affine->tx,affine->ty);
3377 (void) WriteBlobString(image,transform);
3380 static MagickBooleanType IsPoint(const char *point)
3388 value=strtol(point,&p,10);
3390 return(p != point ? MagickTrue : MagickFalse);
3393 static MagickBooleanType TraceSVGImage(Image *image,ExceptionInfo *exception)
3398 register const Quantum
3404 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
3409 at_fitting_opts_type
3428 Trace image and write as SVG.
3430 fitting_options=at_fitting_opts_new();
3431 output_options=at_output_opts_new();
3432 type=GetImageType(image,exception);
3434 if ((type == BilevelType) || (type == GrayscaleType))
3436 trace=at_bitmap_new(image->columns,image->rows,number_planes);
3438 for (y=0; y < (ssize_t) image->rows; y++)
3440 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3441 if (p == (const Quantum *) NULL)
3443 for (x=0; x < (ssize_t) image->columns; x++)
3445 trace->bitmap[i++]=GetPixelRed(image,p);
3446 if (number_planes == 3)
3448 trace->bitmap[i++]=GetPixelGreen(image,p);
3449 trace->bitmap[i++]=GetPixelBlue(image,p);
3451 p+=GetPixelChannels(image);
3454 splines=at_splines_new_full(trace,fitting_options,NULL,NULL,NULL,NULL,NULL,
3456 at_splines_write(at_output_get_handler_by_suffix((char *) "svg"),
3457 GetBlobFileHandle(image),image->filename,output_options,splines,NULL,
3462 at_splines_free(splines);
3463 at_bitmap_free(trace);
3464 at_output_opts_free(output_options);
3465 at_fitting_opts_free(fitting_options);
3470 message[MaxTextExtent],
3471 tuple[MaxTextExtent];
3476 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3477 (void) WriteBlobString(image,
3478 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3479 (void) WriteBlobString(image,
3480 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3481 (void) FormatLocaleString(message,MaxTextExtent,
3482 "<svg width=\"%.20g\" height=\"%.20g\">\n",(double) image->columns,
3483 (double) image->rows);
3484 (void) WriteBlobString(image,message);
3485 GetPixelInfo(image,&pixel);
3486 for (y=0; y < (ssize_t) image->rows; y++)
3488 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3489 if (p == (const Quantum *) NULL)
3491 for (x=0; x < (ssize_t) image->columns; x++)
3493 GetPixelInfoPixel(image,p,&pixel);
3494 (void) QueryColorname(image,&pixel,SVGCompliance,tuple,exception);
3495 (void) FormatLocaleString(message,MaxTextExtent,
3496 " <circle cx=\"%.20g\" cy=\"%.20g\" r=\"1\" fill=\"%s\"/>\n",
3497 (double) x,(double) y,tuple);
3498 (void) WriteBlobString(image,message);
3499 p+=GetPixelChannels(image);
3502 (void) WriteBlobString(image,"</svg>\n");
3508 static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
3509 ExceptionInfo *exception)
3511 #define BezierQuantum 200
3517 keyword[MaxTextExtent],
3518 message[MaxTextExtent],
3519 name[MaxTextExtent],
3521 type[MaxTextExtent];
3563 Open output image file.
3565 assert(image_info != (const ImageInfo *) NULL);
3566 assert(image_info->signature == MagickSignature);
3567 assert(image != (Image *) NULL);
3568 assert(image->signature == MagickSignature);
3569 if (image->debug != MagickFalse)
3570 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3571 assert(exception != (ExceptionInfo *) NULL);
3572 assert(exception->signature == MagickSignature);
3573 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
3574 if (status == MagickFalse)
3576 value=GetImageArtifact(image,"SVG");
3577 if (value != (char *) NULL)
3579 (void) WriteBlobString(image,value);
3580 (void) CloseBlob(image);
3583 value=GetImageArtifact(image,"MVG");
3584 if (value == (char *) NULL)
3585 return(TraceSVGImage(image,exception));
3589 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3590 (void) WriteBlobString(image,
3591 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3592 (void) WriteBlobString(image,
3593 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3594 (void) FormatLocaleString(message,MaxTextExtent,
3595 "<svg width=\"%.20g\" height=\"%.20g\">\n",(double) image->columns,(double)
3597 (void) WriteBlobString(image,message);
3599 Allocate primitive info memory.
3602 primitive_info=(PrimitiveInfo *) AcquireQuantumMemory(number_points,
3603 sizeof(*primitive_info));
3604 if (primitive_info == (PrimitiveInfo *) NULL)
3605 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3606 GetAffineMatrix(&affine);
3607 token=AcquireString(value);
3611 for (q=(const char *) value; *q != '\0'; )
3614 Interpret graphic primitive.
3616 GetMagickToken(q,&q,keyword);
3617 if (*keyword == '\0')
3619 if (*keyword == '#')
3624 if (active != MagickFalse)
3626 AffineToTransform(image,&affine);
3629 (void) WriteBlobString(image,"<desc>");
3630 (void) WriteBlobString(image,keyword+1);
3631 for ( ; (*q != '\n') && (*q != '\0'); q++)
3634 case '<': (void) WriteBlobString(image,"<"); break;
3635 case '>': (void) WriteBlobString(image,">"); break;
3636 case '&': (void) WriteBlobString(image,"&"); break;
3637 default: (void) WriteBlobByte(image,*q); break;
3639 (void) WriteBlobString(image,"</desc>\n");
3642 primitive_type=UndefinedPrimitive;
3650 if (LocaleCompare("affine",keyword) == 0)
3652 GetMagickToken(q,&q,token);
3653 affine.sx=StringToDouble(token,(char **) NULL);
3654 GetMagickToken(q,&q,token);
3656 GetMagickToken(q,&q,token);
3657 affine.rx=StringToDouble(token,(char **) NULL);
3658 GetMagickToken(q,&q,token);
3660 GetMagickToken(q,&q,token);
3661 affine.ry=StringToDouble(token,(char **) NULL);
3662 GetMagickToken(q,&q,token);
3664 GetMagickToken(q,&q,token);
3665 affine.sy=StringToDouble(token,(char **) NULL);
3666 GetMagickToken(q,&q,token);
3668 GetMagickToken(q,&q,token);
3669 affine.tx=StringToDouble(token,(char **) NULL);
3670 GetMagickToken(q,&q,token);
3672 GetMagickToken(q,&q,token);
3673 affine.ty=StringToDouble(token,(char **) NULL);
3676 if (LocaleCompare("angle",keyword) == 0)
3678 GetMagickToken(q,&q,token);
3679 affine.rx=StringToDouble(token,(char **) NULL);
3680 affine.ry=StringToDouble(token,(char **) NULL);
3683 if (LocaleCompare("arc",keyword) == 0)
3685 primitive_type=ArcPrimitive;
3694 if (LocaleCompare("bezier",keyword) == 0)
3696 primitive_type=BezierPrimitive;
3705 if (LocaleCompare("clip-path",keyword) == 0)
3707 GetMagickToken(q,&q,token);
3708 (void) FormatLocaleString(message,MaxTextExtent,
3709 "clip-path:url(#%s);",token);
3710 (void) WriteBlobString(image,message);
3713 if (LocaleCompare("clip-rule",keyword) == 0)
3715 GetMagickToken(q,&q,token);
3716 (void) FormatLocaleString(message,MaxTextExtent,
3717 "clip-rule:%s;",token);
3718 (void) WriteBlobString(image,message);
3721 if (LocaleCompare("clip-units",keyword) == 0)
3723 GetMagickToken(q,&q,token);
3724 (void) FormatLocaleString(message,MaxTextExtent,
3725 "clipPathUnits=%s;",token);
3726 (void) WriteBlobString(image,message);
3729 if (LocaleCompare("circle",keyword) == 0)
3731 primitive_type=CirclePrimitive;
3734 if (LocaleCompare("color",keyword) == 0)
3736 primitive_type=ColorPrimitive;
3745 if (LocaleCompare("decorate",keyword) == 0)
3747 GetMagickToken(q,&q,token);
3748 (void) FormatLocaleString(message,MaxTextExtent,
3749 "text-decoration:%s;",token);
3750 (void) WriteBlobString(image,message);
3759 if (LocaleCompare("ellipse",keyword) == 0)
3761 primitive_type=EllipsePrimitive;
3770 if (LocaleCompare("fill",keyword) == 0)
3772 GetMagickToken(q,&q,token);
3773 (void) FormatLocaleString(message,MaxTextExtent,"fill:%s;",
3775 (void) WriteBlobString(image,message);
3778 if (LocaleCompare("fill-rule",keyword) == 0)
3780 GetMagickToken(q,&q,token);
3781 (void) FormatLocaleString(message,MaxTextExtent,
3782 "fill-rule:%s;",token);
3783 (void) WriteBlobString(image,message);
3786 if (LocaleCompare("fill-alpha",keyword) == 0)
3788 GetMagickToken(q,&q,token);
3789 (void) FormatLocaleString(message,MaxTextExtent,
3790 "fill-alpha:%s;",token);
3791 (void) WriteBlobString(image,message);
3794 if (LocaleCompare("font-family",keyword) == 0)
3796 GetMagickToken(q,&q,token);
3797 (void) FormatLocaleString(message,MaxTextExtent,
3798 "font-family:%s;",token);
3799 (void) WriteBlobString(image,message);
3802 if (LocaleCompare("font-stretch",keyword) == 0)
3804 GetMagickToken(q,&q,token);
3805 (void) FormatLocaleString(message,MaxTextExtent,
3806 "font-stretch:%s;",token);
3807 (void) WriteBlobString(image,message);
3810 if (LocaleCompare("font-style",keyword) == 0)
3812 GetMagickToken(q,&q,token);
3813 (void) FormatLocaleString(message,MaxTextExtent,
3814 "font-style:%s;",token);
3815 (void) WriteBlobString(image,message);
3818 if (LocaleCompare("font-size",keyword) == 0)
3820 GetMagickToken(q,&q,token);
3821 (void) FormatLocaleString(message,MaxTextExtent,
3822 "font-size:%s;",token);
3823 (void) WriteBlobString(image,message);
3826 if (LocaleCompare("font-weight",keyword) == 0)
3828 GetMagickToken(q,&q,token);
3829 (void) FormatLocaleString(message,MaxTextExtent,
3830 "font-weight:%s;",token);
3831 (void) WriteBlobString(image,message);
3840 if (LocaleCompare("gradient-units",keyword) == 0)
3842 GetMagickToken(q,&q,token);
3845 if (LocaleCompare("text-align",keyword) == 0)
3847 GetMagickToken(q,&q,token);
3848 (void) FormatLocaleString(message,MaxTextExtent,
3849 "text-align %s ",token);
3850 (void) WriteBlobString(image,message);
3853 if (LocaleCompare("text-anchor",keyword) == 0)
3855 GetMagickToken(q,&q,token);
3856 (void) FormatLocaleString(message,MaxTextExtent,
3857 "text-anchor %s ",token);
3858 (void) WriteBlobString(image,message);
3867 if (LocaleCompare("image",keyword) == 0)
3869 GetMagickToken(q,&q,token);
3870 primitive_type=ImagePrimitive;
3879 if (LocaleCompare("line",keyword) == 0)
3881 primitive_type=LinePrimitive;
3890 if (LocaleCompare("matte",keyword) == 0)
3892 primitive_type=MattePrimitive;
3901 if (LocaleCompare("opacity",keyword) == 0)
3903 GetMagickToken(q,&q,token);
3904 (void) FormatLocaleString(message,MaxTextExtent,"opacity %s ",
3906 (void) WriteBlobString(image,message);
3915 if (LocaleCompare("path",keyword) == 0)
3917 primitive_type=PathPrimitive;
3920 if (LocaleCompare("point",keyword) == 0)
3922 primitive_type=PointPrimitive;
3925 if (LocaleCompare("polyline",keyword) == 0)
3927 primitive_type=PolylinePrimitive;
3930 if (LocaleCompare("polygon",keyword) == 0)
3932 primitive_type=PolygonPrimitive;
3935 if (LocaleCompare("pop",keyword) == 0)
3937 GetMagickToken(q,&q,token);
3938 if (LocaleCompare("clip-path",token) == 0)
3940 (void) WriteBlobString(image,"</clipPath>\n");
3943 if (LocaleCompare("defs",token) == 0)
3945 (void) WriteBlobString(image,"</defs>\n");
3948 if (LocaleCompare("gradient",token) == 0)
3950 (void) FormatLocaleString(message,MaxTextExtent,
3951 "</%sGradient>\n",type);
3952 (void) WriteBlobString(image,message);
3955 if (LocaleCompare("graphic-context",token) == 0)
3959 ThrowWriterException(DrawError,
3960 "UnbalancedGraphicContextPushPop");
3961 (void) WriteBlobString(image,"</g>\n");
3963 if (LocaleCompare("pattern",token) == 0)
3965 (void) WriteBlobString(image,"</pattern>\n");
3968 if (LocaleCompare("defs",token) == 0)
3969 (void) WriteBlobString(image,"</g>\n");
3972 if (LocaleCompare("push",keyword) == 0)
3974 GetMagickToken(q,&q,token);
3975 if (LocaleCompare("clip-path",token) == 0)
3977 GetMagickToken(q,&q,token);
3978 (void) FormatLocaleString(message,MaxTextExtent,
3979 "<clipPath id=\"%s\">\n",token);
3980 (void) WriteBlobString(image,message);
3983 if (LocaleCompare("defs",token) == 0)
3985 (void) WriteBlobString(image,"<defs>\n");
3988 if (LocaleCompare("gradient",token) == 0)
3990 GetMagickToken(q,&q,token);
3991 (void) CopyMagickString(name,token,MaxTextExtent);
3992 GetMagickToken(q,&q,token);
3993 (void) CopyMagickString(type,token,MaxTextExtent);
3994 GetMagickToken(q,&q,token);
3995 svg_info.segment.x1=StringToDouble(token,(char **) NULL);
3996 svg_info.element.cx=StringToDouble(token,(char **) NULL);
3997 GetMagickToken(q,&q,token);
3999 GetMagickToken(q,&q,token);
4000 svg_info.segment.y1=StringToDouble(token,(char **) NULL);
4001 svg_info.element.cy=StringToDouble(token,(char **) NULL);
4002 GetMagickToken(q,&q,token);
4004 GetMagickToken(q,&q,token);
4005 svg_info.segment.x2=StringToDouble(token,(char **) NULL);
4006 svg_info.element.major=StringToDouble(token,
4008 GetMagickToken(q,&q,token);
4010 GetMagickToken(q,&q,token);
4011 svg_info.segment.y2=StringToDouble(token,(char **) NULL);
4012 svg_info.element.minor=StringToDouble(token,
4014 (void) FormatLocaleString(message,MaxTextExtent,
4015 "<%sGradient id=\"%s\" x1=\"%g\" y1=\"%g\" x2=\"%g\" "
4016 "y2=\"%g\">\n",type,name,svg_info.segment.x1,
4017 svg_info.segment.y1,svg_info.segment.x2,svg_info.segment.y2);
4018 if (LocaleCompare(type,"radial") == 0)
4020 GetMagickToken(q,&q,token);
4022 GetMagickToken(q,&q,token);
4023 svg_info.element.angle=StringToDouble(token,
4025 (void) FormatLocaleString(message,MaxTextExtent,
4026 "<%sGradient id=\"%s\" cx=\"%g\" cy=\"%g\" r=\"%g\" "
4027 "fx=\"%g\" fy=\"%g\">\n",type,name,
4028 svg_info.element.cx,svg_info.element.cy,
4029 svg_info.element.angle,svg_info.element.major,
4030 svg_info.element.minor);
4032 (void) WriteBlobString(image,message);
4035 if (LocaleCompare("graphic-context",token) == 0)
4040 AffineToTransform(image,&affine);
4043 (void) WriteBlobString(image,"<g style=\"");
4046 if (LocaleCompare("pattern",token) == 0)
4048 GetMagickToken(q,&q,token);
4049 (void) CopyMagickString(name,token,MaxTextExtent);
4050 GetMagickToken(q,&q,token);
4051 svg_info.bounds.x=StringToDouble(token,(char **) NULL);
4052 GetMagickToken(q,&q,token);
4054 GetMagickToken(q,&q,token);
4055 svg_info.bounds.y=StringToDouble(token,(char **) NULL);
4056 GetMagickToken(q,&q,token);
4058 GetMagickToken(q,&q,token);
4059 svg_info.bounds.width=StringToDouble(token,
4061 GetMagickToken(q,&q,token);
4063 GetMagickToken(q,&q,token);
4064 svg_info.bounds.height=StringToDouble(token,
4066 (void) FormatLocaleString(message,MaxTextExtent,
4067 "<pattern id=\"%s\" x=\"%g\" y=\"%g\" width=\"%g\" "
4068 "height=\"%g\">\n",name,svg_info.bounds.x,
4069 svg_info.bounds.y,svg_info.bounds.width,
4070 svg_info.bounds.height);
4071 (void) WriteBlobString(image,message);
4082 if (LocaleCompare("rectangle",keyword) == 0)
4084 primitive_type=RectanglePrimitive;
4087 if (LocaleCompare("roundRectangle",keyword) == 0)
4089 primitive_type=RoundRectanglePrimitive;
4092 if (LocaleCompare("rotate",keyword) == 0)
4094 GetMagickToken(q,&q,token);
4095 (void) FormatLocaleString(message,MaxTextExtent,"rotate(%s) ",
4097 (void) WriteBlobString(image,message);
4106 if (LocaleCompare("scale",keyword) == 0)
4108 GetMagickToken(q,&q,token);
4109 affine.sx=StringToDouble(token,(char **) NULL);
4110 GetMagickToken(q,&q,token);
4112 GetMagickToken(q,&q,token);
4113 affine.sy=StringToDouble(token,(char **) NULL);
4116 if (LocaleCompare("skewX",keyword) == 0)
4118 GetMagickToken(q,&q,token);
4119 (void) FormatLocaleString(message,MaxTextExtent,"skewX(%s) ",
4121 (void) WriteBlobString(image,message);
4124 if (LocaleCompare("skewY",keyword) == 0)
4126 GetMagickToken(q,&q,token);
4127 (void) FormatLocaleString(message,MaxTextExtent,"skewY(%s) ",
4129 (void) WriteBlobString(image,message);
4132 if (LocaleCompare("stop-color",keyword) == 0)
4135 color[MaxTextExtent];
4137 GetMagickToken(q,&q,token);
4138 (void) CopyMagickString(color,token,MaxTextExtent);
4139 GetMagickToken(q,&q,token);
4140 (void) FormatLocaleString(message,MaxTextExtent,
4141 " <stop offset=\"%s\" stop-color=\"%s\" />\n",token,color);
4142 (void) WriteBlobString(image,message);
4145 if (LocaleCompare("stroke",keyword) == 0)
4147 GetMagickToken(q,&q,token);
4148 (void) FormatLocaleString(message,MaxTextExtent,"stroke:%s;",
4150 (void) WriteBlobString(image,message);
4153 if (LocaleCompare("stroke-antialias",keyword) == 0)
4155 GetMagickToken(q,&q,token);
4156 (void) FormatLocaleString(message,MaxTextExtent,
4157 "stroke-antialias:%s;",token);
4158 (void) WriteBlobString(image,message);
4161 if (LocaleCompare("stroke-dasharray",keyword) == 0)
4169 GetMagickToken(p,&p,token);
4170 for (k=0; IsPoint(token); k++)
4171 GetMagickToken(p,&p,token);
4172 (void) WriteBlobString(image,"stroke-dasharray:");
4173 for (j=0; j < k; j++)
4175 GetMagickToken(q,&q,token);
4176 (void) FormatLocaleString(message,MaxTextExtent,"%s ",
4178 (void) WriteBlobString(image,message);
4180 (void) WriteBlobString(image,";");
4183 GetMagickToken(q,&q,token);
4184 (void) FormatLocaleString(message,MaxTextExtent,
4185 "stroke-dasharray:%s;",token);
4186 (void) WriteBlobString(image,message);
4189 if (LocaleCompare("stroke-dashoffset",keyword) == 0)
4191 GetMagickToken(q,&q,token);
4192 (void) FormatLocaleString(message,MaxTextExtent,
4193 "stroke-dashoffset:%s;",token);
4194 (void) WriteBlobString(image,message);
4197 if (LocaleCompare("stroke-linecap",keyword) == 0)
4199 GetMagickToken(q,&q,token);
4200 (void) FormatLocaleString(message,MaxTextExtent,
4201 "stroke-linecap:%s;",token);
4202 (void) WriteBlobString(image,message);
4205 if (LocaleCompare("stroke-linejoin",keyword) == 0)
4207 GetMagickToken(q,&q,token);
4208 (void) FormatLocaleString(message,MaxTextExtent,
4209 "stroke-linejoin:%s;",token);
4210 (void) WriteBlobString(image,message);
4213 if (LocaleCompare("stroke-miterlimit",keyword) == 0)
4215 GetMagickToken(q,&q,token);
4216 (void) FormatLocaleString(message,MaxTextExtent,
4217 "stroke-miterlimit:%s;",token);
4218 (void) WriteBlobString(image,message);
4221 if (LocaleCompare("stroke-opacity",keyword) == 0)
4223 GetMagickToken(q,&q,token);
4224 (void) FormatLocaleString(message,MaxTextExtent,
4225 "stroke-opacity:%s;",token);
4226 (void) WriteBlobString(image,message);
4229 if (LocaleCompare("stroke-width",keyword) == 0)
4231 GetMagickToken(q,&q,token);
4232 (void) FormatLocaleString(message,MaxTextExtent,
4233 "stroke-width:%s;",token);
4234 (void) WriteBlobString(image,message);
4243 if (LocaleCompare("text",keyword) == 0)
4245 primitive_type=TextPrimitive;
4248 if (LocaleCompare("text-antialias",keyword) == 0)
4250 GetMagickToken(q,&q,token);
4251 (void) FormatLocaleString(message,MaxTextExtent,
4252 "text-antialias:%s;",token);
4253 (void) WriteBlobString(image,message);
4256 if (LocaleCompare("tspan",keyword) == 0)
4258 primitive_type=TextPrimitive;
4261 if (LocaleCompare("translate",keyword) == 0)
4263 GetMagickToken(q,&q,token);
4264 affine.tx=StringToDouble(token,(char **) NULL);
4265 GetMagickToken(q,&q,token);
4267 GetMagickToken(q,&q,token);
4268 affine.ty=StringToDouble(token,(char **) NULL);
4277 if (LocaleCompare("viewbox",keyword) == 0)
4279 GetMagickToken(q,&q,token);
4281 GetMagickToken(q,&q,token);
4282 GetMagickToken(q,&q,token);
4284 GetMagickToken(q,&q,token);
4285 GetMagickToken(q,&q,token);
4287 GetMagickToken(q,&q,token);
4288 GetMagickToken(q,&q,token);
4300 if (status == MagickFalse)
4302 if (primitive_type == UndefinedPrimitive)
4305 Parse the primitive attributes.
4309 for (x=0; *q != '\0'; x++)
4314 if (IsPoint(q) == MagickFalse)
4316 GetMagickToken(q,&q,token);
4317 point.x=StringToDouble(token,(char **) NULL);
4318 GetMagickToken(q,&q,token);
4320 GetMagickToken(q,&q,token);
4321 point.y=StringToDouble(token,(char **) NULL);
4322 GetMagickToken(q,(const char **) NULL,token);
4324 GetMagickToken(q,&q,token);
4325 primitive_info[i].primitive=primitive_type;
4326 primitive_info[i].point=point;
4327 primitive_info[i].coordinates=0;
4328 primitive_info[i].method=FloodfillMethod;
4330 if (i < (ssize_t) (number_points-6*BezierQuantum-360))
4332 number_points+=6*BezierQuantum+360;
4333 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4334 number_points,sizeof(*primitive_info));
4335 if (primitive_info == (PrimitiveInfo *) NULL)
4337 (void) ThrowMagickException(exception,GetMagickModule(),
4338 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
4342 primitive_info[j].primitive=primitive_type;
4343 primitive_info[j].coordinates=x;
4344 primitive_info[j].method=FloodfillMethod;
4345 primitive_info[j].text=(char *) NULL;
4348 AffineToTransform(image,&affine);
4352 switch (primitive_type)
4354 case PointPrimitive:
4357 if (primitive_info[j].coordinates != 1)
4366 if (primitive_info[j].coordinates != 2)
4371 (void) FormatLocaleString(message,MaxTextExtent,
4372 " <line x1=\"%g\" y1=\"%g\" x2=\"%g\" y2=\"%g\"/>\n",
4373 primitive_info[j].point.x,primitive_info[j].point.y,
4374 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4375 (void) WriteBlobString(image,message);
4378 case RectanglePrimitive:
4380 if (primitive_info[j].coordinates != 2)
4385 (void) FormatLocaleString(message,MaxTextExtent,
4386 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"/>\n",
4387 primitive_info[j].point.x,primitive_info[j].point.y,
4388 primitive_info[j+1].point.x-primitive_info[j].point.x,
4389 primitive_info[j+1].point.y-primitive_info[j].point.y);
4390 (void) WriteBlobString(image,message);
4393 case RoundRectanglePrimitive:
4395 if (primitive_info[j].coordinates != 3)
4400 (void) FormatLocaleString(message,MaxTextExtent,
4401 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" rx=\"%g\" "
4402 "ry=\"%g\"/>\n",primitive_info[j].point.x,
4403 primitive_info[j].point.y,primitive_info[j+1].point.x-
4404 primitive_info[j].point.x,primitive_info[j+1].point.y-
4405 primitive_info[j].point.y,primitive_info[j+2].point.x,
4406 primitive_info[j+2].point.y);
4407 (void) WriteBlobString(image,message);
4412 if (primitive_info[j].coordinates != 3)
4419 case EllipsePrimitive:
4421 if (primitive_info[j].coordinates != 3)
4426 (void) FormatLocaleString(message,MaxTextExtent,
4427 " <ellipse cx=\"%g\" cy=\"%g\" rx=\"%g\" ry=\"%g\"/>\n",
4428 primitive_info[j].point.x,primitive_info[j].point.y,
4429 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4430 (void) WriteBlobString(image,message);
4433 case CirclePrimitive:
4439 if (primitive_info[j].coordinates != 2)
4444 alpha=primitive_info[j+1].point.x-primitive_info[j].point.x;
4445 beta=primitive_info[j+1].point.y-primitive_info[j].point.y;
4446 (void) FormatLocaleString(message,MaxTextExtent,
4447 " <circle cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
4448 primitive_info[j].point.x,primitive_info[j].point.y,
4450 (void) WriteBlobString(image,message);
4453 case PolylinePrimitive:
4455 if (primitive_info[j].coordinates < 2)
4460 (void) CopyMagickString(message," <polyline points=\"",MaxTextExtent);
4461 (void) WriteBlobString(image,message);
4462 length=strlen(message);
4465 (void) FormatLocaleString(message,MaxTextExtent,"%g,%g ",
4466 primitive_info[j].point.x,primitive_info[j].point.y);
4467 length+=strlen(message);
4470 (void) WriteBlobString(image,"\n ");
4471 length=strlen(message)+5;
4473 (void) WriteBlobString(image,message);
4475 (void) WriteBlobString(image,"\"/>\n");
4478 case PolygonPrimitive:
4480 if (primitive_info[j].coordinates < 3)
4485 primitive_info[i]=primitive_info[j];
4486 primitive_info[i].coordinates=0;
4487 primitive_info[j].coordinates++;
4489 (void) CopyMagickString(message," <polygon points=\"",MaxTextExtent);
4490 (void) WriteBlobString(image,message);
4491 length=strlen(message);
4494 (void) FormatLocaleString(message,MaxTextExtent,"%g,%g ",
4495 primitive_info[j].point.x,primitive_info[j].point.y);
4496 length+=strlen(message);
4499 (void) WriteBlobString(image,"\n ");
4500 length=strlen(message)+5;
4502 (void) WriteBlobString(image,message);
4504 (void) WriteBlobString(image,"\"/>\n");
4507 case BezierPrimitive:
4509 if (primitive_info[j].coordinates < 3)
4521 GetMagickToken(q,&q,token);
4522 number_attributes=1;
4523 for (p=token; *p != '\0'; p++)
4524 if (isalpha((int) *p))
4525 number_attributes++;
4526 if (i > (ssize_t) (number_points-6*BezierQuantum*number_attributes-1))
4528 number_points+=6*BezierQuantum*number_attributes;
4529 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4530 number_points,sizeof(*primitive_info));
4531 if (primitive_info == (PrimitiveInfo *) NULL)
4533 (void) ThrowMagickException(exception,GetMagickModule(),
4534 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4539 (void) WriteBlobString(image," <path d=\"");
4540 (void) WriteBlobString(image,token);
4541 (void) WriteBlobString(image,"\"/>\n");
4544 case ColorPrimitive:
4545 case MattePrimitive:
4547 if (primitive_info[j].coordinates != 1)
4552 GetMagickToken(q,&q,token);
4553 if (LocaleCompare("point",token) == 0)
4554 primitive_info[j].method=PointMethod;
4555 if (LocaleCompare("replace",token) == 0)
4556 primitive_info[j].method=ReplaceMethod;
4557 if (LocaleCompare("floodfill",token) == 0)
4558 primitive_info[j].method=FloodfillMethod;
4559 if (LocaleCompare("filltoborder",token) == 0)
4560 primitive_info[j].method=FillToBorderMethod;
4561 if (LocaleCompare("reset",token) == 0)
4562 primitive_info[j].method=ResetMethod;
4570 if (primitive_info[j].coordinates != 1)
4575 GetMagickToken(q,&q,token);
4576 (void) FormatLocaleString(message,MaxTextExtent,
4577 " <text x=\"%g\" y=\"%g\">",primitive_info[j].point.x,
4578 primitive_info[j].point.y);
4579 (void) WriteBlobString(image,message);
4580 for (p=token; *p != '\0'; p++)
4583 case '<': (void) WriteBlobString(image,"<"); break;
4584 case '>': (void) WriteBlobString(image,">"); break;
4585 case '&': (void) WriteBlobString(image,"&"); break;
4586 default: (void) WriteBlobByte(image,*p); break;
4588 (void) WriteBlobString(image,"</text>\n");
4591 case ImagePrimitive:
4593 if (primitive_info[j].coordinates != 2)
4598 GetMagickToken(q,&q,token);
4599 (void) FormatLocaleString(message,MaxTextExtent,
4600 " <image x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" "
4601 "xlink:href=\"%s\"/>\n",primitive_info[j].point.x,
4602 primitive_info[j].point.y,primitive_info[j+1].point.x,
4603 primitive_info[j+1].point.y,token);
4604 (void) WriteBlobString(image,message);
4608 if (primitive_info == (PrimitiveInfo *) NULL)
4610 primitive_info[i].primitive=UndefinedPrimitive;
4611 if (status == MagickFalse)
4614 (void) WriteBlobString(image,"</svg>\n");
4616 Relinquish resources.
4618 token=DestroyString(token);
4619 if (primitive_info != (PrimitiveInfo *) NULL)
4620 primitive_info=(PrimitiveInfo *) RelinquishMagickMemory(primitive_info);
4621 (void) CloseBlob(image);