2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Scalable Vector Graphics Format %
21 % Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
22 % dedicated to making software imaging solutions freely available. %
24 % You may not use this file except in compliance with the License. You may %
25 % obtain a copy of the License at %
27 % http://www.imagemagick.org/script/license.php %
29 % Unless required by applicable law or agreed to in writing, software %
30 % distributed under the License is distributed on an "AS IS" BASIS, %
31 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
32 % See the License for the specific language governing permissions and %
33 % limitations under the License. %
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/annotate.h"
45 #include "MagickCore/artifact.h"
46 #include "MagickCore/attribute.h"
47 #include "MagickCore/blob.h"
48 #include "MagickCore/blob-private.h"
49 #include "MagickCore/cache.h"
50 #include "MagickCore/constitute.h"
51 #include "MagickCore/composite-private.h"
52 #include "MagickCore/delegate.h"
53 #include "MagickCore/delegate-private.h"
54 #include "MagickCore/draw.h"
55 #include "MagickCore/exception.h"
56 #include "MagickCore/exception-private.h"
57 #include "MagickCore/gem.h"
58 #include "MagickCore/image.h"
59 #include "MagickCore/image-private.h"
60 #include "MagickCore/list.h"
61 #include "MagickCore/log.h"
62 #include "MagickCore/magick.h"
63 #include "MagickCore/memory_.h"
64 #include "MagickCore/module.h"
65 #include "MagickCore/monitor.h"
66 #include "MagickCore/monitor-private.h"
67 #include "MagickCore/quantum-private.h"
68 #include "MagickCore/pixel-accessor.h"
69 #include "MagickCore/property.h"
70 #include "MagickCore/resource_.h"
71 #include "MagickCore/static.h"
72 #include "MagickCore/string_.h"
73 #include "MagickCore/string-private.h"
74 #include "MagickCore/token.h"
75 #include "MagickCore/utility.h"
76 #if defined(MAGICKCORE_XML_DELEGATE)
77 # if defined(MAGICKCORE_WINDOWS_SUPPORT)
78 # if defined(__MINGW32__) || defined(__MINGW64__)
81 # include <win32config.h>
84 # include <libxml/parser.h>
85 # include <libxml/xmlmemory.h>
86 # include <libxml/parserInternals.h>
87 # include <libxml/xmlerror.h>
90 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
91 #include "autotrace/autotrace.h"
94 #if defined(MAGICKCORE_RSVG_DELEGATE)
95 #include "librsvg/rsvg.h"
96 #if !defined(LIBRSVG_CHECK_VERSION)
97 #include "librsvg/rsvg-cairo.h"
98 #include "librsvg/librsvg-features.h"
99 #elif !LIBRSVG_CHECK_VERSION(2,36,2)
100 #include "librsvg/rsvg-cairo.h"
101 #include "librsvg/librsvg-features.h"
106 Typedef declarations.
108 typedef struct _BoundingBox
117 typedef struct _ElementInfo
127 typedef struct _SVGInfo
181 #if defined(MAGICKCORE_XML_DELEGATE)
191 Forward declarations.
193 static MagickBooleanType
194 WriteSVGImage(const ImageInfo *,Image *,ExceptionInfo *);
197 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
205 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
207 % IsSVG()() returns MagickTrue if the image format type, identified by the
208 % magick string, is SVG.
210 % The format of the IsSVG method is:
212 % MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
214 % A description of each parameter follows:
216 % o magick: compare image format pattern against these bytes.
218 % o length: Specifies the length of the magick string.
221 static MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
225 if (LocaleNCompare((const char *) magick,"?xml",4) == 0)
230 #if defined(MAGICKCORE_XML_DELEGATE)
232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
236 % R e a d S V G I m a g e %
240 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
242 % ReadSVGImage() reads a Scalable Vector Gaphics file and returns it. It
243 % allocates the memory necessary for the new Image structure and returns a
244 % pointer to the new image.
246 % The format of the ReadSVGImage method is:
248 % Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
250 % A description of each parameter follows:
252 % o image_info: the image info.
254 % o exception: return any errors or warnings in this structure.
258 static SVGInfo *AcquireSVGInfo(void)
263 svg_info=(SVGInfo *) AcquireMagickMemory(sizeof(*svg_info));
264 if (svg_info == (SVGInfo *) NULL)
265 return((SVGInfo *) NULL);
266 (void) ResetMagickMemory(svg_info,0,sizeof(*svg_info));
267 svg_info->text=AcquireString("");
268 svg_info->scale=(double *) AcquireMagickMemory(sizeof(*svg_info->scale));
269 if (svg_info->scale == (double *) NULL)
270 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
271 GetAffineMatrix(&svg_info->affine);
272 svg_info->scale[0]=ExpandAffine(&svg_info->affine);
276 static SVGInfo *DestroySVGInfo(SVGInfo *svg_info)
278 if (svg_info->text != (char *) NULL)
279 svg_info->text=DestroyString(svg_info->text);
280 if (svg_info->scale != (double *) NULL)
281 svg_info->scale=(double *) (svg_info->scale);
282 if (svg_info->title != (char *) NULL)
283 svg_info->title=DestroyString(svg_info->title);
284 if (svg_info->comment != (char *) NULL)
285 svg_info->comment=DestroyString(svg_info->comment);
286 return((SVGInfo *) RelinquishMagickMemory(svg_info));
289 static double GetUserSpaceCoordinateValue(const SVGInfo *svg_info,int type,
293 token[MaxTextExtent];
301 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",string);
302 assert(string != (const char *) NULL);
303 p=(const char *) string;
304 GetMagickToken(p,&p,token);
305 value=StringToDouble(token,(char **) NULL);
306 if (strchr(token,'%') != (char *) NULL)
314 if (svg_info->view_box.width == 0.0)
316 return(svg_info->view_box.width*value/100.0);
320 if (svg_info->view_box.height == 0.0)
322 return(svg_info->view_box.height*value/100.0);
324 alpha=value-svg_info->view_box.width;
325 beta=value-svg_info->view_box.height;
326 return(hypot(alpha,beta)/sqrt(2.0)/100.0);
328 GetMagickToken(p,&p,token);
329 if (LocaleNCompare(token,"cm",2) == 0)
330 return(DefaultResolution*svg_info->scale[0]/2.54*value);
331 if (LocaleNCompare(token,"em",2) == 0)
332 return(svg_info->pointsize*value);
333 if (LocaleNCompare(token,"ex",2) == 0)
334 return(svg_info->pointsize*value/2.0);
335 if (LocaleNCompare(token,"in",2) == 0)
336 return(DefaultResolution*svg_info->scale[0]*value);
337 if (LocaleNCompare(token,"mm",2) == 0)
338 return(DefaultResolution*svg_info->scale[0]/25.4*value);
339 if (LocaleNCompare(token,"pc",2) == 0)
340 return(DefaultResolution*svg_info->scale[0]/6.0*value);
341 if (LocaleNCompare(token,"pt",2) == 0)
342 return(1.25*svg_info->scale[0]*value);
343 if (LocaleNCompare(token,"px",2) == 0)
348 static void StripStyleTokens(char *message)
357 assert(message != (char *) NULL);
358 if (*message == '\0')
360 length=strlen(message);
362 while (isspace((int) ((unsigned char) *p)) != 0)
365 while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
367 (void) CopyMagickMemory(message,p,(size_t) (q-p+1));
369 StripString(message);
372 static char **GetStyleTokens(void *context,const char *style,int *number_tokens)
384 svg_info=(SVGInfo *) context;
387 if (style == (const char *) NULL)
388 return((char **) NULL);
389 text=AcquireString(style);
390 (void) SubstituteString(&text,":","\n");
391 (void) SubstituteString(&text,";","\n");
392 tokens=StringToList(text);
393 text=DestroyString(text);
394 for (i=0; tokens[i] != (char *) NULL; i++)
395 StripStyleTokens(tokens[i]);
400 static char **GetTransformTokens(void *context,const char *text,
416 svg_info=(SVGInfo *) context;
418 if (text == (const char *) NULL)
419 return((char **) NULL);
421 Determine the number of arguments.
423 for (p=text; *p != '\0'; p++)
428 tokens=(char **) AcquireQuantumMemory(*number_tokens+2UL,sizeof(*tokens));
429 if (tokens == (char **) NULL)
431 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
432 ResourceLimitError,"MemoryAllocationFailed","`%s'",text);
433 return((char **) NULL);
436 Convert string to an ASCII list.
440 for (q=p; *q != '\0'; q++)
442 if ((*q != '(') && (*q != ')') && (*q != '\0'))
444 tokens[i]=AcquireString(p);
445 (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
446 StripString(tokens[i++]);
449 tokens[i]=AcquireString(p);
450 (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
451 StripString(tokens[i++]);
452 tokens[i]=(char *) NULL;
456 #if defined(__cplusplus) || defined(c_plusplus)
460 static int SVGIsStandalone(void *context)
466 Is this document tagged standalone?
468 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGIsStandalone()");
469 svg_info=(SVGInfo *) context;
470 return(svg_info->document->standalone == 1);
473 static int SVGHasInternalSubset(void *context)
479 Does this document has an internal subset?
481 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
482 " SAX.SVGHasInternalSubset()");
483 svg_info=(SVGInfo *) context;
484 return(svg_info->document->intSubset != NULL);
487 static int SVGHasExternalSubset(void *context)
493 Does this document has an external subset?
495 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
496 " SAX.SVGHasExternalSubset()");
497 svg_info=(SVGInfo *) context;
498 return(svg_info->document->extSubset != NULL);
501 static void SVGInternalSubset(void *context,const xmlChar *name,
502 const xmlChar *external_id,const xmlChar *system_id)
508 Does this document has an internal subset?
510 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
511 " SAX.internalSubset(%s, %s, %s)",(const char *) name,
512 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
513 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
514 svg_info=(SVGInfo *) context;
515 (void) xmlCreateIntSubset(svg_info->document,name,external_id,system_id);
518 static xmlParserInputPtr SVGResolveEntity(void *context,
519 const xmlChar *public_id,const xmlChar *system_id)
528 Special entity resolver, better left to the parser, it has more
529 context than the application layer. The default behaviour is to
530 not resolve the entities, in that case the ENTITY_REF nodes are
531 built in the structure (and the parameter values).
533 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
534 " SAX.resolveEntity(%s, %s)",
535 (public_id != (const xmlChar *) NULL ? (const char *) public_id : "none"),
536 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
537 svg_info=(SVGInfo *) context;
538 stream=xmlLoadExternalEntity((const char *) system_id,(const char *)
539 public_id,svg_info->parser);
543 static xmlEntityPtr SVGGetEntity(void *context,const xmlChar *name)
549 Get an entity by name.
551 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGGetEntity(%s)",
553 svg_info=(SVGInfo *) context;
554 return(xmlGetDocEntity(svg_info->document,name));
557 static xmlEntityPtr SVGGetParameterEntity(void *context,const xmlChar *name)
563 Get a parameter entity by name.
565 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
566 " SAX.getParameterEntity(%s)",name);
567 svg_info=(SVGInfo *) context;
568 return(xmlGetParameterEntity(svg_info->document,name));
571 static void SVGEntityDeclaration(void *context,const xmlChar *name,int type,
572 const xmlChar *public_id,const xmlChar *system_id,xmlChar *content)
578 An entity definition has been parsed.
580 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
581 " SAX.entityDecl(%s, %d, %s, %s, %s)",name,type,
582 public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
583 system_id != (xmlChar *) NULL ? (const char *) system_id : "none",content);
584 svg_info=(SVGInfo *) context;
585 if (svg_info->parser->inSubset == 1)
586 (void) xmlAddDocEntity(svg_info->document,name,type,public_id,system_id,
589 if (svg_info->parser->inSubset == 2)
590 (void) xmlAddDtdEntity(svg_info->document,name,type,public_id,system_id,
594 static void SVGAttributeDeclaration(void *context,const xmlChar *element,
595 const xmlChar *name,int type,int value,const xmlChar *default_value,
596 xmlEnumerationPtr tree)
609 An attribute definition has been parsed.
611 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
612 " SAX.attributeDecl(%s, %s, %d, %d, %s, ...)",element,name,type,value,
614 svg_info=(SVGInfo *) context;
615 fullname=(xmlChar *) NULL;
616 prefix=(xmlChar *) NULL;
617 parser=svg_info->parser;
618 fullname=(xmlChar *) xmlSplitQName(parser,name,&prefix);
619 if (parser->inSubset == 1)
620 (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->intSubset,
621 element,fullname,prefix,(xmlAttributeType) type,
622 (xmlAttributeDefault) value,default_value,tree);
624 if (parser->inSubset == 2)
625 (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->extSubset,
626 element,fullname,prefix,(xmlAttributeType) type,
627 (xmlAttributeDefault) value,default_value,tree);
628 if (prefix != (xmlChar *) NULL)
630 if (fullname != (xmlChar *) NULL)
634 static void SVGElementDeclaration(void *context,const xmlChar *name,int type,
635 xmlElementContentPtr content)
644 An element definition has been parsed.
646 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
647 " SAX.elementDecl(%s, %d, ...)",name,type);
648 svg_info=(SVGInfo *) context;
649 parser=svg_info->parser;
650 if (parser->inSubset == 1)
651 (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->intSubset,
652 name,(xmlElementTypeVal) type,content);
654 if (parser->inSubset == 2)
655 (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->extSubset,
656 name,(xmlElementTypeVal) type,content);
659 static void SVGNotationDeclaration(void *context,const xmlChar *name,
660 const xmlChar *public_id,const xmlChar *system_id)
669 What to do when a notation declaration has been parsed.
671 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
672 " SAX.notationDecl(%s, %s, %s)",name,
673 public_id != (const xmlChar *) NULL ? (const char *) public_id : "none",
674 system_id != (const xmlChar *) NULL ? (const char *) system_id : "none");
675 svg_info=(SVGInfo *) context;
676 parser=svg_info->parser;
677 if (parser->inSubset == 1)
678 (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
679 name,public_id,system_id);
681 if (parser->inSubset == 2)
682 (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
683 name,public_id,system_id);
686 static void SVGUnparsedEntityDeclaration(void *context,const xmlChar *name,
687 const xmlChar *public_id,const xmlChar *system_id,const xmlChar *notation)
693 What to do when an unparsed entity declaration is parsed.
695 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
696 " SAX.unparsedEntityDecl(%s, %s, %s, %s)",name,
697 public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
698 system_id != (xmlChar *) NULL ? (const char *) system_id : "none",notation);
699 svg_info=(SVGInfo *) context;
700 (void) xmlAddDocEntity(svg_info->document,name,
701 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,public_id,system_id,notation);
705 static void SVGSetDocumentLocator(void *context,xmlSAXLocatorPtr location)
711 Receive the document locator at startup, actually xmlDefaultSAXLocator.
714 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
715 " SAX.setDocumentLocator()");
716 svg_info=(SVGInfo *) context;
720 static void SVGStartDocument(void *context)
729 Called when the document start being processed.
731 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startDocument()");
732 svg_info=(SVGInfo *) context;
733 GetExceptionInfo(svg_info->exception);
734 parser=svg_info->parser;
735 svg_info->document=xmlNewDoc(parser->version);
736 if (svg_info->document == (xmlDocPtr) NULL)
738 if (parser->encoding == NULL)
739 svg_info->document->encoding=(const xmlChar *) NULL;
741 svg_info->document->encoding=xmlStrdup(parser->encoding);
742 svg_info->document->standalone=parser->standalone;
745 static void SVGEndDocument(void *context)
751 Called when the document end has been detected.
753 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.endDocument()");
754 svg_info=(SVGInfo *) context;
755 if (svg_info->offset != (char *) NULL)
756 svg_info->offset=DestroyString(svg_info->offset);
757 if (svg_info->stop_color != (char *) NULL)
758 svg_info->stop_color=DestroyString(svg_info->stop_color);
759 if (svg_info->scale != (double *) NULL)
760 svg_info->scale=(double *) RelinquishMagickMemory(svg_info->scale);
761 if (svg_info->text != (char *) NULL)
762 svg_info->text=DestroyString(svg_info->text);
763 if (svg_info->vertices != (char *) NULL)
764 svg_info->vertices=DestroyString(svg_info->vertices);
765 if (svg_info->url != (char *) NULL)
766 svg_info->url=DestroyString(svg_info->url);
767 #if defined(MAGICKCORE_XML_DELEGATE)
768 if (svg_info->document != (xmlDocPtr) NULL)
770 xmlFreeDoc(svg_info->document);
771 svg_info->document=(xmlDocPtr) NULL;
776 static void SVGStartElement(void *context,const xmlChar *name,
777 const xmlChar **attributes)
782 token[MaxTextExtent],
802 Called when an opening tag has been processed.
804 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startElement(%s",
806 svg_info=(SVGInfo *) context;
808 svg_info->scale=(double *) ResizeQuantumMemory(svg_info->scale,
809 svg_info->n+1UL,sizeof(*svg_info->scale));
810 if (svg_info->scale == (double *) NULL)
812 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
813 ResourceLimitError,"MemoryAllocationFailed","`%s'",name);
816 svg_info->scale[svg_info->n]=svg_info->scale[svg_info->n-1];
817 color=AcquireString("none");
818 units=AcquireString("userSpaceOnUse");
819 value=(const char *) NULL;
820 if (attributes != (const xmlChar **) NULL)
821 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
823 keyword=(const char *) attributes[i];
824 value=(const char *) attributes[i+1];
830 if (LocaleCompare(keyword,"cx") == 0)
832 svg_info->element.cx=
833 GetUserSpaceCoordinateValue(svg_info,1,value);
836 if (LocaleCompare(keyword,"cy") == 0)
838 svg_info->element.cy=
839 GetUserSpaceCoordinateValue(svg_info,-1,value);
847 if (LocaleCompare(keyword,"fx") == 0)
849 svg_info->element.major=
850 GetUserSpaceCoordinateValue(svg_info,1,value);
853 if (LocaleCompare(keyword,"fy") == 0)
855 svg_info->element.minor=
856 GetUserSpaceCoordinateValue(svg_info,-1,value);
864 if (LocaleCompare(keyword,"height") == 0)
866 svg_info->bounds.height=
867 GetUserSpaceCoordinateValue(svg_info,-1,value);
875 if (LocaleCompare(keyword,"id") == 0)
877 (void) CopyMagickString(id,value,MaxTextExtent);
885 if (LocaleCompare(keyword,"r") == 0)
887 svg_info->element.angle=
888 GetUserSpaceCoordinateValue(svg_info,0,value);
896 if (LocaleCompare(keyword,"width") == 0)
898 svg_info->bounds.width=
899 GetUserSpaceCoordinateValue(svg_info,1,value);
907 if (LocaleCompare(keyword,"x") == 0)
909 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value)-
913 if (LocaleCompare(keyword,"x1") == 0)
915 svg_info->segment.x1=GetUserSpaceCoordinateValue(svg_info,1,
919 if (LocaleCompare(keyword,"x2") == 0)
921 svg_info->segment.x2=GetUserSpaceCoordinateValue(svg_info,1,
930 if (LocaleCompare(keyword,"y") == 0)
932 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value)-
936 if (LocaleCompare(keyword,"y1") == 0)
938 svg_info->segment.y1=
939 GetUserSpaceCoordinateValue(svg_info,-1,value);
942 if (LocaleCompare(keyword,"y2") == 0)
944 svg_info->segment.y2=
945 GetUserSpaceCoordinateValue(svg_info,-1,value);
954 if (strchr((char *) name,':') != (char *) NULL)
959 for ( ; *name != ':'; name++) ;
967 if (LocaleCompare((const char *) name,"circle") == 0)
969 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
972 if (LocaleCompare((const char *) name,"clipPath") == 0)
974 (void) FormatLocaleFile(svg_info->file,"push clip-path '%s'\n",id);
982 if (LocaleCompare((const char *) name,"defs") == 0)
984 (void) FormatLocaleFile(svg_info->file,"push defs\n");
992 if (LocaleCompare((const char *) name,"ellipse") == 0)
994 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1002 if (LocaleCompare((const char *) name,"g") == 0)
1004 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1012 if (LocaleCompare((const char *) name,"image") == 0)
1014 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1022 if (LocaleCompare((const char *) name,"line") == 0)
1024 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1027 if (LocaleCompare((const char *) name,"linearGradient") == 0)
1029 (void) FormatLocaleFile(svg_info->file,
1030 "push gradient '%s' linear %g,%g %g,%g\n",id,
1031 svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
1032 svg_info->segment.y2);
1040 if (LocaleCompare((const char *) name,"path") == 0)
1042 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1045 if (LocaleCompare((const char *) name,"pattern") == 0)
1047 (void) FormatLocaleFile(svg_info->file,
1048 "push pattern '%s' %g,%g %g,%g\n",id,
1049 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.width,
1050 svg_info->bounds.height);
1053 if (LocaleCompare((const char *) name,"polygon") == 0)
1055 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1058 if (LocaleCompare((const char *) name,"polyline") == 0)
1060 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1068 if (LocaleCompare((const char *) name,"radialGradient") == 0)
1070 (void) FormatLocaleFile(svg_info->file,
1071 "push gradient '%s' radial %g,%g %g,%g %g\n",
1072 id,svg_info->element.cx,svg_info->element.cy,
1073 svg_info->element.major,svg_info->element.minor,
1074 svg_info->element.angle);
1077 if (LocaleCompare((const char *) name,"rect") == 0)
1079 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1087 if (LocaleCompare((const char *) name,"svg") == 0)
1089 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1097 if (LocaleCompare((const char *) name,"text") == 0)
1099 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1100 svg_info->bounds.x=0.0;
1101 svg_info->bounds.y=0.0;
1102 svg_info->bounds.width=0.0;
1103 svg_info->bounds.height=0.0;
1106 if (LocaleCompare((const char *) name,"tspan") == 0)
1108 if (*svg_info->text != '\0')
1119 text=EscapeString(svg_info->text,'\'');
1120 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
1121 svg_info->bounds.x-svg_info->center.x,svg_info->bounds.y-
1122 svg_info->center.y,text);
1123 text=DestroyString(text);
1124 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
1125 draw_info->pointsize=svg_info->pointsize;
1126 draw_info->text=AcquireString(svg_info->text);
1127 (void) ConcatenateString(&draw_info->text," ");
1128 (void) GetTypeMetrics(svg_info->image,draw_info,
1129 &metrics,svg_info->exception);
1130 svg_info->bounds.x+=metrics.width;
1131 draw_info=DestroyDrawInfo(draw_info);
1132 *svg_info->text='\0';
1134 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1142 if (attributes != (const xmlChar **) NULL)
1143 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
1145 keyword=(const char *) attributes[i];
1146 value=(const char *) attributes[i+1];
1147 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1148 " %s = %s",keyword,value);
1154 if (LocaleCompare(keyword,"angle") == 0)
1156 (void) FormatLocaleFile(svg_info->file,"angle %g\n",
1157 GetUserSpaceCoordinateValue(svg_info,0,value));
1165 if (LocaleCompare(keyword,"clip-path") == 0)
1167 (void) FormatLocaleFile(svg_info->file,"clip-path '%s'\n",value);
1170 if (LocaleCompare(keyword,"clip-rule") == 0)
1172 (void) FormatLocaleFile(svg_info->file,"clip-rule '%s'\n",value);
1175 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1177 (void) CloneString(&units,value);
1178 (void) FormatLocaleFile(svg_info->file,"clip-units '%s'\n",value);
1181 if (LocaleCompare(keyword,"color") == 0)
1183 (void) CloneString(&color,value);
1186 if (LocaleCompare(keyword,"cx") == 0)
1188 svg_info->element.cx=
1189 GetUserSpaceCoordinateValue(svg_info,1,value);
1192 if (LocaleCompare(keyword,"cy") == 0)
1194 svg_info->element.cy=
1195 GetUserSpaceCoordinateValue(svg_info,-1,value);
1203 if (LocaleCompare(keyword,"d") == 0)
1205 (void) CloneString(&svg_info->vertices,value);
1208 if (LocaleCompare(keyword,"dx") == 0)
1210 svg_info->bounds.x+=GetUserSpaceCoordinateValue(svg_info,1,value);
1213 if (LocaleCompare(keyword,"dy") == 0)
1215 svg_info->bounds.y+=
1216 GetUserSpaceCoordinateValue(svg_info,-1,value);
1224 if (LocaleCompare(keyword,"fill") == 0)
1226 if (LocaleCompare(value,"currentColor") == 0)
1228 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",color);
1231 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",value);
1234 if (LocaleCompare(keyword,"fillcolor") == 0)
1236 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",value);
1239 if (LocaleCompare(keyword,"fill-rule") == 0)
1241 (void) FormatLocaleFile(svg_info->file,"fill-rule '%s'\n",value);
1244 if (LocaleCompare(keyword,"fill-alpha") == 0)
1246 (void) FormatLocaleFile(svg_info->file,"fill-alpha '%s'\n",
1250 if (LocaleCompare(keyword,"font-family") == 0)
1252 (void) FormatLocaleFile(svg_info->file,"font-family '%s'\n",
1256 if (LocaleCompare(keyword,"font-stretch") == 0)
1258 (void) FormatLocaleFile(svg_info->file,"font-stretch '%s'\n",
1262 if (LocaleCompare(keyword,"font-style") == 0)
1264 (void) FormatLocaleFile(svg_info->file,"font-style '%s'\n",value);
1267 if (LocaleCompare(keyword,"font-size") == 0)
1269 svg_info->pointsize=GetUserSpaceCoordinateValue(svg_info,0,value);
1270 (void) FormatLocaleFile(svg_info->file,"font-size %g\n",
1271 svg_info->pointsize);
1274 if (LocaleCompare(keyword,"font-weight") == 0)
1276 (void) FormatLocaleFile(svg_info->file,"font-weight '%s'\n",
1285 if (LocaleCompare(keyword,"gradientTransform") == 0)
1292 GetAffineMatrix(&transform);
1293 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1294 tokens=GetTransformTokens(context,value,&number_tokens);
1295 for (j=0; j < (number_tokens-1); j+=2)
1297 keyword=(char *) tokens[j];
1298 if (keyword == (char *) NULL)
1300 value=(char *) tokens[j+1];
1301 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1302 " %s: %s",keyword,value);
1304 GetAffineMatrix(&affine);
1310 if (LocaleCompare(keyword,"matrix") == 0)
1312 p=(const char *) value;
1313 GetMagickToken(p,&p,token);
1314 affine.sx=StringToDouble(value,(char **) NULL);
1315 GetMagickToken(p,&p,token);
1317 GetMagickToken(p,&p,token);
1318 affine.rx=StringToDouble(token,(char **) NULL);
1319 GetMagickToken(p,&p,token);
1321 GetMagickToken(p,&p,token);
1322 affine.ry=StringToDouble(token,(char **) NULL);
1323 GetMagickToken(p,&p,token);
1325 GetMagickToken(p,&p,token);
1326 affine.sy=StringToDouble(token,(char **) NULL);
1327 GetMagickToken(p,&p,token);
1329 GetMagickToken(p,&p,token);
1330 affine.tx=StringToDouble(token,(char **) NULL);
1331 GetMagickToken(p,&p,token);
1333 GetMagickToken(p,&p,token);
1334 affine.ty=StringToDouble(token,(char **) NULL);
1342 if (LocaleCompare(keyword,"rotate") == 0)
1347 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1348 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1349 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1350 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1351 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1359 if (LocaleCompare(keyword,"scale") == 0)
1361 for (p=(const char *) value; *p != '\0'; p++)
1362 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1365 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1366 affine.sy=affine.sx;
1369 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1370 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
1373 if (LocaleCompare(keyword,"skewX") == 0)
1375 affine.sx=svg_info->affine.sx;
1376 affine.ry=tan(DegreesToRadians(fmod(
1377 GetUserSpaceCoordinateValue(svg_info,1,value),
1379 affine.sy=svg_info->affine.sy;
1382 if (LocaleCompare(keyword,"skewY") == 0)
1384 affine.sx=svg_info->affine.sx;
1385 affine.rx=tan(DegreesToRadians(fmod(
1386 GetUserSpaceCoordinateValue(svg_info,-1,value),
1388 affine.sy=svg_info->affine.sy;
1396 if (LocaleCompare(keyword,"translate") == 0)
1398 for (p=(const char *) value; *p != '\0'; p++)
1399 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1402 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
1403 affine.ty=affine.tx;
1406 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1414 transform.sx=affine.sx*current.sx+affine.ry*current.rx;
1415 transform.rx=affine.rx*current.sx+affine.sy*current.rx;
1416 transform.ry=affine.sx*current.ry+affine.ry*current.sy;
1417 transform.sy=affine.rx*current.ry+affine.sy*current.sy;
1418 transform.tx=affine.tx*current.sx+affine.ty*current.ry+
1420 transform.ty=affine.tx*current.rx+affine.ty*current.sy+
1423 (void) FormatLocaleFile(svg_info->file,
1424 "affine %g %g %g %g %g %g\n",transform.sx,
1425 transform.rx,transform.ry,transform.sy,transform.tx,
1427 for (j=0; tokens[j] != (char *) NULL; j++)
1428 tokens[j]=DestroyString(tokens[j]);
1429 tokens=(char **) RelinquishMagickMemory(tokens);
1432 if (LocaleCompare(keyword,"gradientUnits") == 0)
1434 (void) CloneString(&units,value);
1435 (void) FormatLocaleFile(svg_info->file,"gradient-units '%s'\n",
1444 if (LocaleCompare(keyword,"height") == 0)
1446 svg_info->bounds.height=
1447 GetUserSpaceCoordinateValue(svg_info,-1,value);
1450 if (LocaleCompare(keyword,"href") == 0)
1452 (void) CloneString(&svg_info->url,value);
1460 if (LocaleCompare(keyword,"major") == 0)
1462 svg_info->element.major=
1463 GetUserSpaceCoordinateValue(svg_info,1,value);
1466 if (LocaleCompare(keyword,"minor") == 0)
1468 svg_info->element.minor=
1469 GetUserSpaceCoordinateValue(svg_info,-1,value);
1477 if (LocaleCompare(keyword,"offset") == 0)
1479 (void) CloneString(&svg_info->offset,value);
1482 if (LocaleCompare(keyword,"opacity") == 0)
1484 (void) FormatLocaleFile(svg_info->file,"opacity '%s'\n",value);
1492 if (LocaleCompare(keyword,"path") == 0)
1494 (void) CloneString(&svg_info->url,value);
1497 if (LocaleCompare(keyword,"points") == 0)
1499 (void) CloneString(&svg_info->vertices,value);
1507 if (LocaleCompare(keyword,"r") == 0)
1509 svg_info->element.major=
1510 GetUserSpaceCoordinateValue(svg_info,1,value);
1511 svg_info->element.minor=
1512 GetUserSpaceCoordinateValue(svg_info,-1,value);
1515 if (LocaleCompare(keyword,"rotate") == 0)
1520 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1521 (void) FormatLocaleFile(svg_info->file,"translate %g,%g\n",
1522 svg_info->bounds.x,svg_info->bounds.y);
1523 svg_info->bounds.x=0;
1524 svg_info->bounds.y=0;
1525 (void) FormatLocaleFile(svg_info->file,"rotate %g\n",angle);
1528 if (LocaleCompare(keyword,"rx") == 0)
1530 if (LocaleCompare((const char *) name,"ellipse") == 0)
1531 svg_info->element.major=
1532 GetUserSpaceCoordinateValue(svg_info,1,value);
1535 GetUserSpaceCoordinateValue(svg_info,1,value);
1538 if (LocaleCompare(keyword,"ry") == 0)
1540 if (LocaleCompare((const char *) name,"ellipse") == 0)
1541 svg_info->element.minor=
1542 GetUserSpaceCoordinateValue(svg_info,-1,value);
1545 GetUserSpaceCoordinateValue(svg_info,-1,value);
1553 if (LocaleCompare(keyword,"stop-color") == 0)
1555 (void) CloneString(&svg_info->stop_color,value);
1558 if (LocaleCompare(keyword,"stroke") == 0)
1560 if (LocaleCompare(value,"currentColor") == 0)
1562 (void) FormatLocaleFile(svg_info->file,"stroke '%s'\n",color);
1565 (void) FormatLocaleFile(svg_info->file,"stroke '%s'\n",value);
1568 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1570 (void) FormatLocaleFile(svg_info->file,"stroke-antialias %d\n",
1571 LocaleCompare(value,"true") == 0);
1574 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1576 (void) FormatLocaleFile(svg_info->file,"stroke-dasharray %s\n",
1580 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1582 (void) FormatLocaleFile(svg_info->file,"stroke-dashoffset %s\n",
1586 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1588 (void) FormatLocaleFile(svg_info->file,"stroke-linecap '%s'\n",
1592 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1594 (void) FormatLocaleFile(svg_info->file,"stroke-linejoin '%s'\n",
1598 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1600 (void) FormatLocaleFile(svg_info->file,"stroke-miterlimit '%s'\n",
1604 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1606 (void) FormatLocaleFile(svg_info->file,"stroke-opacity '%s'\n",
1610 if (LocaleCompare(keyword,"stroke-width") == 0)
1612 (void) FormatLocaleFile(svg_info->file,"stroke-width %g\n",
1613 GetUserSpaceCoordinateValue(svg_info,1,value));
1616 if (LocaleCompare(keyword,"style") == 0)
1618 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1619 tokens=GetStyleTokens(context,value,&number_tokens);
1620 for (j=0; j < (number_tokens-1); j+=2)
1622 keyword=(char *) tokens[j];
1623 value=(char *) tokens[j+1];
1624 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1625 " %s: %s",keyword,value);
1631 if (LocaleCompare(keyword,"clip-path") == 0)
1633 (void) FormatLocaleFile(svg_info->file,
1634 "clip-path '%s'\n",value);
1637 if (LocaleCompare(keyword,"clip-rule") == 0)
1639 (void) FormatLocaleFile(svg_info->file,
1640 "clip-rule '%s'\n",value);
1643 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1645 (void) CloneString(&units,value);
1646 (void) FormatLocaleFile(svg_info->file,
1647 "clip-units '%s'\n",value);
1650 if (LocaleCompare(keyword,"color") == 0)
1652 (void) CloneString(&color,value);
1660 if (LocaleCompare(keyword,"fill") == 0)
1662 if (LocaleCompare(value,"currentColor") == 0)
1664 (void) FormatLocaleFile(svg_info->file,
1665 "fill '%s'\n",color);
1668 if (LocaleCompare(value,"#000000ff") == 0)
1669 (void) FormatLocaleFile(svg_info->file,
1670 "fill '#000000'\n");
1672 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",
1676 if (LocaleCompare(keyword,"fillcolor") == 0)
1678 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",
1682 if (LocaleCompare(keyword,"fill-rule") == 0)
1684 (void) FormatLocaleFile(svg_info->file,
1685 "fill-rule '%s'\n",value);
1688 if (LocaleCompare(keyword,"fill-alpha") == 0)
1690 (void) FormatLocaleFile(svg_info->file,
1691 "fill-alpha '%s'\n",value);
1694 if (LocaleCompare(keyword,"font-family") == 0)
1696 (void) FormatLocaleFile(svg_info->file,
1697 "font-family '%s'\n",value);
1700 if (LocaleCompare(keyword,"font-stretch") == 0)
1702 (void) FormatLocaleFile(svg_info->file,
1703 "font-stretch '%s'\n",value);
1706 if (LocaleCompare(keyword,"font-style") == 0)
1708 (void) FormatLocaleFile(svg_info->file,
1709 "font-style '%s'\n",value);
1712 if (LocaleCompare(keyword,"font-size") == 0)
1714 svg_info->pointsize=GetUserSpaceCoordinateValue(
1716 (void) FormatLocaleFile(svg_info->file,"font-size %g\n",
1717 svg_info->pointsize);
1720 if (LocaleCompare(keyword,"font-weight") == 0)
1722 (void) FormatLocaleFile(svg_info->file,
1723 "font-weight '%s'\n",value);
1731 if (LocaleCompare(keyword,"offset") == 0)
1733 (void) FormatLocaleFile(svg_info->file,"offset %g\n",
1734 GetUserSpaceCoordinateValue(svg_info,1,value));
1737 if (LocaleCompare(keyword,"opacity") == 0)
1739 (void) FormatLocaleFile(svg_info->file,
1740 "opacity '%s'\n",value);
1748 if (LocaleCompare(keyword,"stop-color") == 0)
1750 (void) CloneString(&svg_info->stop_color,value);
1753 if (LocaleCompare(keyword,"stroke") == 0)
1755 if (LocaleCompare(value,"currentColor") == 0)
1757 (void) FormatLocaleFile(svg_info->file,
1758 "stroke '%s'\n",color);
1761 if (LocaleCompare(value,"#000000ff") == 0)
1762 (void) FormatLocaleFile(svg_info->file,
1763 "fill '#000000'\n");
1765 (void) FormatLocaleFile(svg_info->file,
1766 "stroke '%s'\n",value);
1769 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1771 (void) FormatLocaleFile(svg_info->file,
1772 "stroke-antialias %d\n",
1773 LocaleCompare(value,"true") == 0);
1776 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1778 (void) FormatLocaleFile(svg_info->file,
1779 "stroke-dasharray %s\n",value);
1782 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1784 (void) FormatLocaleFile(svg_info->file,
1785 "stroke-dashoffset %s\n",
1789 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1791 (void) FormatLocaleFile(svg_info->file,
1792 "stroke-linecap '%s'\n",value);
1795 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1797 (void) FormatLocaleFile(svg_info->file,
1798 "stroke-linejoin '%s'\n",
1802 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1804 (void) FormatLocaleFile(svg_info->file,
1805 "stroke-miterlimit '%s'\n",
1809 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1811 (void) FormatLocaleFile(svg_info->file,
1812 "stroke-opacity '%s'\n",value);
1815 if (LocaleCompare(keyword,"stroke-width") == 0)
1817 (void) FormatLocaleFile(svg_info->file,
1818 "stroke-width %g\n",
1819 GetUserSpaceCoordinateValue(svg_info,1,value));
1827 if (LocaleCompare(keyword,"text-align") == 0)
1829 (void) FormatLocaleFile(svg_info->file,
1830 "text-align '%s'\n",value);
1833 if (LocaleCompare(keyword,"text-anchor") == 0)
1835 (void) FormatLocaleFile(svg_info->file,
1836 "text-anchor '%s'\n",value);
1839 if (LocaleCompare(keyword,"text-decoration") == 0)
1841 if (LocaleCompare(value,"underline") == 0)
1842 (void) FormatLocaleFile(svg_info->file,
1843 "decorate underline\n");
1844 if (LocaleCompare(value,"line-through") == 0)
1845 (void) FormatLocaleFile(svg_info->file,
1846 "decorate line-through\n");
1847 if (LocaleCompare(value,"overline") == 0)
1848 (void) FormatLocaleFile(svg_info->file,
1849 "decorate overline\n");
1852 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1854 (void) FormatLocaleFile(svg_info->file,
1855 "text-antialias %d\n",
1856 LocaleCompare(value,"true") == 0);
1865 for (j=0; tokens[j] != (char *) NULL; j++)
1866 tokens[j]=DestroyString(tokens[j]);
1867 tokens=(char **) RelinquishMagickMemory(tokens);
1875 if (LocaleCompare(keyword,"text-align") == 0)
1877 (void) FormatLocaleFile(svg_info->file,"text-align '%s'\n",
1881 if (LocaleCompare(keyword,"text-anchor") == 0)
1883 (void) FormatLocaleFile(svg_info->file,"text-anchor '%s'\n",
1887 if (LocaleCompare(keyword,"text-decoration") == 0)
1889 if (LocaleCompare(value,"underline") == 0)
1890 (void) FormatLocaleFile(svg_info->file,"decorate underline\n");
1891 if (LocaleCompare(value,"line-through") == 0)
1892 (void) FormatLocaleFile(svg_info->file,
1893 "decorate line-through\n");
1894 if (LocaleCompare(value,"overline") == 0)
1895 (void) FormatLocaleFile(svg_info->file,"decorate overline\n");
1898 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1900 (void) FormatLocaleFile(svg_info->file,"text-antialias %d\n",
1901 LocaleCompare(value,"true") == 0);
1904 if (LocaleCompare(keyword,"transform") == 0)
1911 GetAffineMatrix(&transform);
1912 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1913 tokens=GetTransformTokens(context,value,&number_tokens);
1914 for (j=0; j < (number_tokens-1); j+=2)
1916 keyword=(char *) tokens[j];
1917 value=(char *) tokens[j+1];
1918 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1919 " %s: %s",keyword,value);
1921 GetAffineMatrix(&affine);
1927 if (LocaleCompare(keyword,"matrix") == 0)
1929 p=(const char *) value;
1930 GetMagickToken(p,&p,token);
1931 affine.sx=StringToDouble(value,(char **) NULL);
1932 GetMagickToken(p,&p,token);
1934 GetMagickToken(p,&p,token);
1935 affine.rx=StringToDouble(token,(char **) NULL);
1936 GetMagickToken(p,&p,token);
1938 GetMagickToken(p,&p,token);
1939 affine.ry=StringToDouble(token,(char **) NULL);
1940 GetMagickToken(p,&p,token);
1942 GetMagickToken(p,&p,token);
1943 affine.sy=StringToDouble(token,(char **) NULL);
1944 GetMagickToken(p,&p,token);
1946 GetMagickToken(p,&p,token);
1947 affine.tx=StringToDouble(token,(char **) NULL);
1948 GetMagickToken(p,&p,token);
1950 GetMagickToken(p,&p,token);
1951 affine.ty=StringToDouble(token,(char **) NULL);
1959 if (LocaleCompare(keyword,"rotate") == 0)
1966 p=(const char *) value;
1967 GetMagickToken(p,&p,token);
1968 angle=StringToDouble(value,(char **) NULL);
1969 GetMagickToken(p,&p,token);
1971 GetMagickToken(p,&p,token);
1972 x=StringToDouble(token,(char **) NULL);
1973 GetMagickToken(p,&p,token);
1975 GetMagickToken(p,&p,token);
1976 y=StringToDouble(token,(char **) NULL);
1977 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1978 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1979 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1980 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1983 svg_info->center.x=x;
1984 svg_info->center.y=y;
1992 if (LocaleCompare(keyword,"scale") == 0)
1994 for (p=(const char *) value; *p != '\0'; p++)
1995 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1998 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1999 affine.sy=affine.sx;
2001 affine.sy=GetUserSpaceCoordinateValue(svg_info,-1,
2003 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
2006 if (LocaleCompare(keyword,"skewX") == 0)
2008 affine.sx=svg_info->affine.sx;
2009 affine.ry=tan(DegreesToRadians(fmod(
2010 GetUserSpaceCoordinateValue(svg_info,1,value),
2012 affine.sy=svg_info->affine.sy;
2015 if (LocaleCompare(keyword,"skewY") == 0)
2017 affine.sx=svg_info->affine.sx;
2018 affine.rx=tan(DegreesToRadians(fmod(
2019 GetUserSpaceCoordinateValue(svg_info,-1,value),
2021 affine.sy=svg_info->affine.sy;
2029 if (LocaleCompare(keyword,"translate") == 0)
2031 for (p=(const char *) value; *p != '\0'; p++)
2032 if ((isspace((int) ((unsigned char) *p)) != 0) ||
2035 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
2036 affine.ty=affine.tx;
2038 affine.ty=GetUserSpaceCoordinateValue(svg_info,-1,
2047 transform.sx=affine.sx*current.sx+affine.ry*current.rx;
2048 transform.rx=affine.rx*current.sx+affine.sy*current.rx;
2049 transform.ry=affine.sx*current.ry+affine.ry*current.sy;
2050 transform.sy=affine.rx*current.ry+affine.sy*current.sy;
2051 transform.tx=affine.tx*current.sx+affine.ty*current.ry+
2053 transform.ty=affine.tx*current.rx+affine.ty*current.sy+
2056 (void) FormatLocaleFile(svg_info->file,
2057 "affine %g %g %g %g %g %g\n",transform.sx,transform.rx,
2058 transform.ry,transform.sy,transform.tx,transform.ty);
2059 for (j=0; tokens[j] != (char *) NULL; j++)
2060 tokens[j]=DestroyString(tokens[j]);
2061 tokens=(char **) RelinquishMagickMemory(tokens);
2069 if (LocaleCompare(keyword,"verts") == 0)
2071 (void) CloneString(&svg_info->vertices,value);
2074 if (LocaleCompare(keyword,"viewBox") == 0)
2076 p=(const char *) value;
2077 GetMagickToken(p,&p,token);
2078 svg_info->view_box.x=StringToDouble(token,(char **) NULL);
2079 GetMagickToken(p,&p,token);
2081 GetMagickToken(p,&p,token);
2082 svg_info->view_box.y=StringToDouble(token,(char **) NULL);
2083 GetMagickToken(p,&p,token);
2085 GetMagickToken(p,&p,token);
2086 svg_info->view_box.width=StringToDouble(token,
2088 if (svg_info->bounds.width == 0)
2089 svg_info->bounds.width=svg_info->view_box.width;
2090 GetMagickToken(p,&p,token);
2092 GetMagickToken(p,&p,token);
2093 svg_info->view_box.height=StringToDouble(token,
2095 if (svg_info->bounds.height == 0)
2096 svg_info->bounds.height=svg_info->view_box.height;
2104 if (LocaleCompare(keyword,"width") == 0)
2106 svg_info->bounds.width=
2107 GetUserSpaceCoordinateValue(svg_info,1,value);
2115 if (LocaleCompare(keyword,"x") == 0)
2117 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value);
2120 if (LocaleCompare(keyword,"xlink:href") == 0)
2122 (void) CloneString(&svg_info->url,value);
2125 if (LocaleCompare(keyword,"x1") == 0)
2127 svg_info->segment.x1=
2128 GetUserSpaceCoordinateValue(svg_info,1,value);
2131 if (LocaleCompare(keyword,"x2") == 0)
2133 svg_info->segment.x2=
2134 GetUserSpaceCoordinateValue(svg_info,1,value);
2142 if (LocaleCompare(keyword,"y") == 0)
2144 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value);
2147 if (LocaleCompare(keyword,"y1") == 0)
2149 svg_info->segment.y1=
2150 GetUserSpaceCoordinateValue(svg_info,-1,value);
2153 if (LocaleCompare(keyword,"y2") == 0)
2155 svg_info->segment.y2=
2156 GetUserSpaceCoordinateValue(svg_info,-1,value);
2165 if (LocaleCompare((const char *) name,"svg") == 0)
2167 if (svg_info->document->encoding != (const xmlChar *) NULL)
2168 (void) FormatLocaleFile(svg_info->file,"encoding \"%s\"\n",
2169 (const char *) svg_info->document->encoding);
2170 if (attributes != (const xmlChar **) NULL)
2178 if ((svg_info->view_box.width == 0.0) ||
2179 (svg_info->view_box.height == 0.0))
2180 svg_info->view_box=svg_info->bounds;
2181 svg_info->width=(size_t) floor(svg_info->bounds.width+0.5);
2182 svg_info->height=(size_t) floor(svg_info->bounds.height+0.5);
2183 (void) FormatLocaleFile(svg_info->file,"viewbox 0 0 %.20g %.20g\n",
2184 (double) svg_info->width,(double) svg_info->height);
2185 sx=(double) svg_info->width/svg_info->view_box.width;
2186 sy=(double) svg_info->height/svg_info->view_box.height;
2187 tx=svg_info->view_box.x != 0.0 ? (double) -sx*svg_info->view_box.x :
2189 ty=svg_info->view_box.y != 0.0 ? (double) -sy*svg_info->view_box.y :
2191 (void) FormatLocaleFile(svg_info->file,"affine %g 0 0 %g %g %g\n",
2195 (void) LogMagickEvent(CoderEvent,GetMagickModule()," )");
2196 units=DestroyString(units);
2197 if (color != (char *) NULL)
2198 color=DestroyString(color);
2201 static void SVGEndElement(void *context,const xmlChar *name)
2207 Called when the end of an element has been detected.
2209 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2210 " SAX.endElement(%s)",name);
2211 svg_info=(SVGInfo *) context;
2212 if (strchr((char *) name,':') != (char *) NULL)
2215 Skip over namespace.
2217 for ( ; *name != ':'; name++) ;
2225 if (LocaleCompare((const char *) name,"circle") == 0)
2227 (void) FormatLocaleFile(svg_info->file,"circle %g,%g %g,%g\n",
2228 svg_info->element.cx,svg_info->element.cy,svg_info->element.cx,
2229 svg_info->element.cy+svg_info->element.minor);
2230 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2233 if (LocaleCompare((const char *) name,"clipPath") == 0)
2235 (void) FormatLocaleFile(svg_info->file,"pop clip-path\n");
2243 if (LocaleCompare((const char *) name,"defs") == 0)
2245 (void) FormatLocaleFile(svg_info->file,"pop defs\n");
2248 if (LocaleCompare((const char *) name,"desc") == 0)
2253 if (*svg_info->text == '\0')
2255 (void) fputc('#',svg_info->file);
2256 for (p=svg_info->text; *p != '\0'; p++)
2258 (void) fputc(*p,svg_info->file);
2260 (void) fputc('#',svg_info->file);
2262 (void) fputc('\n',svg_info->file);
2263 *svg_info->text='\0';
2271 if (LocaleCompare((const char *) name,"ellipse") == 0)
2276 angle=svg_info->element.angle;
2277 (void) FormatLocaleFile(svg_info->file,"ellipse %g,%g %g,%g 0,360\n",
2278 svg_info->element.cx,svg_info->element.cy,
2279 angle == 0.0 ? svg_info->element.major : svg_info->element.minor,
2280 angle == 0.0 ? svg_info->element.minor : svg_info->element.major);
2281 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2289 if (LocaleCompare((const char *) name,"g") == 0)
2291 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2299 if (LocaleCompare((const char *) name,"image") == 0)
2301 (void) FormatLocaleFile(svg_info->file,
2302 "image Over %g,%g %g,%g '%s'\n",svg_info->bounds.x,
2303 svg_info->bounds.y,svg_info->bounds.width,svg_info->bounds.height,
2305 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2313 if (LocaleCompare((const char *) name,"line") == 0)
2315 (void) FormatLocaleFile(svg_info->file,"line %g,%g %g,%g\n",
2316 svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
2317 svg_info->segment.y2);
2318 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2321 if (LocaleCompare((const char *) name,"linearGradient") == 0)
2323 (void) FormatLocaleFile(svg_info->file,"pop gradient\n");
2331 if (LocaleCompare((const char *) name,"pattern") == 0)
2333 (void) FormatLocaleFile(svg_info->file,"pop pattern\n");
2336 if (LocaleCompare((const char *) name,"path") == 0)
2338 (void) FormatLocaleFile(svg_info->file,"path '%s'\n",
2339 svg_info->vertices);
2340 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2343 if (LocaleCompare((const char *) name,"polygon") == 0)
2345 (void) FormatLocaleFile(svg_info->file,"polygon %s\n",
2346 svg_info->vertices);
2347 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2350 if (LocaleCompare((const char *) name,"polyline") == 0)
2352 (void) FormatLocaleFile(svg_info->file,"polyline %s\n",
2353 svg_info->vertices);
2354 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2362 if (LocaleCompare((const char *) name,"radialGradient") == 0)
2364 (void) FormatLocaleFile(svg_info->file,"pop gradient\n");
2367 if (LocaleCompare((const char *) name,"rect") == 0)
2369 if ((svg_info->radius.x == 0.0) && (svg_info->radius.y == 0.0))
2371 (void) FormatLocaleFile(svg_info->file,"rectangle %g,%g %g,%g\n",
2372 svg_info->bounds.x,svg_info->bounds.y,
2373 svg_info->bounds.x+svg_info->bounds.width,
2374 svg_info->bounds.y+svg_info->bounds.height);
2375 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2378 if (svg_info->radius.x == 0.0)
2379 svg_info->radius.x=svg_info->radius.y;
2380 if (svg_info->radius.y == 0.0)
2381 svg_info->radius.y=svg_info->radius.x;
2382 (void) FormatLocaleFile(svg_info->file,
2383 "roundRectangle %g,%g %g,%g %g,%g\n",
2384 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.x+
2385 svg_info->bounds.width,svg_info->bounds.y+svg_info->bounds.height,
2386 svg_info->radius.x,svg_info->radius.y);
2387 svg_info->radius.x=0.0;
2388 svg_info->radius.y=0.0;
2389 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2397 if (LocaleCompare((const char *) name,"stop") == 0)
2399 (void) FormatLocaleFile(svg_info->file,"stop-color '%s' %s\n",
2400 svg_info->stop_color,svg_info->offset);
2403 if (LocaleCompare((const char *) name,"svg") == 0)
2405 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2413 if (LocaleCompare((const char *) name,"text") == 0)
2415 if (*svg_info->text != '\0')
2420 text=EscapeString(svg_info->text,'\'');
2421 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
2422 svg_info->bounds.x,svg_info->bounds.y,text);
2423 text=DestroyString(text);
2424 *svg_info->text='\0';
2426 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2429 if (LocaleCompare((const char *) name,"tspan") == 0)
2431 if (*svg_info->text != '\0')
2442 text=EscapeString(svg_info->text,'\'');
2443 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
2444 svg_info->bounds.x,svg_info->bounds.y,text);
2445 text=DestroyString(text);
2446 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
2447 draw_info->pointsize=svg_info->pointsize;
2448 draw_info->text=AcquireString(svg_info->text);
2449 (void) ConcatenateString(&draw_info->text," ");
2450 (void) GetTypeMetrics(svg_info->image,draw_info,&metrics,
2451 svg_info->exception);
2452 svg_info->bounds.x+=metrics.width;
2453 draw_info=DestroyDrawInfo(draw_info);
2454 *svg_info->text='\0';
2456 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2459 if (LocaleCompare((const char *) name,"title") == 0)
2461 if (*svg_info->text == '\0')
2463 (void) CloneString(&svg_info->title,svg_info->text);
2464 *svg_info->text='\0';
2472 *svg_info->text='\0';
2473 (void) ResetMagickMemory(&svg_info->element,0,sizeof(svg_info->element));
2474 (void) ResetMagickMemory(&svg_info->segment,0,sizeof(svg_info->segment));
2478 static void SVGCharacters(void *context,const xmlChar *c,int length)
2493 Receiving some characters from the parser.
2495 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2496 " SAX.characters(%s,%.20g)",c,(double) length);
2497 svg_info=(SVGInfo *) context;
2498 text=(char *) AcquireQuantumMemory(length+1,sizeof(*text));
2499 if (text == (char *) NULL)
2502 for (i=0; i < (ssize_t) length; i++)
2506 if (svg_info->text == (char *) NULL)
2507 svg_info->text=text;
2510 (void) ConcatenateString(&svg_info->text,text);
2511 text=DestroyString(text);
2515 static void SVGReference(void *context,const xmlChar *name)
2524 Called when an entity reference is detected.
2526 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.reference(%s)",
2528 svg_info=(SVGInfo *) context;
2529 parser=svg_info->parser;
2530 if (parser == (xmlParserCtxtPtr) NULL)
2532 if (parser->node == (xmlNodePtr) NULL)
2535 (void) xmlAddChild(parser->node,xmlNewCharRef(svg_info->document,name));
2537 (void) xmlAddChild(parser->node,xmlNewReference(svg_info->document,name));
2540 static void SVGIgnorableWhitespace(void *context,const xmlChar *c,int length)
2546 Receiving some ignorable whitespaces from the parser.
2548 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2549 " SAX.ignorableWhitespace(%.30s, %d)",c,length);
2550 svg_info=(SVGInfo *) context;
2554 static void SVGProcessingInstructions(void *context,const xmlChar *target,
2555 const xmlChar *data)
2561 A processing instruction has been parsed.
2563 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2564 " SAX.processingInstruction(%s, %s)",target,data);
2565 svg_info=(SVGInfo *) context;
2569 static void SVGComment(void *context,const xmlChar *value)
2575 A comment has been parsed.
2577 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.comment(%s)",
2579 svg_info=(SVGInfo *) context;
2580 if (svg_info->comment != (char *) NULL)
2581 (void) ConcatenateString(&svg_info->comment,"\n");
2582 (void) ConcatenateString(&svg_info->comment,(const char *) value);
2585 static void SVGWarning(void *context,const char *format,...)
2589 reason[MaxTextExtent];
2598 Display and format a warning messages, gives file, line, position and
2601 va_start(operands,format);
2602 svg_info=(SVGInfo *) context;
2603 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.warning: ");
2604 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2605 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2606 (void) vsprintf(reason,format,operands);
2608 (void) vsnprintf(reason,MaxTextExtent,format,operands);
2610 message=GetExceptionMessage(errno);
2611 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
2612 DelegateWarning,reason,"`%s`",message);
2613 message=DestroyString(message);
2617 static void SVGError(void *context,const char *format,...)
2621 reason[MaxTextExtent];
2630 Display and format a error formats, gives file, line, position and
2633 va_start(operands,format);
2634 svg_info=(SVGInfo *) context;
2635 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.error: ");
2636 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2637 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2638 (void) vsprintf(reason,format,operands);
2640 (void) vsnprintf(reason,MaxTextExtent,format,operands);
2642 message=GetExceptionMessage(errno);
2643 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),CoderError,
2644 reason,"`%s`",message);
2645 message=DestroyString(message);
2649 static void SVGCDataBlock(void *context,const xmlChar *value,int length)
2661 Called when a pcdata block has been parsed.
2663 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.pcdata(%s, %d)",
2665 svg_info=(SVGInfo *) context;
2666 parser=svg_info->parser;
2667 child=xmlGetLastChild(parser->node);
2668 if ((child != (xmlNodePtr) NULL) && (child->type == XML_CDATA_SECTION_NODE))
2670 xmlTextConcat(child,value,length);
2673 (void) xmlAddChild(parser->node,xmlNewCDataBlock(parser->myDoc,value,length));
2676 static void SVGExternalSubset(void *context,const xmlChar *name,
2677 const xmlChar *external_id,const xmlChar *system_id)
2692 Does this document has an external subset?
2694 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2695 " SAX.externalSubset(%s, %s, %s)",name,
2696 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
2697 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
2698 svg_info=(SVGInfo *) context;
2699 parser=svg_info->parser;
2700 if (((external_id == NULL) && (system_id == NULL)) ||
2701 ((parser->validate == 0) || (parser->wellFormed == 0) ||
2702 (svg_info->document == 0)))
2704 input=SVGResolveEntity(context,external_id,system_id);
2707 (void) xmlNewDtd(svg_info->document,name,external_id,system_id);
2708 parser_context=(*parser);
2709 parser->inputTab=(xmlParserInputPtr *) xmlMalloc(5*sizeof(*parser->inputTab));
2710 if (parser->inputTab == (xmlParserInputPtr *) NULL)
2712 parser->errNo=XML_ERR_NO_MEMORY;
2713 parser->input=parser_context.input;
2714 parser->inputNr=parser_context.inputNr;
2715 parser->inputMax=parser_context.inputMax;
2716 parser->inputTab=parser_context.inputTab;
2722 xmlPushInput(parser,input);
2723 (void) xmlSwitchEncoding(parser,xmlDetectCharEncoding(parser->input->cur,4));
2724 if (input->filename == (char *) NULL)
2725 input->filename=(char *) xmlStrdup(system_id);
2728 input->base=parser->input->cur;
2729 input->cur=parser->input->cur;
2731 xmlParseExternalSubset(parser,external_id,system_id);
2732 while (parser->inputNr > 1)
2733 (void) xmlPopInput(parser);
2734 xmlFreeInputStream(parser->input);
2735 xmlFree(parser->inputTab);
2736 parser->input=parser_context.input;
2737 parser->inputNr=parser_context.inputNr;
2738 parser->inputMax=parser_context.inputMax;
2739 parser->inputTab=parser_context.inputTab;
2742 #if defined(__cplusplus) || defined(c_plusplus)
2747 Static declarations.
2750 SVGDensityGeometry[] = "90.0x90.0";
2753 static Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
2756 filename[MaxTextExtent];
2775 message[MaxTextExtent];
2786 assert(image_info != (const ImageInfo *) NULL);
2787 assert(image_info->signature == MagickSignature);
2788 assert(exception != (ExceptionInfo *) NULL);
2789 if (image_info->debug != MagickFalse)
2790 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2791 image_info->filename);
2792 assert(exception->signature == MagickSignature);
2793 image=AcquireImage(image_info,exception);
2794 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2795 if (status == MagickFalse)
2797 image=DestroyImageList(image);
2798 return((Image *) NULL);
2800 if ((image->resolution.x == 0.0) || (image->resolution.y == 0.0))
2808 flags=ParseGeometry(SVGDensityGeometry,&geometry_info);
2809 image->resolution.x=geometry_info.rho;
2810 image->resolution.y=geometry_info.sigma;
2811 if ((flags & SigmaValue) == 0)
2812 image->resolution.y=image->resolution.x;
2814 if (LocaleCompare(image_info->magick,"MSVG") != 0)
2819 delegate_info=GetDelegateInfo("svg:decode",(char *) NULL,exception);
2820 if (delegate_info != (const DelegateInfo *) NULL)
2823 background[MaxTextExtent],
2824 command[MaxTextExtent],
2825 density[MaxTextExtent],
2826 filename[MaxTextExtent],
2827 opacity[MaxTextExtent],
2828 unique[MaxTextExtent];
2834 Our best hope for compliance to the SVG standard.
2836 (void) AcquireUniqueFilename(filename);
2837 (void) AcquireUniqueFilename(unique);
2838 (void) FormatLocaleString(density,MaxTextExtent,"%.20g,%.20g",
2839 image->resolution.x,image->resolution.y);
2840 (void) FormatLocaleString(background,MaxTextExtent,
2841 "rgb(%.20g%%,%.20g%%,%.20g%%)",
2842 100.0*QuantumScale*image->background_color.red,
2843 100.0*QuantumScale*image->background_color.green,
2844 100.0*QuantumScale*image->background_color.blue);
2845 (void) FormatLocaleString(opacity,MaxTextExtent,"%.20g",
2846 QuantumScale*image->background_color.alpha);
2847 (void) FormatLocaleString(command,MaxTextExtent,
2848 GetDelegateCommands(delegate_info),image->filename,filename,density,
2849 background,opacity,unique);
2850 status=SystemCommand(MagickFalse,image_info->verbose,command,
2852 (void) RelinquishUniqueFileResource(unique);
2858 read_info=CloneImageInfo(image_info);
2859 (void) CopyMagickString(read_info->filename,filename,
2861 image=ReadImage(read_info,exception);
2862 read_info=DestroyImageInfo(read_info);
2863 (void) RelinquishUniqueFileResource(filename);
2864 if (image != (Image *) NULL)
2867 (void) RelinquishUniqueFileResource(filename);
2870 #if defined(MAGICKCORE_RSVG_DELEGATE)
2871 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2881 register unsigned char
2894 register const guchar
2917 svg_handle=rsvg_handle_new();
2918 if (svg_handle == (RsvgHandle *) NULL)
2919 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2920 rsvg_handle_set_base_uri(svg_handle,image_info->filename);
2921 rsvg_handle_set_dpi_x_y(svg_handle,image->resolution.x,
2922 image->resolution.y);
2923 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
2925 error=(GError *) NULL;
2926 (void) rsvg_handle_write(svg_handle,message,n,&error);
2927 if (error != (GError *) NULL)
2928 g_error_free(error);
2930 error=(GError *) NULL;
2931 rsvg_handle_close(svg_handle,&error);
2932 if (error != (GError *) NULL)
2933 g_error_free(error);
2934 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2935 rsvg_handle_get_dimensions(svg_handle,&dimension_info);
2936 image->columns=image->resolution.x*dimension_info.width/72.0;
2937 image->rows=image->resolution.y*dimension_info.height/72.0;
2938 pixel_info=(MemoryInfo *) NULL;
2940 pixel_buffer=rsvg_handle_get_pixbuf(svg_handle);
2941 rsvg_handle_free(svg_handle);
2942 image->columns=gdk_pixbuf_get_width(pixel_buffer);
2943 image->rows=gdk_pixbuf_get_height(pixel_buffer);
2945 image->alpha_trait=BlendPixelTrait;
2946 SetImageProperty(image,"svg:base-uri",
2947 rsvg_handle_get_base_uri(svg_handle),exception);
2948 if ((image->columns == 0) || (image->rows == 0))
2950 #if !defined(MAGICKCORE_CAIRO_DELEGATE)
2951 g_object_unref(G_OBJECT(pixel_buffer));
2953 g_object_unref(svg_handle);
2954 ThrowReaderException(MissingDelegateError,
2955 "NoDecodeDelegateForThisImageFormat");
2957 if (image_info->ping == MagickFalse)
2962 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2963 stride=4*image->columns;
2964 #if defined(MAGICKCORE_PANGOCAIRO_DELEGATE)
2965 stride=(size_t) cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32,
2968 pixel_info=AcquireVirtualMemory(stride,image->rows*sizeof(*pixels));
2969 if (pixel_info == (MemoryInfo *) NULL)
2971 g_object_unref(svg_handle);
2972 ThrowReaderException(ResourceLimitError,
2973 "MemoryAllocationFailed");
2975 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
2977 (void) SetImageBackgroundColor(image,exception);
2978 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2979 cairo_surface=cairo_image_surface_create_for_data(pixels,
2980 CAIRO_FORMAT_ARGB32,image->columns,image->rows,stride);
2981 if (cairo_surface == (cairo_surface_t *) NULL)
2983 pixel_info=RelinquishVirtualMemory(pixel_info);
2984 g_object_unref(svg_handle);
2985 ThrowReaderException(ResourceLimitError,
2986 "MemoryAllocationFailed");
2988 cairo_image=cairo_create(cairo_surface);
2989 cairo_set_operator(cairo_image,CAIRO_OPERATOR_CLEAR);
2990 cairo_paint(cairo_image);
2991 cairo_set_operator(cairo_image,CAIRO_OPERATOR_OVER);
2992 cairo_scale(cairo_image,image->resolution.x/72.0,
2993 image->resolution.y/72.0);
2994 rsvg_handle_render_cairo(svg_handle,cairo_image);
2995 cairo_destroy(cairo_image);
2996 cairo_surface_destroy(cairo_surface);
2997 g_object_unref(svg_handle);
3000 p=gdk_pixbuf_get_pixels(pixel_buffer);
3002 GetPixelInfo(image,&fill_color);
3003 for (y=0; y < (ssize_t) image->rows; y++)
3005 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3006 if (q == (Quantum *) NULL)
3008 for (x=0; x < (ssize_t) image->columns; x++)
3010 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3011 fill_color.blue=ScaleCharToQuantum(*p++);
3012 fill_color.green=ScaleCharToQuantum(*p++);
3013 fill_color.red=ScaleCharToQuantum(*p++);
3015 fill_color.red=ScaleCharToQuantum(*p++);
3016 fill_color.green=ScaleCharToQuantum(*p++);
3017 fill_color.blue=ScaleCharToQuantum(*p++);
3019 fill_color.alpha=ScaleCharToQuantum(*p++);
3020 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3025 gamma=QuantumScale*fill_color.alpha;
3026 gamma=PerceptibleReciprocal(gamma);
3027 fill_color.blue*=gamma;
3028 fill_color.green*=gamma;
3029 fill_color.red*=gamma;
3032 CompositePixelOver(image,&fill_color,fill_color.alpha,q,(double)
3033 GetPixelAlpha(image,q),q);
3034 q+=GetPixelChannels(image);
3036 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3038 if (image->previous == (Image *) NULL)
3040 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
3042 if (status == MagickFalse)
3047 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3048 if (pixel_info != (MemoryInfo *) NULL)
3049 pixel_info=RelinquishVirtualMemory(pixel_info);
3051 g_object_unref(G_OBJECT(pixel_buffer));
3053 (void) CloseBlob(image);
3054 return(GetFirstImageInList(image));
3062 unique_file=AcquireUniqueFileResource(filename);
3063 if (unique_file != -1)
3064 file=fdopen(unique_file,"w");
3065 if ((unique_file == -1) || (file == (FILE *) NULL))
3067 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
3068 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
3070 image=DestroyImageList(image);
3071 return((Image *) NULL);
3076 svg_info=AcquireSVGInfo();
3077 if (svg_info == (SVGInfo *) NULL)
3078 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3079 svg_info->file=file;
3080 svg_info->exception=exception;
3081 svg_info->image=image;
3082 svg_info->image_info=image_info;
3083 svg_info->bounds.width=image->columns;
3084 svg_info->bounds.height=image->rows;
3085 if (image_info->size != (char *) NULL)
3086 (void) CloneString(&svg_info->size,image_info->size);
3087 if (image->debug != MagickFalse)
3088 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"begin SAX");
3089 (void) xmlSubstituteEntitiesDefault(1);
3090 (void) ResetMagickMemory(&sax_modules,0,sizeof(sax_modules));
3091 sax_modules.internalSubset=SVGInternalSubset;
3092 sax_modules.isStandalone=SVGIsStandalone;
3093 sax_modules.hasInternalSubset=SVGHasInternalSubset;
3094 sax_modules.hasExternalSubset=SVGHasExternalSubset;
3095 sax_modules.resolveEntity=SVGResolveEntity;
3096 sax_modules.getEntity=SVGGetEntity;
3097 sax_modules.entityDecl=SVGEntityDeclaration;
3098 sax_modules.notationDecl=SVGNotationDeclaration;
3099 sax_modules.attributeDecl=SVGAttributeDeclaration;
3100 sax_modules.elementDecl=SVGElementDeclaration;
3101 sax_modules.unparsedEntityDecl=SVGUnparsedEntityDeclaration;
3102 sax_modules.setDocumentLocator=SVGSetDocumentLocator;
3103 sax_modules.startDocument=SVGStartDocument;
3104 sax_modules.endDocument=SVGEndDocument;
3105 sax_modules.startElement=SVGStartElement;
3106 sax_modules.endElement=SVGEndElement;
3107 sax_modules.reference=SVGReference;
3108 sax_modules.characters=SVGCharacters;
3109 sax_modules.ignorableWhitespace=SVGIgnorableWhitespace;
3110 sax_modules.processingInstruction=SVGProcessingInstructions;
3111 sax_modules.comment=SVGComment;
3112 sax_modules.warning=SVGWarning;
3113 sax_modules.error=SVGError;
3114 sax_modules.fatalError=SVGError;
3115 sax_modules.getParameterEntity=SVGGetParameterEntity;
3116 sax_modules.cdataBlock=SVGCDataBlock;
3117 sax_modules.externalSubset=SVGExternalSubset;
3118 sax_handler=(&sax_modules);
3119 n=ReadBlob(image,MaxTextExtent,message);
3122 svg_info->parser=xmlCreatePushParserCtxt(sax_handler,svg_info,(char *)
3123 message,n,image->filename);
3124 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
3126 status=xmlParseChunk(svg_info->parser,(char *) message,(int) n,0);
3131 (void) xmlParseChunk(svg_info->parser,(char *) message,0,1);
3132 xmlFreeParserCtxt(svg_info->parser);
3133 if (image->debug != MagickFalse)
3134 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"end SAX");
3135 (void) fclose(file);
3136 (void) CloseBlob(image);
3137 image->columns=svg_info->width;
3138 image->rows=svg_info->height;
3139 if (exception->severity >= ErrorException)
3141 image=DestroyImage(image);
3142 return((Image *) NULL);
3144 if (image_info->ping == MagickFalse)
3152 image=DestroyImage(image);
3153 image=(Image *) NULL;
3154 read_info=CloneImageInfo(image_info);
3155 SetImageInfoBlob(read_info,(void *) NULL,0);
3156 if (read_info->density != (char *) NULL)
3157 read_info->density=DestroyString(read_info->density);
3158 (void) FormatLocaleString(read_info->filename,MaxTextExtent,"mvg:%s",
3160 image=ReadImage(read_info,exception);
3161 read_info=DestroyImageInfo(read_info);
3162 if (image != (Image *) NULL)
3163 (void) CopyMagickString(image->filename,image_info->filename,
3167 Relinquish resources.
3169 if (image != (Image *) NULL)
3171 if (svg_info->title != (char *) NULL)
3172 (void) SetImageProperty(image,"svg:title",svg_info->title,exception);
3173 if (svg_info->comment != (char *) NULL)
3174 (void) SetImageProperty(image,"svg:comment",svg_info->comment,
3177 svg_info=DestroySVGInfo(svg_info);
3178 (void) RelinquishUniqueFileResource(filename);
3179 return(GetFirstImageInList(image));
3184 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3188 % R e g i s t e r S V G I m a g e %
3192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3194 % RegisterSVGImage() adds attributes for the SVG image format to
3195 % the list of supported formats. The attributes include the image format
3196 % tag, a method to read and/or write the format, whether the format
3197 % supports the saving of more than one frame to the same file or blob,
3198 % whether the format supports native in-memory I/O, and a brief
3199 % description of the format.
3201 % The format of the RegisterSVGImage method is:
3203 % size_t RegisterSVGImage(void)
3206 ModuleExport size_t RegisterSVGImage(void)
3209 version[MaxTextExtent];
3215 #if defined(LIBXML_DOTTED_VERSION)
3216 (void) CopyMagickString(version,"XML " LIBXML_DOTTED_VERSION,MaxTextExtent);
3218 #if defined(MAGICKCORE_RSVG_DELEGATE)
3219 #if !GLIB_CHECK_VERSION(2,35,0)
3222 #if defined(MAGICKCORE_XML_DELEGATE)
3225 (void) FormatLocaleString(version,MaxTextExtent,"RSVG %d.%d.%d",
3226 LIBRSVG_MAJOR_VERSION,LIBRSVG_MINOR_VERSION,LIBRSVG_MICRO_VERSION);
3228 entry=SetMagickInfo("SVG");
3229 #if defined(MAGICKCORE_XML_DELEGATE)
3230 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3232 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3233 entry->blob_support=MagickFalse;
3234 entry->seekable_stream=MagickFalse;
3235 entry->description=ConstantString("Scalable Vector Graphics");
3236 if (*version != '\0')
3237 entry->version=ConstantString(version);
3238 entry->magick=(IsImageFormatHandler *) IsSVG;
3239 entry->module=ConstantString("SVG");
3240 (void) RegisterMagickInfo(entry);
3241 entry=SetMagickInfo("SVGZ");
3242 #if defined(MAGICKCORE_XML_DELEGATE)
3243 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3245 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3246 entry->blob_support=MagickFalse;
3247 entry->seekable_stream=MagickFalse;
3248 entry->description=ConstantString("Compressed Scalable Vector Graphics");
3249 if (*version != '\0')
3250 entry->version=ConstantString(version);
3251 entry->magick=(IsImageFormatHandler *) IsSVG;
3252 entry->module=ConstantString("SVG");
3253 (void) RegisterMagickInfo(entry);
3254 entry=SetMagickInfo("MSVG");
3255 #if defined(MAGICKCORE_XML_DELEGATE)
3256 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3258 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3259 entry->blob_support=MagickFalse;
3260 entry->seekable_stream=MagickFalse;
3261 entry->description=ConstantString("ImageMagick's own SVG internal renderer");
3262 entry->magick=(IsImageFormatHandler *) IsSVG;
3263 entry->module=ConstantString("SVG");
3264 (void) RegisterMagickInfo(entry);
3265 return(MagickImageCoderSignature);
3269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3273 % U n r e g i s t e r S V G I m a g e %
3277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3279 % UnregisterSVGImage() removes format registrations made by the
3280 % SVG module from the list of supported formats.
3282 % The format of the UnregisterSVGImage method is:
3284 % UnregisterSVGImage(void)
3287 ModuleExport void UnregisterSVGImage(void)
3289 (void) UnregisterMagickInfo("SVGZ");
3290 (void) UnregisterMagickInfo("SVG");
3291 (void) UnregisterMagickInfo("MSVG");
3292 #if defined(MAGICKCORE_XML_DELEGATE)
3298 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3302 % W r i t e S V G I m a g e %
3306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3308 % WriteSVGImage() writes a image in the SVG - XML based W3C standard
3311 % The format of the WriteSVGImage method is:
3313 % MagickBooleanType WriteSVGImage(const ImageInfo *image_info,
3314 % Image *image,ExceptionInfo *exception)
3316 % A description of each parameter follows.
3318 % o image_info: the image info.
3320 % o image: The image.
3322 % o exception: return any errors or warnings in this structure.
3326 static void AffineToTransform(Image *image,AffineMatrix *affine)
3329 transform[MaxTextExtent];
3331 if ((fabs(affine->tx) < MagickEpsilon) && (fabs(affine->ty) < MagickEpsilon))
3333 if ((fabs(affine->rx) < MagickEpsilon) &&
3334 (fabs(affine->ry) < MagickEpsilon))
3336 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3337 (fabs(affine->sy-1.0) < MagickEpsilon))
3339 (void) WriteBlobString(image,"\">\n");
3342 (void) FormatLocaleString(transform,MaxTextExtent,
3343 "\" transform=\"scale(%g,%g)\">\n",affine->sx,affine->sy);
3344 (void) WriteBlobString(image,transform);
3349 if ((fabs(affine->sx-affine->sy) < MagickEpsilon) &&
3350 (fabs(affine->rx+affine->ry) < MagickEpsilon) &&
3351 (fabs(affine->sx*affine->sx+affine->rx*affine->rx-1.0) <
3357 theta=(180.0/MagickPI)*atan2(affine->rx,affine->sx);
3358 (void) FormatLocaleString(transform,MaxTextExtent,
3359 "\" transform=\"rotate(%g)\">\n",theta);
3360 (void) WriteBlobString(image,transform);
3367 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3368 (fabs(affine->rx) < MagickEpsilon) &&
3369 (fabs(affine->ry) < MagickEpsilon) &&
3370 (fabs(affine->sy-1.0) < MagickEpsilon))
3372 (void) FormatLocaleString(transform,MaxTextExtent,
3373 "\" transform=\"translate(%g,%g)\">\n",affine->tx,affine->ty);
3374 (void) WriteBlobString(image,transform);
3378 (void) FormatLocaleString(transform,MaxTextExtent,
3379 "\" transform=\"matrix(%g %g %g %g %g %g)\">\n",
3380 affine->sx,affine->rx,affine->ry,affine->sy,affine->tx,affine->ty);
3381 (void) WriteBlobString(image,transform);
3384 static MagickBooleanType IsPoint(const char *point)
3392 value=strtol(point,&p,10);
3394 return(p != point ? MagickTrue : MagickFalse);
3397 static MagickBooleanType TraceSVGImage(Image *image,ExceptionInfo *exception)
3402 register const Quantum
3408 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
3413 at_fitting_opts_type
3432 Trace image and write as SVG.
3434 fitting_options=at_fitting_opts_new();
3435 output_options=at_output_opts_new();
3436 type=GetImageType(image,exception);
3438 if ((type == BilevelType) || (type == GrayscaleType))
3440 trace=at_bitmap_new(image->columns,image->rows,number_planes);
3442 for (y=0; y < (ssize_t) image->rows; y++)
3444 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3445 if (p == (const Quantum *) NULL)
3447 for (x=0; x < (ssize_t) image->columns; x++)
3449 trace->bitmap[i++]=GetPixelRed(image,p);
3450 if (number_planes == 3)
3452 trace->bitmap[i++]=GetPixelGreen(image,p);
3453 trace->bitmap[i++]=GetPixelBlue(image,p);
3455 p+=GetPixelChannels(image);
3458 splines=at_splines_new_full(trace,fitting_options,NULL,NULL,NULL,NULL,NULL,
3460 at_splines_write(at_output_get_handler_by_suffix((char *) "svg"),
3461 GetBlobFileHandle(image),image->filename,output_options,splines,NULL,
3466 at_splines_free(splines);
3467 at_bitmap_free(trace);
3468 at_output_opts_free(output_options);
3469 at_fitting_opts_free(fitting_options);
3474 message[MaxTextExtent],
3475 tuple[MaxTextExtent];
3480 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3481 (void) WriteBlobString(image,
3482 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3483 (void) WriteBlobString(image,
3484 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3485 (void) FormatLocaleString(message,MaxTextExtent,
3486 "<svg width=\"%.20g\" height=\"%.20g\">\n",(double) image->columns,
3487 (double) image->rows);
3488 (void) WriteBlobString(image,message);
3489 GetPixelInfo(image,&pixel);
3490 for (y=0; y < (ssize_t) image->rows; y++)
3492 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3493 if (p == (const Quantum *) NULL)
3495 for (x=0; x < (ssize_t) image->columns; x++)
3497 GetPixelInfoPixel(image,p,&pixel);
3498 (void) QueryColorname(image,&pixel,SVGCompliance,tuple,exception);
3499 (void) FormatLocaleString(message,MaxTextExtent,
3500 " <circle cx=\"%.20g\" cy=\"%.20g\" r=\"1\" fill=\"%s\"/>\n",
3501 (double) x,(double) y,tuple);
3502 (void) WriteBlobString(image,message);
3503 p+=GetPixelChannels(image);
3506 (void) WriteBlobString(image,"</svg>\n");
3512 static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
3513 ExceptionInfo *exception)
3515 #define BezierQuantum 200
3521 keyword[MaxTextExtent],
3522 message[MaxTextExtent],
3523 name[MaxTextExtent],
3525 type[MaxTextExtent];
3567 Open output image file.
3569 assert(image_info != (const ImageInfo *) NULL);
3570 assert(image_info->signature == MagickSignature);
3571 assert(image != (Image *) NULL);
3572 assert(image->signature == MagickSignature);
3573 if (image->debug != MagickFalse)
3574 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3575 assert(exception != (ExceptionInfo *) NULL);
3576 assert(exception->signature == MagickSignature);
3577 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
3578 if (status == MagickFalse)
3580 value=GetImageArtifact(image,"SVG");
3581 if (value != (char *) NULL)
3583 (void) WriteBlobString(image,value);
3584 (void) CloseBlob(image);
3587 value=GetImageArtifact(image,"MVG");
3588 if (value == (char *) NULL)
3589 return(TraceSVGImage(image,exception));
3593 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3594 (void) WriteBlobString(image,
3595 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3596 (void) WriteBlobString(image,
3597 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3598 (void) FormatLocaleString(message,MaxTextExtent,
3599 "<svg width=\"%.20g\" height=\"%.20g\">\n",(double) image->columns,(double)
3601 (void) WriteBlobString(image,message);
3603 Allocate primitive info memory.
3606 primitive_info=(PrimitiveInfo *) AcquireQuantumMemory(number_points,
3607 sizeof(*primitive_info));
3608 if (primitive_info == (PrimitiveInfo *) NULL)
3609 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3610 GetAffineMatrix(&affine);
3611 token=AcquireString(value);
3615 for (q=(const char *) value; *q != '\0'; )
3618 Interpret graphic primitive.
3620 GetMagickToken(q,&q,keyword);
3621 if (*keyword == '\0')
3623 if (*keyword == '#')
3628 if (active != MagickFalse)
3630 AffineToTransform(image,&affine);
3633 (void) WriteBlobString(image,"<desc>");
3634 (void) WriteBlobString(image,keyword+1);
3635 for ( ; (*q != '\n') && (*q != '\0'); q++)
3638 case '<': (void) WriteBlobString(image,"<"); break;
3639 case '>': (void) WriteBlobString(image,">"); break;
3640 case '&': (void) WriteBlobString(image,"&"); break;
3641 default: (void) WriteBlobByte(image,*q); break;
3643 (void) WriteBlobString(image,"</desc>\n");
3646 primitive_type=UndefinedPrimitive;
3654 if (LocaleCompare("affine",keyword) == 0)
3656 GetMagickToken(q,&q,token);
3657 affine.sx=StringToDouble(token,(char **) NULL);
3658 GetMagickToken(q,&q,token);
3660 GetMagickToken(q,&q,token);
3661 affine.rx=StringToDouble(token,(char **) NULL);
3662 GetMagickToken(q,&q,token);
3664 GetMagickToken(q,&q,token);
3665 affine.ry=StringToDouble(token,(char **) NULL);
3666 GetMagickToken(q,&q,token);
3668 GetMagickToken(q,&q,token);
3669 affine.sy=StringToDouble(token,(char **) NULL);
3670 GetMagickToken(q,&q,token);
3672 GetMagickToken(q,&q,token);
3673 affine.tx=StringToDouble(token,(char **) NULL);
3674 GetMagickToken(q,&q,token);
3676 GetMagickToken(q,&q,token);
3677 affine.ty=StringToDouble(token,(char **) NULL);
3680 if (LocaleCompare("angle",keyword) == 0)
3682 GetMagickToken(q,&q,token);
3683 affine.rx=StringToDouble(token,(char **) NULL);
3684 affine.ry=StringToDouble(token,(char **) NULL);
3687 if (LocaleCompare("arc",keyword) == 0)
3689 primitive_type=ArcPrimitive;
3698 if (LocaleCompare("bezier",keyword) == 0)
3700 primitive_type=BezierPrimitive;
3709 if (LocaleCompare("clip-path",keyword) == 0)
3711 GetMagickToken(q,&q,token);
3712 (void) FormatLocaleString(message,MaxTextExtent,
3713 "clip-path:url(#%s);",token);
3714 (void) WriteBlobString(image,message);
3717 if (LocaleCompare("clip-rule",keyword) == 0)
3719 GetMagickToken(q,&q,token);
3720 (void) FormatLocaleString(message,MaxTextExtent,
3721 "clip-rule:%s;",token);
3722 (void) WriteBlobString(image,message);
3725 if (LocaleCompare("clip-units",keyword) == 0)
3727 GetMagickToken(q,&q,token);
3728 (void) FormatLocaleString(message,MaxTextExtent,
3729 "clipPathUnits=%s;",token);
3730 (void) WriteBlobString(image,message);
3733 if (LocaleCompare("circle",keyword) == 0)
3735 primitive_type=CirclePrimitive;
3738 if (LocaleCompare("color",keyword) == 0)
3740 primitive_type=ColorPrimitive;
3749 if (LocaleCompare("decorate",keyword) == 0)
3751 GetMagickToken(q,&q,token);
3752 (void) FormatLocaleString(message,MaxTextExtent,
3753 "text-decoration:%s;",token);
3754 (void) WriteBlobString(image,message);
3763 if (LocaleCompare("ellipse",keyword) == 0)
3765 primitive_type=EllipsePrimitive;
3774 if (LocaleCompare("fill",keyword) == 0)
3776 GetMagickToken(q,&q,token);
3777 (void) FormatLocaleString(message,MaxTextExtent,"fill:%s;",
3779 (void) WriteBlobString(image,message);
3782 if (LocaleCompare("fill-rule",keyword) == 0)
3784 GetMagickToken(q,&q,token);
3785 (void) FormatLocaleString(message,MaxTextExtent,
3786 "fill-rule:%s;",token);
3787 (void) WriteBlobString(image,message);
3790 if (LocaleCompare("fill-alpha",keyword) == 0)
3792 GetMagickToken(q,&q,token);
3793 (void) FormatLocaleString(message,MaxTextExtent,
3794 "fill-alpha:%s;",token);
3795 (void) WriteBlobString(image,message);
3798 if (LocaleCompare("font-family",keyword) == 0)
3800 GetMagickToken(q,&q,token);
3801 (void) FormatLocaleString(message,MaxTextExtent,
3802 "font-family:%s;",token);
3803 (void) WriteBlobString(image,message);
3806 if (LocaleCompare("font-stretch",keyword) == 0)
3808 GetMagickToken(q,&q,token);
3809 (void) FormatLocaleString(message,MaxTextExtent,
3810 "font-stretch:%s;",token);
3811 (void) WriteBlobString(image,message);
3814 if (LocaleCompare("font-style",keyword) == 0)
3816 GetMagickToken(q,&q,token);
3817 (void) FormatLocaleString(message,MaxTextExtent,
3818 "font-style:%s;",token);
3819 (void) WriteBlobString(image,message);
3822 if (LocaleCompare("font-size",keyword) == 0)
3824 GetMagickToken(q,&q,token);
3825 (void) FormatLocaleString(message,MaxTextExtent,
3826 "font-size:%s;",token);
3827 (void) WriteBlobString(image,message);
3830 if (LocaleCompare("font-weight",keyword) == 0)
3832 GetMagickToken(q,&q,token);
3833 (void) FormatLocaleString(message,MaxTextExtent,
3834 "font-weight:%s;",token);
3835 (void) WriteBlobString(image,message);
3844 if (LocaleCompare("gradient-units",keyword) == 0)
3846 GetMagickToken(q,&q,token);
3849 if (LocaleCompare("text-align",keyword) == 0)
3851 GetMagickToken(q,&q,token);
3852 (void) FormatLocaleString(message,MaxTextExtent,
3853 "text-align %s ",token);
3854 (void) WriteBlobString(image,message);
3857 if (LocaleCompare("text-anchor",keyword) == 0)
3859 GetMagickToken(q,&q,token);
3860 (void) FormatLocaleString(message,MaxTextExtent,
3861 "text-anchor %s ",token);
3862 (void) WriteBlobString(image,message);
3871 if (LocaleCompare("image",keyword) == 0)
3873 GetMagickToken(q,&q,token);
3874 primitive_type=ImagePrimitive;
3883 if (LocaleCompare("line",keyword) == 0)
3885 primitive_type=LinePrimitive;
3894 if (LocaleCompare("matte",keyword) == 0)
3896 primitive_type=MattePrimitive;
3905 if (LocaleCompare("opacity",keyword) == 0)
3907 GetMagickToken(q,&q,token);
3908 (void) FormatLocaleString(message,MaxTextExtent,"opacity %s ",
3910 (void) WriteBlobString(image,message);
3919 if (LocaleCompare("path",keyword) == 0)
3921 primitive_type=PathPrimitive;
3924 if (LocaleCompare("point",keyword) == 0)
3926 primitive_type=PointPrimitive;
3929 if (LocaleCompare("polyline",keyword) == 0)
3931 primitive_type=PolylinePrimitive;
3934 if (LocaleCompare("polygon",keyword) == 0)
3936 primitive_type=PolygonPrimitive;
3939 if (LocaleCompare("pop",keyword) == 0)
3941 GetMagickToken(q,&q,token);
3942 if (LocaleCompare("clip-path",token) == 0)
3944 (void) WriteBlobString(image,"</clipPath>\n");
3947 if (LocaleCompare("defs",token) == 0)
3949 (void) WriteBlobString(image,"</defs>\n");
3952 if (LocaleCompare("gradient",token) == 0)
3954 (void) FormatLocaleString(message,MaxTextExtent,
3955 "</%sGradient>\n",type);
3956 (void) WriteBlobString(image,message);
3959 if (LocaleCompare("graphic-context",token) == 0)
3963 ThrowWriterException(DrawError,
3964 "UnbalancedGraphicContextPushPop");
3965 (void) WriteBlobString(image,"</g>\n");
3967 if (LocaleCompare("pattern",token) == 0)
3969 (void) WriteBlobString(image,"</pattern>\n");
3972 if (LocaleCompare("defs",token) == 0)
3973 (void) WriteBlobString(image,"</g>\n");
3976 if (LocaleCompare("push",keyword) == 0)
3978 GetMagickToken(q,&q,token);
3979 if (LocaleCompare("clip-path",token) == 0)
3981 GetMagickToken(q,&q,token);
3982 (void) FormatLocaleString(message,MaxTextExtent,
3983 "<clipPath id=\"%s\">\n",token);
3984 (void) WriteBlobString(image,message);
3987 if (LocaleCompare("defs",token) == 0)
3989 (void) WriteBlobString(image,"<defs>\n");
3992 if (LocaleCompare("gradient",token) == 0)
3994 GetMagickToken(q,&q,token);
3995 (void) CopyMagickString(name,token,MaxTextExtent);
3996 GetMagickToken(q,&q,token);
3997 (void) CopyMagickString(type,token,MaxTextExtent);
3998 GetMagickToken(q,&q,token);
3999 svg_info.segment.x1=StringToDouble(token,(char **) NULL);
4000 svg_info.element.cx=StringToDouble(token,(char **) NULL);
4001 GetMagickToken(q,&q,token);
4003 GetMagickToken(q,&q,token);
4004 svg_info.segment.y1=StringToDouble(token,(char **) NULL);
4005 svg_info.element.cy=StringToDouble(token,(char **) NULL);
4006 GetMagickToken(q,&q,token);
4008 GetMagickToken(q,&q,token);
4009 svg_info.segment.x2=StringToDouble(token,(char **) NULL);
4010 svg_info.element.major=StringToDouble(token,
4012 GetMagickToken(q,&q,token);
4014 GetMagickToken(q,&q,token);
4015 svg_info.segment.y2=StringToDouble(token,(char **) NULL);
4016 svg_info.element.minor=StringToDouble(token,
4018 (void) FormatLocaleString(message,MaxTextExtent,
4019 "<%sGradient id=\"%s\" x1=\"%g\" y1=\"%g\" x2=\"%g\" "
4020 "y2=\"%g\">\n",type,name,svg_info.segment.x1,
4021 svg_info.segment.y1,svg_info.segment.x2,svg_info.segment.y2);
4022 if (LocaleCompare(type,"radial") == 0)
4024 GetMagickToken(q,&q,token);
4026 GetMagickToken(q,&q,token);
4027 svg_info.element.angle=StringToDouble(token,
4029 (void) FormatLocaleString(message,MaxTextExtent,
4030 "<%sGradient id=\"%s\" cx=\"%g\" cy=\"%g\" r=\"%g\" "
4031 "fx=\"%g\" fy=\"%g\">\n",type,name,
4032 svg_info.element.cx,svg_info.element.cy,
4033 svg_info.element.angle,svg_info.element.major,
4034 svg_info.element.minor);
4036 (void) WriteBlobString(image,message);
4039 if (LocaleCompare("graphic-context",token) == 0)
4044 AffineToTransform(image,&affine);
4047 (void) WriteBlobString(image,"<g style=\"");
4050 if (LocaleCompare("pattern",token) == 0)
4052 GetMagickToken(q,&q,token);
4053 (void) CopyMagickString(name,token,MaxTextExtent);
4054 GetMagickToken(q,&q,token);
4055 svg_info.bounds.x=StringToDouble(token,(char **) NULL);
4056 GetMagickToken(q,&q,token);
4058 GetMagickToken(q,&q,token);
4059 svg_info.bounds.y=StringToDouble(token,(char **) NULL);
4060 GetMagickToken(q,&q,token);
4062 GetMagickToken(q,&q,token);
4063 svg_info.bounds.width=StringToDouble(token,
4065 GetMagickToken(q,&q,token);
4067 GetMagickToken(q,&q,token);
4068 svg_info.bounds.height=StringToDouble(token,
4070 (void) FormatLocaleString(message,MaxTextExtent,
4071 "<pattern id=\"%s\" x=\"%g\" y=\"%g\" width=\"%g\" "
4072 "height=\"%g\">\n",name,svg_info.bounds.x,
4073 svg_info.bounds.y,svg_info.bounds.width,
4074 svg_info.bounds.height);
4075 (void) WriteBlobString(image,message);
4086 if (LocaleCompare("rectangle",keyword) == 0)
4088 primitive_type=RectanglePrimitive;
4091 if (LocaleCompare("roundRectangle",keyword) == 0)
4093 primitive_type=RoundRectanglePrimitive;
4096 if (LocaleCompare("rotate",keyword) == 0)
4098 GetMagickToken(q,&q,token);
4099 (void) FormatLocaleString(message,MaxTextExtent,"rotate(%s) ",
4101 (void) WriteBlobString(image,message);
4110 if (LocaleCompare("scale",keyword) == 0)
4112 GetMagickToken(q,&q,token);
4113 affine.sx=StringToDouble(token,(char **) NULL);
4114 GetMagickToken(q,&q,token);
4116 GetMagickToken(q,&q,token);
4117 affine.sy=StringToDouble(token,(char **) NULL);
4120 if (LocaleCompare("skewX",keyword) == 0)
4122 GetMagickToken(q,&q,token);
4123 (void) FormatLocaleString(message,MaxTextExtent,"skewX(%s) ",
4125 (void) WriteBlobString(image,message);
4128 if (LocaleCompare("skewY",keyword) == 0)
4130 GetMagickToken(q,&q,token);
4131 (void) FormatLocaleString(message,MaxTextExtent,"skewY(%s) ",
4133 (void) WriteBlobString(image,message);
4136 if (LocaleCompare("stop-color",keyword) == 0)
4139 color[MaxTextExtent];
4141 GetMagickToken(q,&q,token);
4142 (void) CopyMagickString(color,token,MaxTextExtent);
4143 GetMagickToken(q,&q,token);
4144 (void) FormatLocaleString(message,MaxTextExtent,
4145 " <stop offset=\"%s\" stop-color=\"%s\" />\n",token,color);
4146 (void) WriteBlobString(image,message);
4149 if (LocaleCompare("stroke",keyword) == 0)
4151 GetMagickToken(q,&q,token);
4152 (void) FormatLocaleString(message,MaxTextExtent,"stroke:%s;",
4154 (void) WriteBlobString(image,message);
4157 if (LocaleCompare("stroke-antialias",keyword) == 0)
4159 GetMagickToken(q,&q,token);
4160 (void) FormatLocaleString(message,MaxTextExtent,
4161 "stroke-antialias:%s;",token);
4162 (void) WriteBlobString(image,message);
4165 if (LocaleCompare("stroke-dasharray",keyword) == 0)
4173 GetMagickToken(p,&p,token);
4174 for (k=0; IsPoint(token); k++)
4175 GetMagickToken(p,&p,token);
4176 (void) WriteBlobString(image,"stroke-dasharray:");
4177 for (j=0; j < k; j++)
4179 GetMagickToken(q,&q,token);
4180 (void) FormatLocaleString(message,MaxTextExtent,"%s ",
4182 (void) WriteBlobString(image,message);
4184 (void) WriteBlobString(image,";");
4187 GetMagickToken(q,&q,token);
4188 (void) FormatLocaleString(message,MaxTextExtent,
4189 "stroke-dasharray:%s;",token);
4190 (void) WriteBlobString(image,message);
4193 if (LocaleCompare("stroke-dashoffset",keyword) == 0)
4195 GetMagickToken(q,&q,token);
4196 (void) FormatLocaleString(message,MaxTextExtent,
4197 "stroke-dashoffset:%s;",token);
4198 (void) WriteBlobString(image,message);
4201 if (LocaleCompare("stroke-linecap",keyword) == 0)
4203 GetMagickToken(q,&q,token);
4204 (void) FormatLocaleString(message,MaxTextExtent,
4205 "stroke-linecap:%s;",token);
4206 (void) WriteBlobString(image,message);
4209 if (LocaleCompare("stroke-linejoin",keyword) == 0)
4211 GetMagickToken(q,&q,token);
4212 (void) FormatLocaleString(message,MaxTextExtent,
4213 "stroke-linejoin:%s;",token);
4214 (void) WriteBlobString(image,message);
4217 if (LocaleCompare("stroke-miterlimit",keyword) == 0)
4219 GetMagickToken(q,&q,token);
4220 (void) FormatLocaleString(message,MaxTextExtent,
4221 "stroke-miterlimit:%s;",token);
4222 (void) WriteBlobString(image,message);
4225 if (LocaleCompare("stroke-opacity",keyword) == 0)
4227 GetMagickToken(q,&q,token);
4228 (void) FormatLocaleString(message,MaxTextExtent,
4229 "stroke-opacity:%s;",token);
4230 (void) WriteBlobString(image,message);
4233 if (LocaleCompare("stroke-width",keyword) == 0)
4235 GetMagickToken(q,&q,token);
4236 (void) FormatLocaleString(message,MaxTextExtent,
4237 "stroke-width:%s;",token);
4238 (void) WriteBlobString(image,message);
4247 if (LocaleCompare("text",keyword) == 0)
4249 primitive_type=TextPrimitive;
4252 if (LocaleCompare("text-antialias",keyword) == 0)
4254 GetMagickToken(q,&q,token);
4255 (void) FormatLocaleString(message,MaxTextExtent,
4256 "text-antialias:%s;",token);
4257 (void) WriteBlobString(image,message);
4260 if (LocaleCompare("tspan",keyword) == 0)
4262 primitive_type=TextPrimitive;
4265 if (LocaleCompare("translate",keyword) == 0)
4267 GetMagickToken(q,&q,token);
4268 affine.tx=StringToDouble(token,(char **) NULL);
4269 GetMagickToken(q,&q,token);
4271 GetMagickToken(q,&q,token);
4272 affine.ty=StringToDouble(token,(char **) NULL);
4281 if (LocaleCompare("viewbox",keyword) == 0)
4283 GetMagickToken(q,&q,token);
4285 GetMagickToken(q,&q,token);
4286 GetMagickToken(q,&q,token);
4288 GetMagickToken(q,&q,token);
4289 GetMagickToken(q,&q,token);
4291 GetMagickToken(q,&q,token);
4292 GetMagickToken(q,&q,token);
4304 if (status == MagickFalse)
4306 if (primitive_type == UndefinedPrimitive)
4309 Parse the primitive attributes.
4313 for (x=0; *q != '\0'; x++)
4318 if (IsPoint(q) == MagickFalse)
4320 GetMagickToken(q,&q,token);
4321 point.x=StringToDouble(token,(char **) NULL);
4322 GetMagickToken(q,&q,token);
4324 GetMagickToken(q,&q,token);
4325 point.y=StringToDouble(token,(char **) NULL);
4326 GetMagickToken(q,(const char **) NULL,token);
4328 GetMagickToken(q,&q,token);
4329 primitive_info[i].primitive=primitive_type;
4330 primitive_info[i].point=point;
4331 primitive_info[i].coordinates=0;
4332 primitive_info[i].method=FloodfillMethod;
4334 if (i < (ssize_t) (number_points-6*BezierQuantum-360))
4336 number_points+=6*BezierQuantum+360;
4337 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4338 number_points,sizeof(*primitive_info));
4339 if (primitive_info == (PrimitiveInfo *) NULL)
4341 (void) ThrowMagickException(exception,GetMagickModule(),
4342 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
4346 primitive_info[j].primitive=primitive_type;
4347 primitive_info[j].coordinates=x;
4348 primitive_info[j].method=FloodfillMethod;
4349 primitive_info[j].text=(char *) NULL;
4352 AffineToTransform(image,&affine);
4356 switch (primitive_type)
4358 case PointPrimitive:
4361 if (primitive_info[j].coordinates != 1)
4370 if (primitive_info[j].coordinates != 2)
4375 (void) FormatLocaleString(message,MaxTextExtent,
4376 " <line x1=\"%g\" y1=\"%g\" x2=\"%g\" y2=\"%g\"/>\n",
4377 primitive_info[j].point.x,primitive_info[j].point.y,
4378 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4379 (void) WriteBlobString(image,message);
4382 case RectanglePrimitive:
4384 if (primitive_info[j].coordinates != 2)
4389 (void) FormatLocaleString(message,MaxTextExtent,
4390 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"/>\n",
4391 primitive_info[j].point.x,primitive_info[j].point.y,
4392 primitive_info[j+1].point.x-primitive_info[j].point.x,
4393 primitive_info[j+1].point.y-primitive_info[j].point.y);
4394 (void) WriteBlobString(image,message);
4397 case RoundRectanglePrimitive:
4399 if (primitive_info[j].coordinates != 3)
4404 (void) FormatLocaleString(message,MaxTextExtent,
4405 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" rx=\"%g\" "
4406 "ry=\"%g\"/>\n",primitive_info[j].point.x,
4407 primitive_info[j].point.y,primitive_info[j+1].point.x-
4408 primitive_info[j].point.x,primitive_info[j+1].point.y-
4409 primitive_info[j].point.y,primitive_info[j+2].point.x,
4410 primitive_info[j+2].point.y);
4411 (void) WriteBlobString(image,message);
4416 if (primitive_info[j].coordinates != 3)
4423 case EllipsePrimitive:
4425 if (primitive_info[j].coordinates != 3)
4430 (void) FormatLocaleString(message,MaxTextExtent,
4431 " <ellipse cx=\"%g\" cy=\"%g\" rx=\"%g\" ry=\"%g\"/>\n",
4432 primitive_info[j].point.x,primitive_info[j].point.y,
4433 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4434 (void) WriteBlobString(image,message);
4437 case CirclePrimitive:
4443 if (primitive_info[j].coordinates != 2)
4448 alpha=primitive_info[j+1].point.x-primitive_info[j].point.x;
4449 beta=primitive_info[j+1].point.y-primitive_info[j].point.y;
4450 (void) FormatLocaleString(message,MaxTextExtent,
4451 " <circle cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
4452 primitive_info[j].point.x,primitive_info[j].point.y,
4454 (void) WriteBlobString(image,message);
4457 case PolylinePrimitive:
4459 if (primitive_info[j].coordinates < 2)
4464 (void) CopyMagickString(message," <polyline points=\"",MaxTextExtent);
4465 (void) WriteBlobString(image,message);
4466 length=strlen(message);
4469 (void) FormatLocaleString(message,MaxTextExtent,"%g,%g ",
4470 primitive_info[j].point.x,primitive_info[j].point.y);
4471 length+=strlen(message);
4474 (void) WriteBlobString(image,"\n ");
4475 length=strlen(message)+5;
4477 (void) WriteBlobString(image,message);
4479 (void) WriteBlobString(image,"\"/>\n");
4482 case PolygonPrimitive:
4484 if (primitive_info[j].coordinates < 3)
4489 primitive_info[i]=primitive_info[j];
4490 primitive_info[i].coordinates=0;
4491 primitive_info[j].coordinates++;
4493 (void) CopyMagickString(message," <polygon points=\"",MaxTextExtent);
4494 (void) WriteBlobString(image,message);
4495 length=strlen(message);
4498 (void) FormatLocaleString(message,MaxTextExtent,"%g,%g ",
4499 primitive_info[j].point.x,primitive_info[j].point.y);
4500 length+=strlen(message);
4503 (void) WriteBlobString(image,"\n ");
4504 length=strlen(message)+5;
4506 (void) WriteBlobString(image,message);
4508 (void) WriteBlobString(image,"\"/>\n");
4511 case BezierPrimitive:
4513 if (primitive_info[j].coordinates < 3)
4525 GetMagickToken(q,&q,token);
4526 number_attributes=1;
4527 for (p=token; *p != '\0'; p++)
4528 if (isalpha((int) *p))
4529 number_attributes++;
4530 if (i > (ssize_t) (number_points-6*BezierQuantum*number_attributes-1))
4532 number_points+=6*BezierQuantum*number_attributes;
4533 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4534 number_points,sizeof(*primitive_info));
4535 if (primitive_info == (PrimitiveInfo *) NULL)
4537 (void) ThrowMagickException(exception,GetMagickModule(),
4538 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4543 (void) WriteBlobString(image," <path d=\"");
4544 (void) WriteBlobString(image,token);
4545 (void) WriteBlobString(image,"\"/>\n");
4548 case ColorPrimitive:
4549 case MattePrimitive:
4551 if (primitive_info[j].coordinates != 1)
4556 GetMagickToken(q,&q,token);
4557 if (LocaleCompare("point",token) == 0)
4558 primitive_info[j].method=PointMethod;
4559 if (LocaleCompare("replace",token) == 0)
4560 primitive_info[j].method=ReplaceMethod;
4561 if (LocaleCompare("floodfill",token) == 0)
4562 primitive_info[j].method=FloodfillMethod;
4563 if (LocaleCompare("filltoborder",token) == 0)
4564 primitive_info[j].method=FillToBorderMethod;
4565 if (LocaleCompare("reset",token) == 0)
4566 primitive_info[j].method=ResetMethod;
4574 if (primitive_info[j].coordinates != 1)
4579 GetMagickToken(q,&q,token);
4580 (void) FormatLocaleString(message,MaxTextExtent,
4581 " <text x=\"%g\" y=\"%g\">",primitive_info[j].point.x,
4582 primitive_info[j].point.y);
4583 (void) WriteBlobString(image,message);
4584 for (p=token; *p != '\0'; p++)
4587 case '<': (void) WriteBlobString(image,"<"); break;
4588 case '>': (void) WriteBlobString(image,">"); break;
4589 case '&': (void) WriteBlobString(image,"&"); break;
4590 default: (void) WriteBlobByte(image,*p); break;
4592 (void) WriteBlobString(image,"</text>\n");
4595 case ImagePrimitive:
4597 if (primitive_info[j].coordinates != 2)
4602 GetMagickToken(q,&q,token);
4603 (void) FormatLocaleString(message,MaxTextExtent,
4604 " <image x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" "
4605 "xlink:href=\"%s\"/>\n",primitive_info[j].point.x,
4606 primitive_info[j].point.y,primitive_info[j+1].point.x,
4607 primitive_info[j+1].point.y,token);
4608 (void) WriteBlobString(image,message);
4612 if (primitive_info == (PrimitiveInfo *) NULL)
4614 primitive_info[i].primitive=UndefinedPrimitive;
4615 if (status == MagickFalse)
4618 (void) WriteBlobString(image,"</svg>\n");
4620 Relinquish resources.
4622 token=DestroyString(token);
4623 if (primitive_info != (PrimitiveInfo *) NULL)
4624 primitive_info=(PrimitiveInfo *) RelinquishMagickMemory(primitive_info);
4625 (void) CloseBlob(image);