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)
2878 register unsigned char
2891 register const guchar
2914 svg_handle=rsvg_handle_new();
2915 if (svg_handle == (RsvgHandle *) NULL)
2916 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2917 rsvg_handle_set_base_uri(svg_handle,image_info->filename);
2918 rsvg_handle_set_dpi_x_y(svg_handle,image->resolution.x,
2919 image->resolution.y);
2920 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
2922 error=(GError *) NULL;
2923 (void) rsvg_handle_write(svg_handle,message,n,&error);
2924 if (error != (GError *) NULL)
2925 g_error_free(error);
2927 error=(GError *) NULL;
2928 rsvg_handle_close(svg_handle,&error);
2929 if (error != (GError *) NULL)
2930 g_error_free(error);
2931 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2932 rsvg_handle_get_dimensions(svg_handle,&dimension_info);
2933 image->columns=image->resolution.x*dimension_info.width/72.0;
2934 image->rows=image->resolution.y*dimension_info.height/72.0;
2935 pixels=(unsigned char *) NULL;
2937 pixel_info=rsvg_handle_get_pixbuf(svg_handle);
2938 rsvg_handle_free(svg_handle);
2939 image->columns=gdk_pixbuf_get_width(pixel_info);
2940 image->rows=gdk_pixbuf_get_height(pixel_info);
2942 image->alpha_trait=BlendPixelTrait;
2943 SetImageProperty(image,"svg:base-uri",
2944 rsvg_handle_get_base_uri(svg_handle),exception);
2945 if ((image->columns == 0) || (image->rows == 0))
2947 #if !defined(MAGICKCORE_CAIRO_DELEGATE)
2948 g_object_unref(G_OBJECT(pixel_info));
2950 g_object_unref(svg_handle);
2951 ThrowReaderException(MissingDelegateError,
2952 "NoDecodeDelegateForThisImageFormat");
2954 if (image_info->ping == MagickFalse)
2959 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2960 stride=4*image->columns;
2961 #if defined(MAGICKCORE_PANGOCAIRO_DELEGATE)
2962 stride=(size_t) cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32,
2965 pixels=(unsigned char *) AcquireQuantumMemory(stride,image->rows*
2967 if (pixels == (unsigned char *) NULL)
2969 g_object_unref(svg_handle);
2970 ThrowReaderException(ResourceLimitError,
2971 "MemoryAllocationFailed");
2974 (void) SetImageBackgroundColor(image,exception);
2975 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2976 cairo_surface=cairo_image_surface_create_for_data(pixels,
2977 CAIRO_FORMAT_ARGB32,image->columns,image->rows,stride);
2978 if (cairo_surface == (cairo_surface_t *) NULL)
2980 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2981 g_object_unref(svg_handle);
2982 ThrowReaderException(ResourceLimitError,
2983 "MemoryAllocationFailed");
2985 cairo_image=cairo_create(cairo_surface);
2986 cairo_set_operator(cairo_image,CAIRO_OPERATOR_CLEAR);
2987 cairo_paint(cairo_image);
2988 cairo_set_operator(cairo_image,CAIRO_OPERATOR_OVER);
2989 cairo_scale(cairo_image,image->resolution.x/72.0,
2990 image->resolution.y/72.0);
2991 rsvg_handle_render_cairo(svg_handle,cairo_image);
2992 cairo_destroy(cairo_image);
2993 cairo_surface_destroy(cairo_surface);
2994 g_object_unref(svg_handle);
2997 p=gdk_pixbuf_get_pixels(pixel_info);
2999 GetPixelInfo(image,&fill_color);
3000 for (y=0; y < (ssize_t) image->rows; y++)
3002 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3003 if (q == (Quantum *) NULL)
3005 for (x=0; x < (ssize_t) image->columns; x++)
3007 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3008 fill_color.blue=ScaleCharToQuantum(*p++);
3009 fill_color.green=ScaleCharToQuantum(*p++);
3010 fill_color.red=ScaleCharToQuantum(*p++);
3012 fill_color.red=ScaleCharToQuantum(*p++);
3013 fill_color.green=ScaleCharToQuantum(*p++);
3014 fill_color.blue=ScaleCharToQuantum(*p++);
3016 fill_color.alpha=ScaleCharToQuantum(*p++);
3017 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3022 gamma=QuantumScale*fill_color.alpha;
3023 gamma=PerceptibleReciprocal(gamma);
3024 fill_color.blue*=gamma;
3025 fill_color.green*=gamma;
3026 fill_color.red*=gamma;
3029 CompositePixelOver(image,&fill_color,fill_color.alpha,q,(double)
3030 GetPixelAlpha(image,q),q);
3031 q+=GetPixelChannels(image);
3033 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3035 if (image->previous == (Image *) NULL)
3037 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
3039 if (status == MagickFalse)
3044 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3045 if (pixels != (unsigned char *) NULL)
3046 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
3048 g_object_unref(G_OBJECT(pixel_info));
3050 (void) CloseBlob(image);
3051 return(GetFirstImageInList(image));
3059 unique_file=AcquireUniqueFileResource(filename);
3060 if (unique_file != -1)
3061 file=fdopen(unique_file,"w");
3062 if ((unique_file == -1) || (file == (FILE *) NULL))
3064 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
3065 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
3067 image=DestroyImageList(image);
3068 return((Image *) NULL);
3073 svg_info=AcquireSVGInfo();
3074 if (svg_info == (SVGInfo *) NULL)
3075 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3076 svg_info->file=file;
3077 svg_info->exception=exception;
3078 svg_info->image=image;
3079 svg_info->image_info=image_info;
3080 svg_info->bounds.width=image->columns;
3081 svg_info->bounds.height=image->rows;
3082 if (image_info->size != (char *) NULL)
3083 (void) CloneString(&svg_info->size,image_info->size);
3084 if (image->debug != MagickFalse)
3085 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"begin SAX");
3087 (void) xmlSubstituteEntitiesDefault(1);
3088 (void) ResetMagickMemory(&sax_modules,0,sizeof(sax_modules));
3089 sax_modules.internalSubset=SVGInternalSubset;
3090 sax_modules.isStandalone=SVGIsStandalone;
3091 sax_modules.hasInternalSubset=SVGHasInternalSubset;
3092 sax_modules.hasExternalSubset=SVGHasExternalSubset;
3093 sax_modules.resolveEntity=SVGResolveEntity;
3094 sax_modules.getEntity=SVGGetEntity;
3095 sax_modules.entityDecl=SVGEntityDeclaration;
3096 sax_modules.notationDecl=SVGNotationDeclaration;
3097 sax_modules.attributeDecl=SVGAttributeDeclaration;
3098 sax_modules.elementDecl=SVGElementDeclaration;
3099 sax_modules.unparsedEntityDecl=SVGUnparsedEntityDeclaration;
3100 sax_modules.setDocumentLocator=SVGSetDocumentLocator;
3101 sax_modules.startDocument=SVGStartDocument;
3102 sax_modules.endDocument=SVGEndDocument;
3103 sax_modules.startElement=SVGStartElement;
3104 sax_modules.endElement=SVGEndElement;
3105 sax_modules.reference=SVGReference;
3106 sax_modules.characters=SVGCharacters;
3107 sax_modules.ignorableWhitespace=SVGIgnorableWhitespace;
3108 sax_modules.processingInstruction=SVGProcessingInstructions;
3109 sax_modules.comment=SVGComment;
3110 sax_modules.warning=SVGWarning;
3111 sax_modules.error=SVGError;
3112 sax_modules.fatalError=SVGError;
3113 sax_modules.getParameterEntity=SVGGetParameterEntity;
3114 sax_modules.cdataBlock=SVGCDataBlock;
3115 sax_modules.externalSubset=SVGExternalSubset;
3116 sax_handler=(&sax_modules);
3117 n=ReadBlob(image,MaxTextExtent,message);
3120 svg_info->parser=xmlCreatePushParserCtxt(sax_handler,svg_info,(char *)
3121 message,n,image->filename);
3122 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
3124 status=xmlParseChunk(svg_info->parser,(char *) message,(int) n,0);
3129 (void) xmlParseChunk(svg_info->parser,(char *) message,0,1);
3130 xmlFreeParserCtxt(svg_info->parser);
3131 if (image->debug != MagickFalse)
3132 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"end SAX");
3134 (void) fclose(file);
3135 (void) CloseBlob(image);
3136 image->columns=svg_info->width;
3137 image->rows=svg_info->height;
3138 if (exception->severity >= ErrorException)
3140 image=DestroyImage(image);
3141 return((Image *) NULL);
3143 if (image_info->ping == MagickFalse)
3151 image=DestroyImage(image);
3152 image=(Image *) NULL;
3153 read_info=CloneImageInfo(image_info);
3154 SetImageInfoBlob(read_info,(void *) NULL,0);
3155 if (read_info->density != (char *) NULL)
3156 read_info->density=DestroyString(read_info->density);
3157 (void) FormatLocaleString(read_info->filename,MaxTextExtent,"mvg:%s",
3159 image=ReadImage(read_info,exception);
3160 read_info=DestroyImageInfo(read_info);
3161 if (image != (Image *) NULL)
3162 (void) CopyMagickString(image->filename,image_info->filename,
3166 Relinquish resources.
3168 if (image != (Image *) NULL)
3170 if (svg_info->title != (char *) NULL)
3171 (void) SetImageProperty(image,"svg:title",svg_info->title,exception);
3172 if (svg_info->comment != (char *) NULL)
3173 (void) SetImageProperty(image,"svg:comment",svg_info->comment,
3176 svg_info=DestroySVGInfo(svg_info);
3177 (void) RelinquishUniqueFileResource(filename);
3178 return(GetFirstImageInList(image));
3183 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3187 % R e g i s t e r S V G I m a g e %
3191 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3193 % RegisterSVGImage() adds attributes for the SVG image format to
3194 % the list of supported formats. The attributes include the image format
3195 % tag, a method to read and/or write the format, whether the format
3196 % supports the saving of more than one frame to the same file or blob,
3197 % whether the format supports native in-memory I/O, and a brief
3198 % description of the format.
3200 % The format of the RegisterSVGImage method is:
3202 % size_t RegisterSVGImage(void)
3205 ModuleExport size_t RegisterSVGImage(void)
3208 version[MaxTextExtent];
3214 #if defined(LIBXML_DOTTED_VERSION)
3215 (void) CopyMagickString(version,"XML " LIBXML_DOTTED_VERSION,MaxTextExtent);
3217 #if defined(MAGICKCORE_RSVG_DELEGATE)
3218 (void) FormatLocaleString(version,MaxTextExtent,"RSVG %d.%d.%d",
3219 LIBRSVG_MAJOR_VERSION,LIBRSVG_MINOR_VERSION,LIBRSVG_MICRO_VERSION);
3221 entry=SetMagickInfo("SVG");
3222 #if defined(MAGICKCORE_XML_DELEGATE)
3223 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3225 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3226 entry->blob_support=MagickFalse;
3227 entry->seekable_stream=MagickFalse;
3228 entry->description=ConstantString("Scalable Vector Graphics");
3229 if (*version != '\0')
3230 entry->version=ConstantString(version);
3231 entry->magick=(IsImageFormatHandler *) IsSVG;
3232 entry->module=ConstantString("SVG");
3233 (void) RegisterMagickInfo(entry);
3234 entry=SetMagickInfo("SVGZ");
3235 #if defined(MAGICKCORE_XML_DELEGATE)
3236 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3238 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3239 entry->blob_support=MagickFalse;
3240 entry->seekable_stream=MagickFalse;
3241 entry->description=ConstantString("Compressed Scalable Vector Graphics");
3242 if (*version != '\0')
3243 entry->version=ConstantString(version);
3244 entry->magick=(IsImageFormatHandler *) IsSVG;
3245 entry->module=ConstantString("SVG");
3246 (void) RegisterMagickInfo(entry);
3247 entry=SetMagickInfo("MSVG");
3248 #if defined(MAGICKCORE_XML_DELEGATE)
3249 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3251 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3252 entry->blob_support=MagickFalse;
3253 entry->seekable_stream=MagickFalse;
3254 entry->description=ConstantString("ImageMagick's own SVG internal renderer");
3255 entry->magick=(IsImageFormatHandler *) IsSVG;
3256 entry->module=ConstantString("SVG");
3257 (void) RegisterMagickInfo(entry);
3258 return(MagickImageCoderSignature);
3262 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3266 % U n r e g i s t e r S V G I m a g e %
3270 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3272 % UnregisterSVGImage() removes format registrations made by the
3273 % SVG module from the list of supported formats.
3275 % The format of the UnregisterSVGImage method is:
3277 % UnregisterSVGImage(void)
3280 ModuleExport void UnregisterSVGImage(void)
3282 (void) UnregisterMagickInfo("SVGZ");
3283 (void) UnregisterMagickInfo("SVG");
3284 (void) UnregisterMagickInfo("MSVG");
3288 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3292 % W r i t e S V G I m a g e %
3296 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3298 % WriteSVGImage() writes a image in the SVG - XML based W3C standard
3301 % The format of the WriteSVGImage method is:
3303 % MagickBooleanType WriteSVGImage(const ImageInfo *image_info,
3304 % Image *image,ExceptionInfo *exception)
3306 % A description of each parameter follows.
3308 % o image_info: the image info.
3310 % o image: The image.
3312 % o exception: return any errors or warnings in this structure.
3316 static void AffineToTransform(Image *image,AffineMatrix *affine)
3319 transform[MaxTextExtent];
3321 if ((fabs(affine->tx) < MagickEpsilon) && (fabs(affine->ty) < MagickEpsilon))
3323 if ((fabs(affine->rx) < MagickEpsilon) &&
3324 (fabs(affine->ry) < MagickEpsilon))
3326 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3327 (fabs(affine->sy-1.0) < MagickEpsilon))
3329 (void) WriteBlobString(image,"\">\n");
3332 (void) FormatLocaleString(transform,MaxTextExtent,
3333 "\" transform=\"scale(%g,%g)\">\n",affine->sx,affine->sy);
3334 (void) WriteBlobString(image,transform);
3339 if ((fabs(affine->sx-affine->sy) < MagickEpsilon) &&
3340 (fabs(affine->rx+affine->ry) < MagickEpsilon) &&
3341 (fabs(affine->sx*affine->sx+affine->rx*affine->rx-1.0) <
3347 theta=(180.0/MagickPI)*atan2(affine->rx,affine->sx);
3348 (void) FormatLocaleString(transform,MaxTextExtent,
3349 "\" transform=\"rotate(%g)\">\n",theta);
3350 (void) WriteBlobString(image,transform);
3357 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3358 (fabs(affine->rx) < MagickEpsilon) &&
3359 (fabs(affine->ry) < MagickEpsilon) &&
3360 (fabs(affine->sy-1.0) < MagickEpsilon))
3362 (void) FormatLocaleString(transform,MaxTextExtent,
3363 "\" transform=\"translate(%g,%g)\">\n",affine->tx,affine->ty);
3364 (void) WriteBlobString(image,transform);
3368 (void) FormatLocaleString(transform,MaxTextExtent,
3369 "\" transform=\"matrix(%g %g %g %g %g %g)\">\n",
3370 affine->sx,affine->rx,affine->ry,affine->sy,affine->tx,affine->ty);
3371 (void) WriteBlobString(image,transform);
3374 static MagickBooleanType IsPoint(const char *point)
3382 value=strtol(point,&p,10);
3384 return(p != point ? MagickTrue : MagickFalse);
3387 static MagickBooleanType TraceSVGImage(Image *image,ExceptionInfo *exception)
3392 register const Quantum
3398 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
3403 at_fitting_opts_type
3422 Trace image and write as SVG.
3424 fitting_options=at_fitting_opts_new();
3425 output_options=at_output_opts_new();
3426 type=GetImageType(image,exception);
3428 if ((type == BilevelType) || (type == GrayscaleType))
3430 trace=at_bitmap_new(image->columns,image->rows,number_planes);
3432 for (y=0; y < (ssize_t) image->rows; y++)
3434 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3435 if (p == (const Quantum *) NULL)
3437 for (x=0; x < (ssize_t) image->columns; x++)
3439 trace->bitmap[i++]=GetPixelRed(image,p);
3440 if (number_planes == 3)
3442 trace->bitmap[i++]=GetPixelGreen(image,p);
3443 trace->bitmap[i++]=GetPixelBlue(image,p);
3445 p+=GetPixelChannels(image);
3448 splines=at_splines_new_full(trace,fitting_options,NULL,NULL,NULL,NULL,NULL,
3450 at_splines_write(at_output_get_handler_by_suffix((char *) "svg"),
3451 GetBlobFileHandle(image),image->filename,output_options,splines,NULL,
3456 at_splines_free(splines);
3457 at_bitmap_free(trace);
3458 at_output_opts_free(output_options);
3459 at_fitting_opts_free(fitting_options);
3464 message[MaxTextExtent],
3465 tuple[MaxTextExtent];
3470 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3471 (void) WriteBlobString(image,
3472 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3473 (void) WriteBlobString(image,
3474 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3475 (void) FormatLocaleString(message,MaxTextExtent,
3476 "<svg width=\"%.20g\" height=\"%.20g\">\n",(double) image->columns,
3477 (double) image->rows);
3478 (void) WriteBlobString(image,message);
3479 GetPixelInfo(image,&pixel);
3480 for (y=0; y < (ssize_t) image->rows; y++)
3482 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3483 if (p == (const Quantum *) NULL)
3485 for (x=0; x < (ssize_t) image->columns; x++)
3487 GetPixelInfoPixel(image,p,&pixel);
3488 (void) QueryColorname(image,&pixel,SVGCompliance,tuple,exception);
3489 (void) FormatLocaleString(message,MaxTextExtent,
3490 " <circle cx=\"%.20g\" cy=\"%.20g\" r=\"1\" fill=\"%s\"/>\n",
3491 (double) x,(double) y,tuple);
3492 (void) WriteBlobString(image,message);
3493 p+=GetPixelChannels(image);
3496 (void) WriteBlobString(image,"</svg>\n");
3502 static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
3503 ExceptionInfo *exception)
3505 #define BezierQuantum 200
3511 keyword[MaxTextExtent],
3512 message[MaxTextExtent],
3513 name[MaxTextExtent],
3515 type[MaxTextExtent];
3557 Open output image file.
3559 assert(image_info != (const ImageInfo *) NULL);
3560 assert(image_info->signature == MagickSignature);
3561 assert(image != (Image *) NULL);
3562 assert(image->signature == MagickSignature);
3563 if (image->debug != MagickFalse)
3564 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3565 assert(exception != (ExceptionInfo *) NULL);
3566 assert(exception->signature == MagickSignature);
3567 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
3568 if (status == MagickFalse)
3570 value=GetImageArtifact(image,"SVG");
3571 if (value != (char *) NULL)
3573 (void) WriteBlobString(image,value);
3574 (void) CloseBlob(image);
3577 value=GetImageArtifact(image,"MVG");
3578 if (value == (char *) NULL)
3579 return(TraceSVGImage(image,exception));
3583 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3584 (void) WriteBlobString(image,
3585 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3586 (void) WriteBlobString(image,
3587 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3588 (void) FormatLocaleString(message,MaxTextExtent,
3589 "<svg width=\"%.20g\" height=\"%.20g\">\n",(double) image->columns,(double)
3591 (void) WriteBlobString(image,message);
3593 Allocate primitive info memory.
3596 primitive_info=(PrimitiveInfo *) AcquireQuantumMemory(number_points,
3597 sizeof(*primitive_info));
3598 if (primitive_info == (PrimitiveInfo *) NULL)
3599 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3600 GetAffineMatrix(&affine);
3601 token=AcquireString(value);
3605 for (q=(const char *) value; *q != '\0'; )
3608 Interpret graphic primitive.
3610 GetMagickToken(q,&q,keyword);
3611 if (*keyword == '\0')
3613 if (*keyword == '#')
3618 if (active != MagickFalse)
3620 AffineToTransform(image,&affine);
3623 (void) WriteBlobString(image,"<desc>");
3624 (void) WriteBlobString(image,keyword+1);
3625 for ( ; (*q != '\n') && (*q != '\0'); q++)
3628 case '<': (void) WriteBlobString(image,"<"); break;
3629 case '>': (void) WriteBlobString(image,">"); break;
3630 case '&': (void) WriteBlobString(image,"&"); break;
3631 default: (void) WriteBlobByte(image,*q); break;
3633 (void) WriteBlobString(image,"</desc>\n");
3636 primitive_type=UndefinedPrimitive;
3644 if (LocaleCompare("affine",keyword) == 0)
3646 GetMagickToken(q,&q,token);
3647 affine.sx=StringToDouble(token,(char **) NULL);
3648 GetMagickToken(q,&q,token);
3650 GetMagickToken(q,&q,token);
3651 affine.rx=StringToDouble(token,(char **) NULL);
3652 GetMagickToken(q,&q,token);
3654 GetMagickToken(q,&q,token);
3655 affine.ry=StringToDouble(token,(char **) NULL);
3656 GetMagickToken(q,&q,token);
3658 GetMagickToken(q,&q,token);
3659 affine.sy=StringToDouble(token,(char **) NULL);
3660 GetMagickToken(q,&q,token);
3662 GetMagickToken(q,&q,token);
3663 affine.tx=StringToDouble(token,(char **) NULL);
3664 GetMagickToken(q,&q,token);
3666 GetMagickToken(q,&q,token);
3667 affine.ty=StringToDouble(token,(char **) NULL);
3670 if (LocaleCompare("angle",keyword) == 0)
3672 GetMagickToken(q,&q,token);
3673 affine.rx=StringToDouble(token,(char **) NULL);
3674 affine.ry=StringToDouble(token,(char **) NULL);
3677 if (LocaleCompare("arc",keyword) == 0)
3679 primitive_type=ArcPrimitive;
3688 if (LocaleCompare("bezier",keyword) == 0)
3690 primitive_type=BezierPrimitive;
3699 if (LocaleCompare("clip-path",keyword) == 0)
3701 GetMagickToken(q,&q,token);
3702 (void) FormatLocaleString(message,MaxTextExtent,
3703 "clip-path:url(#%s);",token);
3704 (void) WriteBlobString(image,message);
3707 if (LocaleCompare("clip-rule",keyword) == 0)
3709 GetMagickToken(q,&q,token);
3710 (void) FormatLocaleString(message,MaxTextExtent,
3711 "clip-rule:%s;",token);
3712 (void) WriteBlobString(image,message);
3715 if (LocaleCompare("clip-units",keyword) == 0)
3717 GetMagickToken(q,&q,token);
3718 (void) FormatLocaleString(message,MaxTextExtent,
3719 "clipPathUnits=%s;",token);
3720 (void) WriteBlobString(image,message);
3723 if (LocaleCompare("circle",keyword) == 0)
3725 primitive_type=CirclePrimitive;
3728 if (LocaleCompare("color",keyword) == 0)
3730 primitive_type=ColorPrimitive;
3739 if (LocaleCompare("decorate",keyword) == 0)
3741 GetMagickToken(q,&q,token);
3742 (void) FormatLocaleString(message,MaxTextExtent,
3743 "text-decoration:%s;",token);
3744 (void) WriteBlobString(image,message);
3753 if (LocaleCompare("ellipse",keyword) == 0)
3755 primitive_type=EllipsePrimitive;
3764 if (LocaleCompare("fill",keyword) == 0)
3766 GetMagickToken(q,&q,token);
3767 (void) FormatLocaleString(message,MaxTextExtent,"fill:%s;",
3769 (void) WriteBlobString(image,message);
3772 if (LocaleCompare("fill-rule",keyword) == 0)
3774 GetMagickToken(q,&q,token);
3775 (void) FormatLocaleString(message,MaxTextExtent,
3776 "fill-rule:%s;",token);
3777 (void) WriteBlobString(image,message);
3780 if (LocaleCompare("fill-alpha",keyword) == 0)
3782 GetMagickToken(q,&q,token);
3783 (void) FormatLocaleString(message,MaxTextExtent,
3784 "fill-alpha:%s;",token);
3785 (void) WriteBlobString(image,message);
3788 if (LocaleCompare("font-family",keyword) == 0)
3790 GetMagickToken(q,&q,token);
3791 (void) FormatLocaleString(message,MaxTextExtent,
3792 "font-family:%s;",token);
3793 (void) WriteBlobString(image,message);
3796 if (LocaleCompare("font-stretch",keyword) == 0)
3798 GetMagickToken(q,&q,token);
3799 (void) FormatLocaleString(message,MaxTextExtent,
3800 "font-stretch:%s;",token);
3801 (void) WriteBlobString(image,message);
3804 if (LocaleCompare("font-style",keyword) == 0)
3806 GetMagickToken(q,&q,token);
3807 (void) FormatLocaleString(message,MaxTextExtent,
3808 "font-style:%s;",token);
3809 (void) WriteBlobString(image,message);
3812 if (LocaleCompare("font-size",keyword) == 0)
3814 GetMagickToken(q,&q,token);
3815 (void) FormatLocaleString(message,MaxTextExtent,
3816 "font-size:%s;",token);
3817 (void) WriteBlobString(image,message);
3820 if (LocaleCompare("font-weight",keyword) == 0)
3822 GetMagickToken(q,&q,token);
3823 (void) FormatLocaleString(message,MaxTextExtent,
3824 "font-weight:%s;",token);
3825 (void) WriteBlobString(image,message);
3834 if (LocaleCompare("gradient-units",keyword) == 0)
3836 GetMagickToken(q,&q,token);
3839 if (LocaleCompare("text-align",keyword) == 0)
3841 GetMagickToken(q,&q,token);
3842 (void) FormatLocaleString(message,MaxTextExtent,
3843 "text-align %s ",token);
3844 (void) WriteBlobString(image,message);
3847 if (LocaleCompare("text-anchor",keyword) == 0)
3849 GetMagickToken(q,&q,token);
3850 (void) FormatLocaleString(message,MaxTextExtent,
3851 "text-anchor %s ",token);
3852 (void) WriteBlobString(image,message);
3861 if (LocaleCompare("image",keyword) == 0)
3863 GetMagickToken(q,&q,token);
3864 primitive_type=ImagePrimitive;
3873 if (LocaleCompare("line",keyword) == 0)
3875 primitive_type=LinePrimitive;
3884 if (LocaleCompare("matte",keyword) == 0)
3886 primitive_type=MattePrimitive;
3895 if (LocaleCompare("opacity",keyword) == 0)
3897 GetMagickToken(q,&q,token);
3898 (void) FormatLocaleString(message,MaxTextExtent,"opacity %s ",
3900 (void) WriteBlobString(image,message);
3909 if (LocaleCompare("path",keyword) == 0)
3911 primitive_type=PathPrimitive;
3914 if (LocaleCompare("point",keyword) == 0)
3916 primitive_type=PointPrimitive;
3919 if (LocaleCompare("polyline",keyword) == 0)
3921 primitive_type=PolylinePrimitive;
3924 if (LocaleCompare("polygon",keyword) == 0)
3926 primitive_type=PolygonPrimitive;
3929 if (LocaleCompare("pop",keyword) == 0)
3931 GetMagickToken(q,&q,token);
3932 if (LocaleCompare("clip-path",token) == 0)
3934 (void) WriteBlobString(image,"</clipPath>\n");
3937 if (LocaleCompare("defs",token) == 0)
3939 (void) WriteBlobString(image,"</defs>\n");
3942 if (LocaleCompare("gradient",token) == 0)
3944 (void) FormatLocaleString(message,MaxTextExtent,
3945 "</%sGradient>\n",type);
3946 (void) WriteBlobString(image,message);
3949 if (LocaleCompare("graphic-context",token) == 0)
3953 ThrowWriterException(DrawError,
3954 "UnbalancedGraphicContextPushPop");
3955 (void) WriteBlobString(image,"</g>\n");
3957 if (LocaleCompare("pattern",token) == 0)
3959 (void) WriteBlobString(image,"</pattern>\n");
3962 if (LocaleCompare("defs",token) == 0)
3963 (void) WriteBlobString(image,"</g>\n");
3966 if (LocaleCompare("push",keyword) == 0)
3968 GetMagickToken(q,&q,token);
3969 if (LocaleCompare("clip-path",token) == 0)
3971 GetMagickToken(q,&q,token);
3972 (void) FormatLocaleString(message,MaxTextExtent,
3973 "<clipPath id=\"%s\">\n",token);
3974 (void) WriteBlobString(image,message);
3977 if (LocaleCompare("defs",token) == 0)
3979 (void) WriteBlobString(image,"<defs>\n");
3982 if (LocaleCompare("gradient",token) == 0)
3984 GetMagickToken(q,&q,token);
3985 (void) CopyMagickString(name,token,MaxTextExtent);
3986 GetMagickToken(q,&q,token);
3987 (void) CopyMagickString(type,token,MaxTextExtent);
3988 GetMagickToken(q,&q,token);
3989 svg_info.segment.x1=StringToDouble(token,(char **) NULL);
3990 svg_info.element.cx=StringToDouble(token,(char **) NULL);
3991 GetMagickToken(q,&q,token);
3993 GetMagickToken(q,&q,token);
3994 svg_info.segment.y1=StringToDouble(token,(char **) NULL);
3995 svg_info.element.cy=StringToDouble(token,(char **) NULL);
3996 GetMagickToken(q,&q,token);
3998 GetMagickToken(q,&q,token);
3999 svg_info.segment.x2=StringToDouble(token,(char **) NULL);
4000 svg_info.element.major=StringToDouble(token,
4002 GetMagickToken(q,&q,token);
4004 GetMagickToken(q,&q,token);
4005 svg_info.segment.y2=StringToDouble(token,(char **) NULL);
4006 svg_info.element.minor=StringToDouble(token,
4008 (void) FormatLocaleString(message,MaxTextExtent,
4009 "<%sGradient id=\"%s\" x1=\"%g\" y1=\"%g\" x2=\"%g\" "
4010 "y2=\"%g\">\n",type,name,svg_info.segment.x1,
4011 svg_info.segment.y1,svg_info.segment.x2,svg_info.segment.y2);
4012 if (LocaleCompare(type,"radial") == 0)
4014 GetMagickToken(q,&q,token);
4016 GetMagickToken(q,&q,token);
4017 svg_info.element.angle=StringToDouble(token,
4019 (void) FormatLocaleString(message,MaxTextExtent,
4020 "<%sGradient id=\"%s\" cx=\"%g\" cy=\"%g\" r=\"%g\" "
4021 "fx=\"%g\" fy=\"%g\">\n",type,name,
4022 svg_info.element.cx,svg_info.element.cy,
4023 svg_info.element.angle,svg_info.element.major,
4024 svg_info.element.minor);
4026 (void) WriteBlobString(image,message);
4029 if (LocaleCompare("graphic-context",token) == 0)
4034 AffineToTransform(image,&affine);
4037 (void) WriteBlobString(image,"<g style=\"");
4040 if (LocaleCompare("pattern",token) == 0)
4042 GetMagickToken(q,&q,token);
4043 (void) CopyMagickString(name,token,MaxTextExtent);
4044 GetMagickToken(q,&q,token);
4045 svg_info.bounds.x=StringToDouble(token,(char **) NULL);
4046 GetMagickToken(q,&q,token);
4048 GetMagickToken(q,&q,token);
4049 svg_info.bounds.y=StringToDouble(token,(char **) NULL);
4050 GetMagickToken(q,&q,token);
4052 GetMagickToken(q,&q,token);
4053 svg_info.bounds.width=StringToDouble(token,
4055 GetMagickToken(q,&q,token);
4057 GetMagickToken(q,&q,token);
4058 svg_info.bounds.height=StringToDouble(token,
4060 (void) FormatLocaleString(message,MaxTextExtent,
4061 "<pattern id=\"%s\" x=\"%g\" y=\"%g\" width=\"%g\" "
4062 "height=\"%g\">\n",name,svg_info.bounds.x,
4063 svg_info.bounds.y,svg_info.bounds.width,
4064 svg_info.bounds.height);
4065 (void) WriteBlobString(image,message);
4076 if (LocaleCompare("rectangle",keyword) == 0)
4078 primitive_type=RectanglePrimitive;
4081 if (LocaleCompare("roundRectangle",keyword) == 0)
4083 primitive_type=RoundRectanglePrimitive;
4086 if (LocaleCompare("rotate",keyword) == 0)
4088 GetMagickToken(q,&q,token);
4089 (void) FormatLocaleString(message,MaxTextExtent,"rotate(%s) ",
4091 (void) WriteBlobString(image,message);
4100 if (LocaleCompare("scale",keyword) == 0)
4102 GetMagickToken(q,&q,token);
4103 affine.sx=StringToDouble(token,(char **) NULL);
4104 GetMagickToken(q,&q,token);
4106 GetMagickToken(q,&q,token);
4107 affine.sy=StringToDouble(token,(char **) NULL);
4110 if (LocaleCompare("skewX",keyword) == 0)
4112 GetMagickToken(q,&q,token);
4113 (void) FormatLocaleString(message,MaxTextExtent,"skewX(%s) ",
4115 (void) WriteBlobString(image,message);
4118 if (LocaleCompare("skewY",keyword) == 0)
4120 GetMagickToken(q,&q,token);
4121 (void) FormatLocaleString(message,MaxTextExtent,"skewY(%s) ",
4123 (void) WriteBlobString(image,message);
4126 if (LocaleCompare("stop-color",keyword) == 0)
4129 color[MaxTextExtent];
4131 GetMagickToken(q,&q,token);
4132 (void) CopyMagickString(color,token,MaxTextExtent);
4133 GetMagickToken(q,&q,token);
4134 (void) FormatLocaleString(message,MaxTextExtent,
4135 " <stop offset=\"%s\" stop-color=\"%s\" />\n",token,color);
4136 (void) WriteBlobString(image,message);
4139 if (LocaleCompare("stroke",keyword) == 0)
4141 GetMagickToken(q,&q,token);
4142 (void) FormatLocaleString(message,MaxTextExtent,"stroke:%s;",
4144 (void) WriteBlobString(image,message);
4147 if (LocaleCompare("stroke-antialias",keyword) == 0)
4149 GetMagickToken(q,&q,token);
4150 (void) FormatLocaleString(message,MaxTextExtent,
4151 "stroke-antialias:%s;",token);
4152 (void) WriteBlobString(image,message);
4155 if (LocaleCompare("stroke-dasharray",keyword) == 0)
4163 GetMagickToken(p,&p,token);
4164 for (k=0; IsPoint(token); k++)
4165 GetMagickToken(p,&p,token);
4166 (void) WriteBlobString(image,"stroke-dasharray:");
4167 for (j=0; j < k; j++)
4169 GetMagickToken(q,&q,token);
4170 (void) FormatLocaleString(message,MaxTextExtent,"%s ",
4172 (void) WriteBlobString(image,message);
4174 (void) WriteBlobString(image,";");
4177 GetMagickToken(q,&q,token);
4178 (void) FormatLocaleString(message,MaxTextExtent,
4179 "stroke-dasharray:%s;",token);
4180 (void) WriteBlobString(image,message);
4183 if (LocaleCompare("stroke-dashoffset",keyword) == 0)
4185 GetMagickToken(q,&q,token);
4186 (void) FormatLocaleString(message,MaxTextExtent,
4187 "stroke-dashoffset:%s;",token);
4188 (void) WriteBlobString(image,message);
4191 if (LocaleCompare("stroke-linecap",keyword) == 0)
4193 GetMagickToken(q,&q,token);
4194 (void) FormatLocaleString(message,MaxTextExtent,
4195 "stroke-linecap:%s;",token);
4196 (void) WriteBlobString(image,message);
4199 if (LocaleCompare("stroke-linejoin",keyword) == 0)
4201 GetMagickToken(q,&q,token);
4202 (void) FormatLocaleString(message,MaxTextExtent,
4203 "stroke-linejoin:%s;",token);
4204 (void) WriteBlobString(image,message);
4207 if (LocaleCompare("stroke-miterlimit",keyword) == 0)
4209 GetMagickToken(q,&q,token);
4210 (void) FormatLocaleString(message,MaxTextExtent,
4211 "stroke-miterlimit:%s;",token);
4212 (void) WriteBlobString(image,message);
4215 if (LocaleCompare("stroke-opacity",keyword) == 0)
4217 GetMagickToken(q,&q,token);
4218 (void) FormatLocaleString(message,MaxTextExtent,
4219 "stroke-opacity:%s;",token);
4220 (void) WriteBlobString(image,message);
4223 if (LocaleCompare("stroke-width",keyword) == 0)
4225 GetMagickToken(q,&q,token);
4226 (void) FormatLocaleString(message,MaxTextExtent,
4227 "stroke-width:%s;",token);
4228 (void) WriteBlobString(image,message);
4237 if (LocaleCompare("text",keyword) == 0)
4239 primitive_type=TextPrimitive;
4242 if (LocaleCompare("text-antialias",keyword) == 0)
4244 GetMagickToken(q,&q,token);
4245 (void) FormatLocaleString(message,MaxTextExtent,
4246 "text-antialias:%s;",token);
4247 (void) WriteBlobString(image,message);
4250 if (LocaleCompare("tspan",keyword) == 0)
4252 primitive_type=TextPrimitive;
4255 if (LocaleCompare("translate",keyword) == 0)
4257 GetMagickToken(q,&q,token);
4258 affine.tx=StringToDouble(token,(char **) NULL);
4259 GetMagickToken(q,&q,token);
4261 GetMagickToken(q,&q,token);
4262 affine.ty=StringToDouble(token,(char **) NULL);
4271 if (LocaleCompare("viewbox",keyword) == 0)
4273 GetMagickToken(q,&q,token);
4275 GetMagickToken(q,&q,token);
4276 GetMagickToken(q,&q,token);
4278 GetMagickToken(q,&q,token);
4279 GetMagickToken(q,&q,token);
4281 GetMagickToken(q,&q,token);
4282 GetMagickToken(q,&q,token);
4294 if (status == MagickFalse)
4296 if (primitive_type == UndefinedPrimitive)
4299 Parse the primitive attributes.
4303 for (x=0; *q != '\0'; x++)
4308 if (IsPoint(q) == MagickFalse)
4310 GetMagickToken(q,&q,token);
4311 point.x=StringToDouble(token,(char **) NULL);
4312 GetMagickToken(q,&q,token);
4314 GetMagickToken(q,&q,token);
4315 point.y=StringToDouble(token,(char **) NULL);
4316 GetMagickToken(q,(const char **) NULL,token);
4318 GetMagickToken(q,&q,token);
4319 primitive_info[i].primitive=primitive_type;
4320 primitive_info[i].point=point;
4321 primitive_info[i].coordinates=0;
4322 primitive_info[i].method=FloodfillMethod;
4324 if (i < (ssize_t) (number_points-6*BezierQuantum-360))
4326 number_points+=6*BezierQuantum+360;
4327 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4328 number_points,sizeof(*primitive_info));
4329 if (primitive_info == (PrimitiveInfo *) NULL)
4331 (void) ThrowMagickException(exception,GetMagickModule(),
4332 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
4336 primitive_info[j].primitive=primitive_type;
4337 primitive_info[j].coordinates=x;
4338 primitive_info[j].method=FloodfillMethod;
4339 primitive_info[j].text=(char *) NULL;
4342 AffineToTransform(image,&affine);
4346 switch (primitive_type)
4348 case PointPrimitive:
4351 if (primitive_info[j].coordinates != 1)
4360 if (primitive_info[j].coordinates != 2)
4365 (void) FormatLocaleString(message,MaxTextExtent,
4366 " <line x1=\"%g\" y1=\"%g\" x2=\"%g\" y2=\"%g\"/>\n",
4367 primitive_info[j].point.x,primitive_info[j].point.y,
4368 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4369 (void) WriteBlobString(image,message);
4372 case RectanglePrimitive:
4374 if (primitive_info[j].coordinates != 2)
4379 (void) FormatLocaleString(message,MaxTextExtent,
4380 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"/>\n",
4381 primitive_info[j].point.x,primitive_info[j].point.y,
4382 primitive_info[j+1].point.x-primitive_info[j].point.x,
4383 primitive_info[j+1].point.y-primitive_info[j].point.y);
4384 (void) WriteBlobString(image,message);
4387 case RoundRectanglePrimitive:
4389 if (primitive_info[j].coordinates != 3)
4394 (void) FormatLocaleString(message,MaxTextExtent,
4395 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" rx=\"%g\" "
4396 "ry=\"%g\"/>\n",primitive_info[j].point.x,
4397 primitive_info[j].point.y,primitive_info[j+1].point.x-
4398 primitive_info[j].point.x,primitive_info[j+1].point.y-
4399 primitive_info[j].point.y,primitive_info[j+2].point.x,
4400 primitive_info[j+2].point.y);
4401 (void) WriteBlobString(image,message);
4406 if (primitive_info[j].coordinates != 3)
4413 case EllipsePrimitive:
4415 if (primitive_info[j].coordinates != 3)
4420 (void) FormatLocaleString(message,MaxTextExtent,
4421 " <ellipse cx=\"%g\" cy=\"%g\" rx=\"%g\" ry=\"%g\"/>\n",
4422 primitive_info[j].point.x,primitive_info[j].point.y,
4423 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4424 (void) WriteBlobString(image,message);
4427 case CirclePrimitive:
4433 if (primitive_info[j].coordinates != 2)
4438 alpha=primitive_info[j+1].point.x-primitive_info[j].point.x;
4439 beta=primitive_info[j+1].point.y-primitive_info[j].point.y;
4440 (void) FormatLocaleString(message,MaxTextExtent,
4441 " <circle cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
4442 primitive_info[j].point.x,primitive_info[j].point.y,
4444 (void) WriteBlobString(image,message);
4447 case PolylinePrimitive:
4449 if (primitive_info[j].coordinates < 2)
4454 (void) CopyMagickString(message," <polyline points=\"",MaxTextExtent);
4455 (void) WriteBlobString(image,message);
4456 length=strlen(message);
4459 (void) FormatLocaleString(message,MaxTextExtent,"%g,%g ",
4460 primitive_info[j].point.x,primitive_info[j].point.y);
4461 length+=strlen(message);
4464 (void) WriteBlobString(image,"\n ");
4465 length=strlen(message)+5;
4467 (void) WriteBlobString(image,message);
4469 (void) WriteBlobString(image,"\"/>\n");
4472 case PolygonPrimitive:
4474 if (primitive_info[j].coordinates < 3)
4479 primitive_info[i]=primitive_info[j];
4480 primitive_info[i].coordinates=0;
4481 primitive_info[j].coordinates++;
4483 (void) CopyMagickString(message," <polygon points=\"",MaxTextExtent);
4484 (void) WriteBlobString(image,message);
4485 length=strlen(message);
4488 (void) FormatLocaleString(message,MaxTextExtent,"%g,%g ",
4489 primitive_info[j].point.x,primitive_info[j].point.y);
4490 length+=strlen(message);
4493 (void) WriteBlobString(image,"\n ");
4494 length=strlen(message)+5;
4496 (void) WriteBlobString(image,message);
4498 (void) WriteBlobString(image,"\"/>\n");
4501 case BezierPrimitive:
4503 if (primitive_info[j].coordinates < 3)
4515 GetMagickToken(q,&q,token);
4516 number_attributes=1;
4517 for (p=token; *p != '\0'; p++)
4518 if (isalpha((int) *p))
4519 number_attributes++;
4520 if (i > (ssize_t) (number_points-6*BezierQuantum*number_attributes-1))
4522 number_points+=6*BezierQuantum*number_attributes;
4523 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4524 number_points,sizeof(*primitive_info));
4525 if (primitive_info == (PrimitiveInfo *) NULL)
4527 (void) ThrowMagickException(exception,GetMagickModule(),
4528 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4533 (void) WriteBlobString(image," <path d=\"");
4534 (void) WriteBlobString(image,token);
4535 (void) WriteBlobString(image,"\"/>\n");
4538 case ColorPrimitive:
4539 case MattePrimitive:
4541 if (primitive_info[j].coordinates != 1)
4546 GetMagickToken(q,&q,token);
4547 if (LocaleCompare("point",token) == 0)
4548 primitive_info[j].method=PointMethod;
4549 if (LocaleCompare("replace",token) == 0)
4550 primitive_info[j].method=ReplaceMethod;
4551 if (LocaleCompare("floodfill",token) == 0)
4552 primitive_info[j].method=FloodfillMethod;
4553 if (LocaleCompare("filltoborder",token) == 0)
4554 primitive_info[j].method=FillToBorderMethod;
4555 if (LocaleCompare("reset",token) == 0)
4556 primitive_info[j].method=ResetMethod;
4564 if (primitive_info[j].coordinates != 1)
4569 GetMagickToken(q,&q,token);
4570 (void) FormatLocaleString(message,MaxTextExtent,
4571 " <text x=\"%g\" y=\"%g\">",primitive_info[j].point.x,
4572 primitive_info[j].point.y);
4573 (void) WriteBlobString(image,message);
4574 for (p=token; *p != '\0'; p++)
4577 case '<': (void) WriteBlobString(image,"<"); break;
4578 case '>': (void) WriteBlobString(image,">"); break;
4579 case '&': (void) WriteBlobString(image,"&"); break;
4580 default: (void) WriteBlobByte(image,*p); break;
4582 (void) WriteBlobString(image,"</text>\n");
4585 case ImagePrimitive:
4587 if (primitive_info[j].coordinates != 2)
4592 GetMagickToken(q,&q,token);
4593 (void) FormatLocaleString(message,MaxTextExtent,
4594 " <image x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" "
4595 "xlink:href=\"%s\"/>\n",primitive_info[j].point.x,
4596 primitive_info[j].point.y,primitive_info[j+1].point.x,
4597 primitive_info[j+1].point.y,token);
4598 (void) WriteBlobString(image,message);
4602 if (primitive_info == (PrimitiveInfo *) NULL)
4604 primitive_info[i].primitive=UndefinedPrimitive;
4605 if (status == MagickFalse)
4608 (void) WriteBlobString(image,"</svg>\n");
4610 Relinquish resources.
4612 token=DestroyString(token);
4613 if (primitive_info != (PrimitiveInfo *) NULL)
4614 primitive_info=(PrimitiveInfo *) RelinquishMagickMemory(primitive_info);
4615 (void) CloseBlob(image);