2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Scalable Vector Graphics Format %
21 % Copyright 1999-2012 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__)
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(MAGICKCORE_CAIRO_DELEGATE)
97 #include "librsvg/rsvg-cairo.h"
99 #include "librsvg/librsvg-features.h"
103 Typedef declarations.
105 typedef struct _BoundingBox
114 typedef struct _ElementInfo
124 typedef struct _SVGInfo
178 #if defined(MAGICKCORE_XML_DELEGATE)
188 Forward declarations.
190 static MagickBooleanType
191 WriteSVGImage(const ImageInfo *,Image *,ExceptionInfo *);
194 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
202 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
204 % IsSVG()() returns MagickTrue if the image format type, identified by the
205 % magick string, is SVG.
207 % The format of the IsSVG method is:
209 % MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
211 % A description of each parameter follows:
213 % o magick: compare image format pattern against these bytes.
215 % o length: Specifies the length of the magick string.
218 static MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
222 if (LocaleNCompare((const char *) magick,"?xml",4) == 0)
227 #if defined(MAGICKCORE_XML_DELEGATE)
229 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
233 % R e a d S V G I m a g e %
237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
239 % ReadSVGImage() reads a Scalable Vector Gaphics file and returns it. It
240 % allocates the memory necessary for the new Image structure and returns a
241 % pointer to the new image.
243 % The format of the ReadSVGImage method is:
245 % Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
247 % A description of each parameter follows:
249 % o image_info: the image info.
251 % o exception: return any errors or warnings in this structure.
255 static SVGInfo *AcquireSVGInfo(void)
260 svg_info=(SVGInfo *) AcquireMagickMemory(sizeof(*svg_info));
261 if (svg_info == (SVGInfo *) NULL)
262 return((SVGInfo *) NULL);
263 (void) ResetMagickMemory(svg_info,0,sizeof(*svg_info));
264 svg_info->text=AcquireString("");
265 svg_info->scale=(double *) AcquireMagickMemory(sizeof(*svg_info->scale));
266 if (svg_info->scale == (double *) NULL)
267 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
268 GetAffineMatrix(&svg_info->affine);
269 svg_info->scale[0]=ExpandAffine(&svg_info->affine);
273 static SVGInfo *DestroySVGInfo(SVGInfo *svg_info)
275 if (svg_info->text != (char *) NULL)
276 svg_info->text=DestroyString(svg_info->text);
277 if (svg_info->scale != (double *) NULL)
278 svg_info->scale=(double *) (svg_info->scale);
279 if (svg_info->title != (char *) NULL)
280 svg_info->title=DestroyString(svg_info->title);
281 if (svg_info->comment != (char *) NULL)
282 svg_info->comment=DestroyString(svg_info->comment);
283 return((SVGInfo *) RelinquishMagickMemory(svg_info));
286 static double GetUserSpaceCoordinateValue(const SVGInfo *svg_info,int type,
290 token[MaxTextExtent];
298 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",string);
299 assert(string != (const char *) NULL);
300 p=(const char *) string;
301 GetMagickToken(p,&p,token);
302 value=StringToDouble(token,(char **) NULL);
303 if (strchr(token,'%') != (char *) NULL)
311 if (svg_info->view_box.width == 0.0)
313 return(svg_info->view_box.width*value/100.0);
317 if (svg_info->view_box.height == 0.0)
319 return(svg_info->view_box.height*value/100.0);
321 alpha=value-svg_info->view_box.width;
322 beta=value-svg_info->view_box.height;
323 return(hypot(alpha,beta)/sqrt(2.0)/100.0);
325 GetMagickToken(p,&p,token);
326 if (LocaleNCompare(token,"cm",2) == 0)
327 return(DefaultResolution*svg_info->scale[0]/2.54*value);
328 if (LocaleNCompare(token,"em",2) == 0)
329 return(svg_info->pointsize*value);
330 if (LocaleNCompare(token,"ex",2) == 0)
331 return(svg_info->pointsize*value/2.0);
332 if (LocaleNCompare(token,"in",2) == 0)
333 return(DefaultResolution*svg_info->scale[0]*value);
334 if (LocaleNCompare(token,"mm",2) == 0)
335 return(DefaultResolution*svg_info->scale[0]/25.4*value);
336 if (LocaleNCompare(token,"pc",2) == 0)
337 return(DefaultResolution*svg_info->scale[0]/6.0*value);
338 if (LocaleNCompare(token,"pt",2) == 0)
339 return(1.25*svg_info->scale[0]*value);
340 if (LocaleNCompare(token,"px",2) == 0)
345 static void StripStyleTokens(char *message)
354 assert(message != (char *) NULL);
355 if (*message == '\0')
357 length=strlen(message);
359 while (isspace((int) ((unsigned char) *p)) != 0)
362 while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
364 (void) CopyMagickMemory(message,p,(size_t) (q-p+1));
366 StripString(message);
369 static char **GetStyleTokens(void *context,const char *style,int *number_tokens)
381 svg_info=(SVGInfo *) context;
384 if (style == (const char *) NULL)
385 return((char **) NULL);
386 text=AcquireString(style);
387 (void) SubstituteString(&text,":","\n");
388 (void) SubstituteString(&text,";","\n");
389 tokens=StringToList(text);
390 text=DestroyString(text);
391 for (i=0; tokens[i] != (char *) NULL; i++)
392 StripStyleTokens(tokens[i]);
397 static char **GetTransformTokens(void *context,const char *text,
413 svg_info=(SVGInfo *) context;
415 if (text == (const char *) NULL)
416 return((char **) NULL);
418 Determine the number of arguments.
420 for (p=text; *p != '\0'; p++)
425 tokens=(char **) AcquireQuantumMemory(*number_tokens+2UL,sizeof(*tokens));
426 if (tokens == (char **) NULL)
428 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
429 ResourceLimitError,"MemoryAllocationFailed","`%s'",text);
430 return((char **) NULL);
433 Convert string to an ASCII list.
437 for (q=p; *q != '\0'; q++)
439 if ((*q != '(') && (*q != ')') && (*q != '\0'))
441 tokens[i]=AcquireString(p);
442 (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
443 StripString(tokens[i++]);
446 tokens[i]=AcquireString(p);
447 (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
448 StripString(tokens[i++]);
449 tokens[i]=(char *) NULL;
453 #if defined(__cplusplus) || defined(c_plusplus)
457 static int SVGIsStandalone(void *context)
463 Is this document tagged standalone?
465 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGIsStandalone()");
466 svg_info=(SVGInfo *) context;
467 return(svg_info->document->standalone == 1);
470 static int SVGHasInternalSubset(void *context)
476 Does this document has an internal subset?
478 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
479 " SAX.SVGHasInternalSubset()");
480 svg_info=(SVGInfo *) context;
481 return(svg_info->document->intSubset != NULL);
484 static int SVGHasExternalSubset(void *context)
490 Does this document has an external subset?
492 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
493 " SAX.SVGHasExternalSubset()");
494 svg_info=(SVGInfo *) context;
495 return(svg_info->document->extSubset != NULL);
498 static void SVGInternalSubset(void *context,const xmlChar *name,
499 const xmlChar *external_id,const xmlChar *system_id)
505 Does this document has an internal subset?
507 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
508 " SAX.internalSubset(%s, %s, %s)",(const char *) name,
509 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
510 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
511 svg_info=(SVGInfo *) context;
512 (void) xmlCreateIntSubset(svg_info->document,name,external_id,system_id);
515 static xmlParserInputPtr SVGResolveEntity(void *context,
516 const xmlChar *public_id,const xmlChar *system_id)
525 Special entity resolver, better left to the parser, it has more
526 context than the application layer. The default behaviour is to
527 not resolve the entities, in that case the ENTITY_REF nodes are
528 built in the structure (and the parameter values).
530 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
531 " SAX.resolveEntity(%s, %s)",
532 (public_id != (const xmlChar *) NULL ? (const char *) public_id : "none"),
533 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
534 svg_info=(SVGInfo *) context;
535 stream=xmlLoadExternalEntity((const char *) system_id,(const char *)
536 public_id,svg_info->parser);
540 static xmlEntityPtr SVGGetEntity(void *context,const xmlChar *name)
546 Get an entity by name.
548 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGGetEntity(%s)",
550 svg_info=(SVGInfo *) context;
551 return(xmlGetDocEntity(svg_info->document,name));
554 static xmlEntityPtr SVGGetParameterEntity(void *context,const xmlChar *name)
560 Get a parameter entity by name.
562 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
563 " SAX.getParameterEntity(%s)",name);
564 svg_info=(SVGInfo *) context;
565 return(xmlGetParameterEntity(svg_info->document,name));
568 static void SVGEntityDeclaration(void *context,const xmlChar *name,int type,
569 const xmlChar *public_id,const xmlChar *system_id,xmlChar *content)
575 An entity definition has been parsed.
577 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
578 " SAX.entityDecl(%s, %d, %s, %s, %s)",name,type,
579 public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
580 system_id != (xmlChar *) NULL ? (const char *) system_id : "none",content);
581 svg_info=(SVGInfo *) context;
582 if (svg_info->parser->inSubset == 1)
583 (void) xmlAddDocEntity(svg_info->document,name,type,public_id,system_id,
586 if (svg_info->parser->inSubset == 2)
587 (void) xmlAddDtdEntity(svg_info->document,name,type,public_id,system_id,
591 static void SVGAttributeDeclaration(void *context,const xmlChar *element,
592 const xmlChar *name,int type,int value,const xmlChar *default_value,
593 xmlEnumerationPtr tree)
606 An attribute definition has been parsed.
608 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
609 " SAX.attributeDecl(%s, %s, %d, %d, %s, ...)",element,name,type,value,
611 svg_info=(SVGInfo *) context;
612 fullname=(xmlChar *) NULL;
613 prefix=(xmlChar *) NULL;
614 parser=svg_info->parser;
615 fullname=(xmlChar *) xmlSplitQName(parser,name,&prefix);
616 if (parser->inSubset == 1)
617 (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->intSubset,
618 element,fullname,prefix,(xmlAttributeType) type,
619 (xmlAttributeDefault) value,default_value,tree);
621 if (parser->inSubset == 2)
622 (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->extSubset,
623 element,fullname,prefix,(xmlAttributeType) type,
624 (xmlAttributeDefault) value,default_value,tree);
625 if (prefix != (xmlChar *) NULL)
627 if (fullname != (xmlChar *) NULL)
631 static void SVGElementDeclaration(void *context,const xmlChar *name,int type,
632 xmlElementContentPtr content)
641 An element definition has been parsed.
643 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
644 " SAX.elementDecl(%s, %d, ...)",name,type);
645 svg_info=(SVGInfo *) context;
646 parser=svg_info->parser;
647 if (parser->inSubset == 1)
648 (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->intSubset,
649 name,(xmlElementTypeVal) type,content);
651 if (parser->inSubset == 2)
652 (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->extSubset,
653 name,(xmlElementTypeVal) type,content);
656 static void SVGNotationDeclaration(void *context,const xmlChar *name,
657 const xmlChar *public_id,const xmlChar *system_id)
666 What to do when a notation declaration has been parsed.
668 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
669 " SAX.notationDecl(%s, %s, %s)",name,
670 public_id != (const xmlChar *) NULL ? (const char *) public_id : "none",
671 system_id != (const xmlChar *) NULL ? (const char *) system_id : "none");
672 svg_info=(SVGInfo *) context;
673 parser=svg_info->parser;
674 if (parser->inSubset == 1)
675 (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
676 name,public_id,system_id);
678 if (parser->inSubset == 2)
679 (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
680 name,public_id,system_id);
683 static void SVGUnparsedEntityDeclaration(void *context,const xmlChar *name,
684 const xmlChar *public_id,const xmlChar *system_id,const xmlChar *notation)
690 What to do when an unparsed entity declaration is parsed.
692 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
693 " SAX.unparsedEntityDecl(%s, %s, %s, %s)",name,
694 public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
695 system_id != (xmlChar *) NULL ? (const char *) system_id : "none",notation);
696 svg_info=(SVGInfo *) context;
697 (void) xmlAddDocEntity(svg_info->document,name,
698 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,public_id,system_id,notation);
702 static void SVGSetDocumentLocator(void *context,xmlSAXLocatorPtr location)
708 Receive the document locator at startup, actually xmlDefaultSAXLocator.
711 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
712 " SAX.setDocumentLocator()");
713 svg_info=(SVGInfo *) context;
717 static void SVGStartDocument(void *context)
726 Called when the document start being processed.
728 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startDocument()");
729 svg_info=(SVGInfo *) context;
730 GetExceptionInfo(svg_info->exception);
731 parser=svg_info->parser;
732 svg_info->document=xmlNewDoc(parser->version);
733 if (svg_info->document == (xmlDocPtr) NULL)
735 if (parser->encoding == NULL)
736 svg_info->document->encoding=(const xmlChar *) NULL;
738 svg_info->document->encoding=xmlStrdup(parser->encoding);
739 svg_info->document->standalone=parser->standalone;
742 static void SVGEndDocument(void *context)
748 Called when the document end has been detected.
750 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.endDocument()");
751 svg_info=(SVGInfo *) context;
752 if (svg_info->offset != (char *) NULL)
753 svg_info->offset=DestroyString(svg_info->offset);
754 if (svg_info->stop_color != (char *) NULL)
755 svg_info->stop_color=DestroyString(svg_info->stop_color);
756 if (svg_info->scale != (double *) NULL)
757 svg_info->scale=(double *) RelinquishMagickMemory(svg_info->scale);
758 if (svg_info->text != (char *) NULL)
759 svg_info->text=DestroyString(svg_info->text);
760 if (svg_info->vertices != (char *) NULL)
761 svg_info->vertices=DestroyString(svg_info->vertices);
762 if (svg_info->url != (char *) NULL)
763 svg_info->url=DestroyString(svg_info->url);
764 #if defined(MAGICKCORE_XML_DELEGATE)
765 if (svg_info->document != (xmlDocPtr) NULL)
767 xmlFreeDoc(svg_info->document);
768 svg_info->document=(xmlDocPtr) NULL;
773 static void SVGStartElement(void *context,const xmlChar *name,
774 const xmlChar **attributes)
779 token[MaxTextExtent],
799 Called when an opening tag has been processed.
801 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startElement(%s",
803 svg_info=(SVGInfo *) context;
805 svg_info->scale=(double *) ResizeQuantumMemory(svg_info->scale,
806 svg_info->n+1UL,sizeof(*svg_info->scale));
807 if (svg_info->scale == (double *) NULL)
809 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
810 ResourceLimitError,"MemoryAllocationFailed","`%s'",name);
813 svg_info->scale[svg_info->n]=svg_info->scale[svg_info->n-1];
814 color=AcquireString("none");
815 units=AcquireString("userSpaceOnUse");
816 value=(const char *) NULL;
817 if (attributes != (const xmlChar **) NULL)
818 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
820 keyword=(const char *) attributes[i];
821 value=(const char *) attributes[i+1];
827 if (LocaleCompare(keyword,"cx") == 0)
829 svg_info->element.cx=
830 GetUserSpaceCoordinateValue(svg_info,1,value);
833 if (LocaleCompare(keyword,"cy") == 0)
835 svg_info->element.cy=
836 GetUserSpaceCoordinateValue(svg_info,-1,value);
844 if (LocaleCompare(keyword,"fx") == 0)
846 svg_info->element.major=
847 GetUserSpaceCoordinateValue(svg_info,1,value);
850 if (LocaleCompare(keyword,"fy") == 0)
852 svg_info->element.minor=
853 GetUserSpaceCoordinateValue(svg_info,-1,value);
861 if (LocaleCompare(keyword,"height") == 0)
863 svg_info->bounds.height=
864 GetUserSpaceCoordinateValue(svg_info,-1,value);
872 if (LocaleCompare(keyword,"id") == 0)
874 (void) CopyMagickString(id,value,MaxTextExtent);
882 if (LocaleCompare(keyword,"r") == 0)
884 svg_info->element.angle=
885 GetUserSpaceCoordinateValue(svg_info,0,value);
893 if (LocaleCompare(keyword,"width") == 0)
895 svg_info->bounds.width=
896 GetUserSpaceCoordinateValue(svg_info,1,value);
904 if (LocaleCompare(keyword,"x") == 0)
906 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value)-
910 if (LocaleCompare(keyword,"x1") == 0)
912 svg_info->segment.x1=GetUserSpaceCoordinateValue(svg_info,1,
916 if (LocaleCompare(keyword,"x2") == 0)
918 svg_info->segment.x2=GetUserSpaceCoordinateValue(svg_info,1,
927 if (LocaleCompare(keyword,"y") == 0)
929 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value)-
933 if (LocaleCompare(keyword,"y1") == 0)
935 svg_info->segment.y1=
936 GetUserSpaceCoordinateValue(svg_info,-1,value);
939 if (LocaleCompare(keyword,"y2") == 0)
941 svg_info->segment.y2=
942 GetUserSpaceCoordinateValue(svg_info,-1,value);
951 if (strchr((char *) name,':') != (char *) NULL)
956 for ( ; *name != ':'; name++) ;
964 if (LocaleCompare((const char *) name,"circle") == 0)
966 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
969 if (LocaleCompare((const char *) name,"clipPath") == 0)
971 (void) FormatLocaleFile(svg_info->file,"push clip-path '%s'\n",id);
979 if (LocaleCompare((const char *) name,"defs") == 0)
981 (void) FormatLocaleFile(svg_info->file,"push defs\n");
989 if (LocaleCompare((const char *) name,"ellipse") == 0)
991 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
999 if (LocaleCompare((const char *) name,"g") == 0)
1001 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1009 if (LocaleCompare((const char *) name,"image") == 0)
1011 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1019 if (LocaleCompare((const char *) name,"line") == 0)
1021 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1024 if (LocaleCompare((const char *) name,"linearGradient") == 0)
1026 (void) FormatLocaleFile(svg_info->file,
1027 "push gradient '%s' linear %g,%g %g,%g\n",id,
1028 svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
1029 svg_info->segment.y2);
1037 if (LocaleCompare((const char *) name,"path") == 0)
1039 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1042 if (LocaleCompare((const char *) name,"pattern") == 0)
1044 (void) FormatLocaleFile(svg_info->file,
1045 "push pattern '%s' %g,%g %g,%g\n",id,
1046 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.width,
1047 svg_info->bounds.height);
1050 if (LocaleCompare((const char *) name,"polygon") == 0)
1052 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1055 if (LocaleCompare((const char *) name,"polyline") == 0)
1057 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1065 if (LocaleCompare((const char *) name,"radialGradient") == 0)
1067 (void) FormatLocaleFile(svg_info->file,
1068 "push gradient '%s' radial %g,%g %g,%g %g\n",
1069 id,svg_info->element.cx,svg_info->element.cy,
1070 svg_info->element.major,svg_info->element.minor,
1071 svg_info->element.angle);
1074 if (LocaleCompare((const char *) name,"rect") == 0)
1076 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1084 if (LocaleCompare((const char *) name,"svg") == 0)
1086 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1094 if (LocaleCompare((const char *) name,"text") == 0)
1096 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1097 svg_info->bounds.x=0.0;
1098 svg_info->bounds.y=0.0;
1099 svg_info->bounds.width=0.0;
1100 svg_info->bounds.height=0.0;
1103 if (LocaleCompare((const char *) name,"tspan") == 0)
1105 if (*svg_info->text != '\0')
1116 text=EscapeString(svg_info->text,'\'');
1117 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
1118 svg_info->bounds.x-svg_info->center.x,svg_info->bounds.y-
1119 svg_info->center.y,text);
1120 text=DestroyString(text);
1121 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
1122 draw_info->pointsize=svg_info->pointsize;
1123 draw_info->text=AcquireString(svg_info->text);
1124 (void) ConcatenateString(&draw_info->text," ");
1125 (void) GetTypeMetrics(svg_info->image,draw_info,
1126 &metrics,svg_info->exception);
1127 svg_info->bounds.x+=metrics.width;
1128 draw_info=DestroyDrawInfo(draw_info);
1129 *svg_info->text='\0';
1131 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1139 if (attributes != (const xmlChar **) NULL)
1140 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
1142 keyword=(const char *) attributes[i];
1143 value=(const char *) attributes[i+1];
1144 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1145 " %s = %s",keyword,value);
1151 if (LocaleCompare(keyword,"angle") == 0)
1153 (void) FormatLocaleFile(svg_info->file,"angle %g\n",
1154 GetUserSpaceCoordinateValue(svg_info,0,value));
1162 if (LocaleCompare(keyword,"clip-path") == 0)
1164 (void) FormatLocaleFile(svg_info->file,"clip-path '%s'\n",value);
1167 if (LocaleCompare(keyword,"clip-rule") == 0)
1169 (void) FormatLocaleFile(svg_info->file,"clip-rule '%s'\n",value);
1172 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1174 (void) CloneString(&units,value);
1175 (void) FormatLocaleFile(svg_info->file,"clip-units '%s'\n",value);
1178 if (LocaleCompare(keyword,"color") == 0)
1180 (void) CloneString(&color,value);
1183 if (LocaleCompare(keyword,"cx") == 0)
1185 svg_info->element.cx=
1186 GetUserSpaceCoordinateValue(svg_info,1,value);
1189 if (LocaleCompare(keyword,"cy") == 0)
1191 svg_info->element.cy=
1192 GetUserSpaceCoordinateValue(svg_info,-1,value);
1200 if (LocaleCompare(keyword,"d") == 0)
1202 (void) CloneString(&svg_info->vertices,value);
1205 if (LocaleCompare(keyword,"dx") == 0)
1207 svg_info->bounds.x+=GetUserSpaceCoordinateValue(svg_info,1,value);
1210 if (LocaleCompare(keyword,"dy") == 0)
1212 svg_info->bounds.y+=
1213 GetUserSpaceCoordinateValue(svg_info,-1,value);
1221 if (LocaleCompare(keyword,"fill") == 0)
1223 if (LocaleCompare(value,"currentColor") == 0)
1225 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",color);
1228 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",value);
1231 if (LocaleCompare(keyword,"fillcolor") == 0)
1233 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",value);
1236 if (LocaleCompare(keyword,"fill-rule") == 0)
1238 (void) FormatLocaleFile(svg_info->file,"fill-rule '%s'\n",value);
1241 if (LocaleCompare(keyword,"fill-alpha") == 0)
1243 (void) FormatLocaleFile(svg_info->file,"fill-alpha '%s'\n",
1247 if (LocaleCompare(keyword,"font-family") == 0)
1249 (void) FormatLocaleFile(svg_info->file,"font-family '%s'\n",
1253 if (LocaleCompare(keyword,"font-stretch") == 0)
1255 (void) FormatLocaleFile(svg_info->file,"font-stretch '%s'\n",
1259 if (LocaleCompare(keyword,"font-style") == 0)
1261 (void) FormatLocaleFile(svg_info->file,"font-style '%s'\n",value);
1264 if (LocaleCompare(keyword,"font-size") == 0)
1266 svg_info->pointsize=GetUserSpaceCoordinateValue(svg_info,0,value);
1267 (void) FormatLocaleFile(svg_info->file,"font-size %g\n",
1268 svg_info->pointsize);
1271 if (LocaleCompare(keyword,"font-weight") == 0)
1273 (void) FormatLocaleFile(svg_info->file,"font-weight '%s'\n",
1282 if (LocaleCompare(keyword,"gradientTransform") == 0)
1289 GetAffineMatrix(&transform);
1290 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1291 tokens=GetTransformTokens(context,value,&number_tokens);
1292 for (j=0; j < (number_tokens-1); j+=2)
1294 keyword=(char *) tokens[j];
1295 if (keyword == (char *) NULL)
1297 value=(char *) tokens[j+1];
1298 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1299 " %s: %s",keyword,value);
1301 GetAffineMatrix(&affine);
1307 if (LocaleCompare(keyword,"matrix") == 0)
1309 p=(const char *) value;
1310 GetMagickToken(p,&p,token);
1311 affine.sx=StringToDouble(value,(char **) NULL);
1312 GetMagickToken(p,&p,token);
1314 GetMagickToken(p,&p,token);
1315 affine.rx=StringToDouble(token,(char **) NULL);
1316 GetMagickToken(p,&p,token);
1318 GetMagickToken(p,&p,token);
1319 affine.ry=StringToDouble(token,(char **) NULL);
1320 GetMagickToken(p,&p,token);
1322 GetMagickToken(p,&p,token);
1323 affine.sy=StringToDouble(token,(char **) NULL);
1324 GetMagickToken(p,&p,token);
1326 GetMagickToken(p,&p,token);
1327 affine.tx=StringToDouble(token,(char **) NULL);
1328 GetMagickToken(p,&p,token);
1330 GetMagickToken(p,&p,token);
1331 affine.ty=StringToDouble(token,(char **) NULL);
1339 if (LocaleCompare(keyword,"rotate") == 0)
1344 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1345 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1346 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1347 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1348 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1356 if (LocaleCompare(keyword,"scale") == 0)
1358 for (p=(const char *) value; *p != '\0'; p++)
1359 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1362 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1363 affine.sy=affine.sx;
1366 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1367 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
1370 if (LocaleCompare(keyword,"skewX") == 0)
1372 affine.sx=svg_info->affine.sx;
1373 affine.ry=tan(DegreesToRadians(fmod(
1374 GetUserSpaceCoordinateValue(svg_info,1,value),
1376 affine.sy=svg_info->affine.sy;
1379 if (LocaleCompare(keyword,"skewY") == 0)
1381 affine.sx=svg_info->affine.sx;
1382 affine.rx=tan(DegreesToRadians(fmod(
1383 GetUserSpaceCoordinateValue(svg_info,-1,value),
1385 affine.sy=svg_info->affine.sy;
1393 if (LocaleCompare(keyword,"translate") == 0)
1395 for (p=(const char *) value; *p != '\0'; p++)
1396 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1399 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
1400 affine.ty=affine.tx;
1403 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1411 transform.sx=affine.sx*current.sx+affine.ry*current.rx;
1412 transform.rx=affine.rx*current.sx+affine.sy*current.rx;
1413 transform.ry=affine.sx*current.ry+affine.ry*current.sy;
1414 transform.sy=affine.rx*current.ry+affine.sy*current.sy;
1415 transform.tx=affine.tx*current.sx+affine.ty*current.ry+
1417 transform.ty=affine.tx*current.rx+affine.ty*current.sy+
1420 (void) FormatLocaleFile(svg_info->file,
1421 "affine %g %g %g %g %g %g\n",transform.sx,
1422 transform.rx,transform.ry,transform.sy,transform.tx,
1424 for (j=0; tokens[j] != (char *) NULL; j++)
1425 tokens[j]=DestroyString(tokens[j]);
1426 tokens=(char **) RelinquishMagickMemory(tokens);
1429 if (LocaleCompare(keyword,"gradientUnits") == 0)
1431 (void) CloneString(&units,value);
1432 (void) FormatLocaleFile(svg_info->file,"gradient-units '%s'\n",
1441 if (LocaleCompare(keyword,"height") == 0)
1443 svg_info->bounds.height=
1444 GetUserSpaceCoordinateValue(svg_info,-1,value);
1447 if (LocaleCompare(keyword,"href") == 0)
1449 (void) CloneString(&svg_info->url,value);
1457 if (LocaleCompare(keyword,"major") == 0)
1459 svg_info->element.major=
1460 GetUserSpaceCoordinateValue(svg_info,1,value);
1463 if (LocaleCompare(keyword,"minor") == 0)
1465 svg_info->element.minor=
1466 GetUserSpaceCoordinateValue(svg_info,-1,value);
1474 if (LocaleCompare(keyword,"offset") == 0)
1476 (void) CloneString(&svg_info->offset,value);
1479 if (LocaleCompare(keyword,"opacity") == 0)
1481 (void) FormatLocaleFile(svg_info->file,"opacity '%s'\n",value);
1489 if (LocaleCompare(keyword,"path") == 0)
1491 (void) CloneString(&svg_info->url,value);
1494 if (LocaleCompare(keyword,"points") == 0)
1496 (void) CloneString(&svg_info->vertices,value);
1504 if (LocaleCompare(keyword,"r") == 0)
1506 svg_info->element.major=
1507 GetUserSpaceCoordinateValue(svg_info,1,value);
1508 svg_info->element.minor=
1509 GetUserSpaceCoordinateValue(svg_info,-1,value);
1512 if (LocaleCompare(keyword,"rotate") == 0)
1517 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1518 (void) FormatLocaleFile(svg_info->file,"translate %g,%g\n",
1519 svg_info->bounds.x,svg_info->bounds.y);
1520 svg_info->bounds.x=0;
1521 svg_info->bounds.y=0;
1522 (void) FormatLocaleFile(svg_info->file,"rotate %g\n",angle);
1525 if (LocaleCompare(keyword,"rx") == 0)
1527 if (LocaleCompare((const char *) name,"ellipse") == 0)
1528 svg_info->element.major=
1529 GetUserSpaceCoordinateValue(svg_info,1,value);
1532 GetUserSpaceCoordinateValue(svg_info,1,value);
1535 if (LocaleCompare(keyword,"ry") == 0)
1537 if (LocaleCompare((const char *) name,"ellipse") == 0)
1538 svg_info->element.minor=
1539 GetUserSpaceCoordinateValue(svg_info,-1,value);
1542 GetUserSpaceCoordinateValue(svg_info,-1,value);
1550 if (LocaleCompare(keyword,"stop-color") == 0)
1552 (void) CloneString(&svg_info->stop_color,value);
1555 if (LocaleCompare(keyword,"stroke") == 0)
1557 if (LocaleCompare(value,"currentColor") == 0)
1559 (void) FormatLocaleFile(svg_info->file,"stroke '%s'\n",color);
1562 (void) FormatLocaleFile(svg_info->file,"stroke '%s'\n",value);
1565 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1567 (void) FormatLocaleFile(svg_info->file,"stroke-antialias %d\n",
1568 LocaleCompare(value,"true") == 0);
1571 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1573 (void) FormatLocaleFile(svg_info->file,"stroke-dasharray %s\n",
1577 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1579 (void) FormatLocaleFile(svg_info->file,"stroke-dashoffset %s\n",
1583 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1585 (void) FormatLocaleFile(svg_info->file,"stroke-linecap '%s'\n",
1589 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1591 (void) FormatLocaleFile(svg_info->file,"stroke-linejoin '%s'\n",
1595 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1597 (void) FormatLocaleFile(svg_info->file,"stroke-miterlimit '%s'\n",
1601 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1603 (void) FormatLocaleFile(svg_info->file,"stroke-opacity '%s'\n",
1607 if (LocaleCompare(keyword,"stroke-width") == 0)
1609 (void) FormatLocaleFile(svg_info->file,"stroke-width %g\n",
1610 GetUserSpaceCoordinateValue(svg_info,1,value));
1613 if (LocaleCompare(keyword,"style") == 0)
1615 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1616 tokens=GetStyleTokens(context,value,&number_tokens);
1617 for (j=0; j < (number_tokens-1); j+=2)
1619 keyword=(char *) tokens[j];
1620 value=(char *) tokens[j+1];
1621 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1622 " %s: %s",keyword,value);
1628 if (LocaleCompare(keyword,"clip-path") == 0)
1630 (void) FormatLocaleFile(svg_info->file,
1631 "clip-path '%s'\n",value);
1634 if (LocaleCompare(keyword,"clip-rule") == 0)
1636 (void) FormatLocaleFile(svg_info->file,
1637 "clip-rule '%s'\n",value);
1640 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1642 (void) CloneString(&units,value);
1643 (void) FormatLocaleFile(svg_info->file,
1644 "clip-units '%s'\n",value);
1647 if (LocaleCompare(keyword,"color") == 0)
1649 (void) CloneString(&color,value);
1657 if (LocaleCompare(keyword,"fill") == 0)
1659 if (LocaleCompare(value,"currentColor") == 0)
1661 (void) FormatLocaleFile(svg_info->file,
1662 "fill '%s'\n",color);
1665 if (LocaleCompare(value,"#00000000") == 0)
1666 (void) FormatLocaleFile(svg_info->file,
1667 "fill '#000000'\n");
1669 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",
1673 if (LocaleCompare(keyword,"fillcolor") == 0)
1675 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",
1679 if (LocaleCompare(keyword,"fill-rule") == 0)
1681 (void) FormatLocaleFile(svg_info->file,
1682 "fill-rule '%s'\n",value);
1685 if (LocaleCompare(keyword,"fill-alpha") == 0)
1687 (void) FormatLocaleFile(svg_info->file,
1688 "fill-alpha '%s'\n",value);
1691 if (LocaleCompare(keyword,"font-family") == 0)
1693 (void) FormatLocaleFile(svg_info->file,
1694 "font-family '%s'\n",value);
1697 if (LocaleCompare(keyword,"font-stretch") == 0)
1699 (void) FormatLocaleFile(svg_info->file,
1700 "font-stretch '%s'\n",value);
1703 if (LocaleCompare(keyword,"font-style") == 0)
1705 (void) FormatLocaleFile(svg_info->file,
1706 "font-style '%s'\n",value);
1709 if (LocaleCompare(keyword,"font-size") == 0)
1711 svg_info->pointsize=GetUserSpaceCoordinateValue(
1713 (void) FormatLocaleFile(svg_info->file,"font-size %g\n",
1714 svg_info->pointsize);
1717 if (LocaleCompare(keyword,"font-weight") == 0)
1719 (void) FormatLocaleFile(svg_info->file,
1720 "font-weight '%s'\n",value);
1728 if (LocaleCompare(keyword,"offset") == 0)
1730 (void) FormatLocaleFile(svg_info->file,"offset %g\n",
1731 GetUserSpaceCoordinateValue(svg_info,1,value));
1734 if (LocaleCompare(keyword,"opacity") == 0)
1736 (void) FormatLocaleFile(svg_info->file,
1737 "opacity '%s'\n",value);
1745 if (LocaleCompare(keyword,"stop-color") == 0)
1747 (void) CloneString(&svg_info->stop_color,value);
1750 if (LocaleCompare(keyword,"stroke") == 0)
1752 if (LocaleCompare(value,"currentColor") == 0)
1754 (void) FormatLocaleFile(svg_info->file,
1755 "stroke '%s'\n",color);
1758 if (LocaleCompare(value,"#00000000") == 0)
1759 (void) FormatLocaleFile(svg_info->file,
1760 "fill '#000000'\n");
1762 (void) FormatLocaleFile(svg_info->file,
1763 "stroke '%s'\n",value);
1766 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1768 (void) FormatLocaleFile(svg_info->file,
1769 "stroke-antialias %d\n",
1770 LocaleCompare(value,"true") == 0);
1773 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1775 (void) FormatLocaleFile(svg_info->file,
1776 "stroke-dasharray %s\n",value);
1779 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1781 (void) FormatLocaleFile(svg_info->file,
1782 "stroke-dashoffset %s\n",
1786 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1788 (void) FormatLocaleFile(svg_info->file,
1789 "stroke-linecap '%s'\n",value);
1792 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1794 (void) FormatLocaleFile(svg_info->file,
1795 "stroke-linejoin '%s'\n",
1799 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1801 (void) FormatLocaleFile(svg_info->file,
1802 "stroke-miterlimit '%s'\n",
1806 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1808 (void) FormatLocaleFile(svg_info->file,
1809 "stroke-opacity '%s'\n",value);
1812 if (LocaleCompare(keyword,"stroke-width") == 0)
1814 (void) FormatLocaleFile(svg_info->file,
1815 "stroke-width %g\n",
1816 GetUserSpaceCoordinateValue(svg_info,1,value));
1824 if (LocaleCompare(keyword,"text-align") == 0)
1826 (void) FormatLocaleFile(svg_info->file,
1827 "text-align '%s'\n",value);
1830 if (LocaleCompare(keyword,"text-anchor") == 0)
1832 (void) FormatLocaleFile(svg_info->file,
1833 "text-anchor '%s'\n",value);
1836 if (LocaleCompare(keyword,"text-decoration") == 0)
1838 if (LocaleCompare(value,"underline") == 0)
1839 (void) FormatLocaleFile(svg_info->file,
1840 "decorate underline\n");
1841 if (LocaleCompare(value,"line-through") == 0)
1842 (void) FormatLocaleFile(svg_info->file,
1843 "decorate line-through\n");
1844 if (LocaleCompare(value,"overline") == 0)
1845 (void) FormatLocaleFile(svg_info->file,
1846 "decorate overline\n");
1849 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1851 (void) FormatLocaleFile(svg_info->file,
1852 "text-antialias %d\n",
1853 LocaleCompare(value,"true") == 0);
1862 for (j=0; tokens[j] != (char *) NULL; j++)
1863 tokens[j]=DestroyString(tokens[j]);
1864 tokens=(char **) RelinquishMagickMemory(tokens);
1872 if (LocaleCompare(keyword,"text-align") == 0)
1874 (void) FormatLocaleFile(svg_info->file,"text-align '%s'\n",
1878 if (LocaleCompare(keyword,"text-anchor") == 0)
1880 (void) FormatLocaleFile(svg_info->file,"text-anchor '%s'\n",
1884 if (LocaleCompare(keyword,"text-decoration") == 0)
1886 if (LocaleCompare(value,"underline") == 0)
1887 (void) FormatLocaleFile(svg_info->file,"decorate underline\n");
1888 if (LocaleCompare(value,"line-through") == 0)
1889 (void) FormatLocaleFile(svg_info->file,
1890 "decorate line-through\n");
1891 if (LocaleCompare(value,"overline") == 0)
1892 (void) FormatLocaleFile(svg_info->file,"decorate overline\n");
1895 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1897 (void) FormatLocaleFile(svg_info->file,"text-antialias %d\n",
1898 LocaleCompare(value,"true") == 0);
1901 if (LocaleCompare(keyword,"transform") == 0)
1908 GetAffineMatrix(&transform);
1909 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1910 tokens=GetTransformTokens(context,value,&number_tokens);
1911 for (j=0; j < (number_tokens-1); j+=2)
1913 keyword=(char *) tokens[j];
1914 value=(char *) tokens[j+1];
1915 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1916 " %s: %s",keyword,value);
1918 GetAffineMatrix(&affine);
1924 if (LocaleCompare(keyword,"matrix") == 0)
1926 p=(const char *) value;
1927 GetMagickToken(p,&p,token);
1928 affine.sx=StringToDouble(value,(char **) NULL);
1929 GetMagickToken(p,&p,token);
1931 GetMagickToken(p,&p,token);
1932 affine.rx=StringToDouble(token,(char **) NULL);
1933 GetMagickToken(p,&p,token);
1935 GetMagickToken(p,&p,token);
1936 affine.ry=StringToDouble(token,(char **) NULL);
1937 GetMagickToken(p,&p,token);
1939 GetMagickToken(p,&p,token);
1940 affine.sy=StringToDouble(token,(char **) NULL);
1941 GetMagickToken(p,&p,token);
1943 GetMagickToken(p,&p,token);
1944 affine.tx=StringToDouble(token,(char **) NULL);
1945 GetMagickToken(p,&p,token);
1947 GetMagickToken(p,&p,token);
1948 affine.ty=StringToDouble(token,(char **) NULL);
1956 if (LocaleCompare(keyword,"rotate") == 0)
1963 p=(const char *) value;
1964 GetMagickToken(p,&p,token);
1965 angle=StringToDouble(value,(char **) NULL);
1966 GetMagickToken(p,&p,token);
1968 GetMagickToken(p,&p,token);
1969 x=StringToDouble(token,(char **) NULL);
1970 GetMagickToken(p,&p,token);
1972 GetMagickToken(p,&p,token);
1973 y=StringToDouble(token,(char **) NULL);
1974 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1975 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1976 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1977 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1980 svg_info->center.x=x;
1981 svg_info->center.y=y;
1989 if (LocaleCompare(keyword,"scale") == 0)
1991 for (p=(const char *) value; *p != '\0'; p++)
1992 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1995 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1996 affine.sy=affine.sx;
1998 affine.sy=GetUserSpaceCoordinateValue(svg_info,-1,
2000 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
2003 if (LocaleCompare(keyword,"skewX") == 0)
2005 affine.sx=svg_info->affine.sx;
2006 affine.ry=tan(DegreesToRadians(fmod(
2007 GetUserSpaceCoordinateValue(svg_info,1,value),
2009 affine.sy=svg_info->affine.sy;
2012 if (LocaleCompare(keyword,"skewY") == 0)
2014 affine.sx=svg_info->affine.sx;
2015 affine.rx=tan(DegreesToRadians(fmod(
2016 GetUserSpaceCoordinateValue(svg_info,-1,value),
2018 affine.sy=svg_info->affine.sy;
2026 if (LocaleCompare(keyword,"translate") == 0)
2028 for (p=(const char *) value; *p != '\0'; p++)
2029 if ((isspace((int) ((unsigned char) *p)) != 0) ||
2032 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
2033 affine.ty=affine.tx;
2035 affine.ty=GetUserSpaceCoordinateValue(svg_info,-1,
2044 transform.sx=affine.sx*current.sx+affine.ry*current.rx;
2045 transform.rx=affine.rx*current.sx+affine.sy*current.rx;
2046 transform.ry=affine.sx*current.ry+affine.ry*current.sy;
2047 transform.sy=affine.rx*current.ry+affine.sy*current.sy;
2048 transform.tx=affine.tx*current.sx+affine.ty*current.ry+
2050 transform.ty=affine.tx*current.rx+affine.ty*current.sy+
2053 (void) FormatLocaleFile(svg_info->file,
2054 "affine %g %g %g %g %g %g\n",transform.sx,transform.rx,
2055 transform.ry,transform.sy,transform.tx,transform.ty);
2056 for (j=0; tokens[j] != (char *) NULL; j++)
2057 tokens[j]=DestroyString(tokens[j]);
2058 tokens=(char **) RelinquishMagickMemory(tokens);
2066 if (LocaleCompare(keyword,"verts") == 0)
2068 (void) CloneString(&svg_info->vertices,value);
2071 if (LocaleCompare(keyword,"viewBox") == 0)
2073 p=(const char *) value;
2074 GetMagickToken(p,&p,token);
2075 svg_info->view_box.x=StringToDouble(token,(char **) NULL);
2076 GetMagickToken(p,&p,token);
2078 GetMagickToken(p,&p,token);
2079 svg_info->view_box.y=StringToDouble(token,(char **) NULL);
2080 GetMagickToken(p,&p,token);
2082 GetMagickToken(p,&p,token);
2083 svg_info->view_box.width=StringToDouble(token,
2085 if (svg_info->bounds.width == 0)
2086 svg_info->bounds.width=svg_info->view_box.width;
2087 GetMagickToken(p,&p,token);
2089 GetMagickToken(p,&p,token);
2090 svg_info->view_box.height=StringToDouble(token,
2092 if (svg_info->bounds.height == 0)
2093 svg_info->bounds.height=svg_info->view_box.height;
2101 if (LocaleCompare(keyword,"width") == 0)
2103 svg_info->bounds.width=
2104 GetUserSpaceCoordinateValue(svg_info,1,value);
2112 if (LocaleCompare(keyword,"x") == 0)
2114 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value);
2117 if (LocaleCompare(keyword,"xlink:href") == 0)
2119 (void) CloneString(&svg_info->url,value);
2122 if (LocaleCompare(keyword,"x1") == 0)
2124 svg_info->segment.x1=
2125 GetUserSpaceCoordinateValue(svg_info,1,value);
2128 if (LocaleCompare(keyword,"x2") == 0)
2130 svg_info->segment.x2=
2131 GetUserSpaceCoordinateValue(svg_info,1,value);
2139 if (LocaleCompare(keyword,"y") == 0)
2141 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value);
2144 if (LocaleCompare(keyword,"y1") == 0)
2146 svg_info->segment.y1=
2147 GetUserSpaceCoordinateValue(svg_info,-1,value);
2150 if (LocaleCompare(keyword,"y2") == 0)
2152 svg_info->segment.y2=
2153 GetUserSpaceCoordinateValue(svg_info,-1,value);
2162 if (LocaleCompare((const char *) name,"svg") == 0)
2164 if (svg_info->document->encoding != (const xmlChar *) NULL)
2165 (void) FormatLocaleFile(svg_info->file,"encoding \"%s\"\n",
2166 (const char *) svg_info->document->encoding);
2167 if (attributes != (const xmlChar **) NULL)
2175 if ((svg_info->view_box.width == 0.0) ||
2176 (svg_info->view_box.height == 0.0))
2177 svg_info->view_box=svg_info->bounds;
2178 svg_info->width=(size_t) floor(svg_info->bounds.width+0.5);
2179 svg_info->height=(size_t) floor(svg_info->bounds.height+0.5);
2180 (void) FormatLocaleFile(svg_info->file,"viewbox 0 0 %.20g %.20g\n",
2181 (double) svg_info->width,(double) svg_info->height);
2182 sx=(double) svg_info->width/svg_info->view_box.width;
2183 sy=(double) svg_info->height/svg_info->view_box.height;
2184 tx=svg_info->view_box.x != 0.0 ? (double) -sx*svg_info->view_box.x :
2186 ty=svg_info->view_box.y != 0.0 ? (double) -sy*svg_info->view_box.y :
2188 (void) FormatLocaleFile(svg_info->file,"affine %g 0 0 %g %g %g\n",
2192 (void) LogMagickEvent(CoderEvent,GetMagickModule()," )");
2193 units=DestroyString(units);
2194 if (color != (char *) NULL)
2195 color=DestroyString(color);
2198 static void SVGEndElement(void *context,const xmlChar *name)
2204 Called when the end of an element has been detected.
2206 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2207 " SAX.endElement(%s)",name);
2208 svg_info=(SVGInfo *) context;
2209 if (strchr((char *) name,':') != (char *) NULL)
2212 Skip over namespace.
2214 for ( ; *name != ':'; name++) ;
2222 if (LocaleCompare((const char *) name,"circle") == 0)
2224 (void) FormatLocaleFile(svg_info->file,"circle %g,%g %g,%g\n",
2225 svg_info->element.cx,svg_info->element.cy,svg_info->element.cx,
2226 svg_info->element.cy+svg_info->element.minor);
2227 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2230 if (LocaleCompare((const char *) name,"clipPath") == 0)
2232 (void) FormatLocaleFile(svg_info->file,"pop clip-path\n");
2240 if (LocaleCompare((const char *) name,"defs") == 0)
2242 (void) FormatLocaleFile(svg_info->file,"pop defs\n");
2245 if (LocaleCompare((const char *) name,"desc") == 0)
2250 if (*svg_info->text == '\0')
2252 (void) fputc('#',svg_info->file);
2253 for (p=svg_info->text; *p != '\0'; p++)
2255 (void) fputc(*p,svg_info->file);
2257 (void) fputc('#',svg_info->file);
2259 (void) fputc('\n',svg_info->file);
2260 *svg_info->text='\0';
2268 if (LocaleCompare((const char *) name,"ellipse") == 0)
2273 angle=svg_info->element.angle;
2274 (void) FormatLocaleFile(svg_info->file,"ellipse %g,%g %g,%g 0,360\n",
2275 svg_info->element.cx,svg_info->element.cy,
2276 angle == 0.0 ? svg_info->element.major : svg_info->element.minor,
2277 angle == 0.0 ? svg_info->element.minor : svg_info->element.major);
2278 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2286 if (LocaleCompare((const char *) name,"g") == 0)
2288 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2296 if (LocaleCompare((const char *) name,"image") == 0)
2298 (void) FormatLocaleFile(svg_info->file,
2299 "image Over %g,%g %g,%g '%s'\n",svg_info->bounds.x,
2300 svg_info->bounds.y,svg_info->bounds.width,svg_info->bounds.height,
2302 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2310 if (LocaleCompare((const char *) name,"line") == 0)
2312 (void) FormatLocaleFile(svg_info->file,"line %g,%g %g,%g\n",
2313 svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
2314 svg_info->segment.y2);
2315 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2318 if (LocaleCompare((const char *) name,"linearGradient") == 0)
2320 (void) FormatLocaleFile(svg_info->file,"pop gradient\n");
2328 if (LocaleCompare((const char *) name,"pattern") == 0)
2330 (void) FormatLocaleFile(svg_info->file,"pop pattern\n");
2333 if (LocaleCompare((const char *) name,"path") == 0)
2335 (void) FormatLocaleFile(svg_info->file,"path '%s'\n",
2336 svg_info->vertices);
2337 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2340 if (LocaleCompare((const char *) name,"polygon") == 0)
2342 (void) FormatLocaleFile(svg_info->file,"polygon %s\n",
2343 svg_info->vertices);
2344 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2347 if (LocaleCompare((const char *) name,"polyline") == 0)
2349 (void) FormatLocaleFile(svg_info->file,"polyline %s\n",
2350 svg_info->vertices);
2351 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2359 if (LocaleCompare((const char *) name,"radialGradient") == 0)
2361 (void) FormatLocaleFile(svg_info->file,"pop gradient\n");
2364 if (LocaleCompare((const char *) name,"rect") == 0)
2366 if ((svg_info->radius.x == 0.0) && (svg_info->radius.y == 0.0))
2368 (void) FormatLocaleFile(svg_info->file,"rectangle %g,%g %g,%g\n",
2369 svg_info->bounds.x,svg_info->bounds.y,
2370 svg_info->bounds.x+svg_info->bounds.width,
2371 svg_info->bounds.y+svg_info->bounds.height);
2372 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2375 if (svg_info->radius.x == 0.0)
2376 svg_info->radius.x=svg_info->radius.y;
2377 if (svg_info->radius.y == 0.0)
2378 svg_info->radius.y=svg_info->radius.x;
2379 (void) FormatLocaleFile(svg_info->file,
2380 "roundRectangle %g,%g %g,%g %g,%g\n",
2381 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.x+
2382 svg_info->bounds.width,svg_info->bounds.y+svg_info->bounds.height,
2383 svg_info->radius.x,svg_info->radius.y);
2384 svg_info->radius.x=0.0;
2385 svg_info->radius.y=0.0;
2386 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2394 if (LocaleCompare((const char *) name,"stop") == 0)
2396 (void) FormatLocaleFile(svg_info->file,"stop-color '%s' %s\n",
2397 svg_info->stop_color,svg_info->offset);
2400 if (LocaleCompare((const char *) name,"svg") == 0)
2402 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2410 if (LocaleCompare((const char *) name,"text") == 0)
2412 if (*svg_info->text != '\0')
2417 text=EscapeString(svg_info->text,'\'');
2418 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
2419 svg_info->bounds.x,svg_info->bounds.y,text);
2420 text=DestroyString(text);
2421 *svg_info->text='\0';
2423 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2426 if (LocaleCompare((const char *) name,"tspan") == 0)
2428 if (*svg_info->text != '\0')
2439 text=EscapeString(svg_info->text,'\'');
2440 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
2441 svg_info->bounds.x,svg_info->bounds.y,text);
2442 text=DestroyString(text);
2443 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
2444 draw_info->pointsize=svg_info->pointsize;
2445 draw_info->text=AcquireString(svg_info->text);
2446 (void) ConcatenateString(&draw_info->text," ");
2447 (void) GetTypeMetrics(svg_info->image,draw_info,&metrics,
2448 svg_info->exception);
2449 svg_info->bounds.x+=metrics.width;
2450 draw_info=DestroyDrawInfo(draw_info);
2451 *svg_info->text='\0';
2453 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2456 if (LocaleCompare((const char *) name,"title") == 0)
2458 if (*svg_info->text == '\0')
2460 (void) CloneString(&svg_info->title,svg_info->text);
2461 *svg_info->text='\0';
2469 *svg_info->text='\0';
2470 (void) ResetMagickMemory(&svg_info->element,0,sizeof(svg_info->element));
2471 (void) ResetMagickMemory(&svg_info->segment,0,sizeof(svg_info->segment));
2475 static void SVGCharacters(void *context,const xmlChar *c,int length)
2490 Receiving some characters from the parser.
2492 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2493 " SAX.characters(%s,%.20g)",c,(double) length);
2494 svg_info=(SVGInfo *) context;
2495 text=(char *) AcquireQuantumMemory(length+1,sizeof(*text));
2496 if (text == (char *) NULL)
2499 for (i=0; i < (ssize_t) length; i++)
2503 if (svg_info->text == (char *) NULL)
2504 svg_info->text=text;
2507 (void) ConcatenateString(&svg_info->text,text);
2508 text=DestroyString(text);
2512 static void SVGReference(void *context,const xmlChar *name)
2521 Called when an entity reference is detected.
2523 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.reference(%s)",
2525 svg_info=(SVGInfo *) context;
2526 parser=svg_info->parser;
2527 if (parser == (xmlParserCtxtPtr) NULL)
2529 if (parser->node == (xmlNodePtr) NULL)
2532 (void) xmlAddChild(parser->node,xmlNewCharRef(svg_info->document,name));
2534 (void) xmlAddChild(parser->node,xmlNewReference(svg_info->document,name));
2537 static void SVGIgnorableWhitespace(void *context,const xmlChar *c,int length)
2543 Receiving some ignorable whitespaces from the parser.
2545 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2546 " SAX.ignorableWhitespace(%.30s, %d)",c,length);
2547 svg_info=(SVGInfo *) context;
2551 static void SVGProcessingInstructions(void *context,const xmlChar *target,
2552 const xmlChar *data)
2558 A processing instruction has been parsed.
2560 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2561 " SAX.processingInstruction(%s, %s)",target,data);
2562 svg_info=(SVGInfo *) context;
2566 static void SVGComment(void *context,const xmlChar *value)
2572 A comment has been parsed.
2574 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.comment(%s)",
2576 svg_info=(SVGInfo *) context;
2577 if (svg_info->comment != (char *) NULL)
2578 (void) ConcatenateString(&svg_info->comment,"\n");
2579 (void) ConcatenateString(&svg_info->comment,(const char *) value);
2582 static void SVGWarning(void *context,const char *format,...)
2586 reason[MaxTextExtent];
2595 Display and format a warning messages, gives file, line, position and
2598 va_start(operands,format);
2599 svg_info=(SVGInfo *) context;
2600 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.warning: ");
2601 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2602 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2603 (void) vsprintf(reason,format,operands);
2605 (void) vsnprintf(reason,MaxTextExtent,format,operands);
2607 message=GetExceptionMessage(errno);
2608 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
2609 DelegateWarning,reason,"`%s`",message);
2610 message=DestroyString(message);
2614 static void SVGError(void *context,const char *format,...)
2618 reason[MaxTextExtent];
2627 Display and format a error formats, gives file, line, position and
2630 va_start(operands,format);
2631 svg_info=(SVGInfo *) context;
2632 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.error: ");
2633 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2634 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2635 (void) vsprintf(reason,format,operands);
2637 (void) vsnprintf(reason,MaxTextExtent,format,operands);
2639 message=GetExceptionMessage(errno);
2640 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),CoderError,
2641 reason,"`%s`",message);
2642 message=DestroyString(message);
2646 static void SVGCDataBlock(void *context,const xmlChar *value,int length)
2658 Called when a pcdata block has been parsed.
2660 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.pcdata(%s, %d)",
2662 svg_info=(SVGInfo *) context;
2663 parser=svg_info->parser;
2664 child=xmlGetLastChild(parser->node);
2665 if ((child != (xmlNodePtr) NULL) && (child->type == XML_CDATA_SECTION_NODE))
2667 xmlTextConcat(child,value,length);
2670 (void) xmlAddChild(parser->node,xmlNewCDataBlock(parser->myDoc,value,length));
2673 static void SVGExternalSubset(void *context,const xmlChar *name,
2674 const xmlChar *external_id,const xmlChar *system_id)
2689 Does this document has an external subset?
2691 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2692 " SAX.externalSubset(%s, %s, %s)",name,
2693 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
2694 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
2695 svg_info=(SVGInfo *) context;
2696 parser=svg_info->parser;
2697 if (((external_id == NULL) && (system_id == NULL)) ||
2698 ((parser->validate == 0) || (parser->wellFormed == 0) ||
2699 (svg_info->document == 0)))
2701 input=SVGResolveEntity(context,external_id,system_id);
2704 (void) xmlNewDtd(svg_info->document,name,external_id,system_id);
2705 parser_context=(*parser);
2706 parser->inputTab=(xmlParserInputPtr *) xmlMalloc(5*sizeof(*parser->inputTab));
2707 if (parser->inputTab == (xmlParserInputPtr *) NULL)
2709 parser->errNo=XML_ERR_NO_MEMORY;
2710 parser->input=parser_context.input;
2711 parser->inputNr=parser_context.inputNr;
2712 parser->inputMax=parser_context.inputMax;
2713 parser->inputTab=parser_context.inputTab;
2719 xmlPushInput(parser,input);
2720 (void) xmlSwitchEncoding(parser,xmlDetectCharEncoding(parser->input->cur,4));
2721 if (input->filename == (char *) NULL)
2722 input->filename=(char *) xmlStrdup(system_id);
2725 input->base=parser->input->cur;
2726 input->cur=parser->input->cur;
2728 xmlParseExternalSubset(parser,external_id,system_id);
2729 while (parser->inputNr > 1)
2730 (void) xmlPopInput(parser);
2731 xmlFreeInputStream(parser->input);
2732 xmlFree(parser->inputTab);
2733 parser->input=parser_context.input;
2734 parser->inputNr=parser_context.inputNr;
2735 parser->inputMax=parser_context.inputMax;
2736 parser->inputTab=parser_context.inputTab;
2739 #if defined(__cplusplus) || defined(c_plusplus)
2744 Static declarations.
2747 SVGDensityGeometry[] = "90.0x90.0";
2750 static Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
2753 filename[MaxTextExtent];
2772 message[MaxTextExtent];
2783 assert(image_info != (const ImageInfo *) NULL);
2784 assert(image_info->signature == MagickSignature);
2785 assert(exception != (ExceptionInfo *) NULL);
2786 if (image_info->debug != MagickFalse)
2787 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2788 image_info->filename);
2789 assert(exception->signature == MagickSignature);
2790 image=AcquireImage(image_info,exception);
2791 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2792 if (status == MagickFalse)
2794 image=DestroyImageList(image);
2795 return((Image *) NULL);
2797 if ((image->resolution.x == 0.0) || (image->resolution.y == 0.0))
2805 flags=ParseGeometry(SVGDensityGeometry,&geometry_info);
2806 image->resolution.x=geometry_info.rho;
2807 image->resolution.y=geometry_info.sigma;
2808 if ((flags & SigmaValue) == 0)
2809 image->resolution.y=image->resolution.x;
2811 if (LocaleCompare(image_info->magick,"MSVG") != 0)
2816 delegate_info=GetDelegateInfo("svg:decode",(char *) NULL,exception);
2817 if (delegate_info != (const DelegateInfo *) NULL)
2820 background[MaxTextExtent],
2821 command[MaxTextExtent],
2822 density[MaxTextExtent],
2823 filename[MaxTextExtent],
2824 opacity[MaxTextExtent],
2825 unique[MaxTextExtent];
2831 Our best hope for compliance to the SVG standard.
2833 (void) AcquireUniqueFilename(filename);
2834 (void) AcquireUniqueFilename(unique);
2835 (void) FormatLocaleString(density,MaxTextExtent,"%.20g,%.20g",
2836 image->resolution.x,image->resolution.y);
2837 (void) FormatLocaleString(background,MaxTextExtent,
2838 "rgb(%.20g%%,%.20g%%,%.20g%%)",
2839 100.0*QuantumScale*image->background_color.red,
2840 100.0*QuantumScale*image->background_color.green,
2841 100.0*QuantumScale*image->background_color.blue);
2842 (void) FormatLocaleString(opacity,MaxTextExtent,"%.20g",
2843 QuantumScale*image->background_color.alpha);
2844 (void) FormatLocaleString(command,MaxTextExtent,
2845 GetDelegateCommands(delegate_info),image->filename,filename,density,
2846 background,opacity,unique);
2847 status=SystemCommand(MagickFalse,image_info->verbose,command,
2849 (void) RelinquishUniqueFileResource(unique);
2855 read_info=CloneImageInfo(image_info);
2856 (void) CopyMagickString(read_info->filename,filename,
2858 image=ReadImage(read_info,exception);
2859 read_info=DestroyImageInfo(read_info);
2860 (void) RelinquishUniqueFileResource(filename);
2861 if (image != (Image *) NULL)
2864 (void) RelinquishUniqueFileResource(filename);
2867 #if defined(MAGICKCORE_RSVG_DELEGATE)
2868 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2875 register unsigned char
2888 register const guchar
2911 svg_handle=rsvg_handle_new();
2912 if (svg_handle == (RsvgHandle *) NULL)
2913 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2914 rsvg_handle_set_base_uri(svg_handle,image_info->filename);
2915 rsvg_handle_set_dpi_x_y(svg_handle,image->resolution.x,
2916 image->resolution.y);
2917 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
2919 error=(GError *) NULL;
2920 (void) rsvg_handle_write(svg_handle,message,n,&error);
2921 if (error != (GError *) NULL)
2922 g_error_free(error);
2924 error=(GError *) NULL;
2925 rsvg_handle_close(svg_handle,&error);
2926 if (error != (GError *) NULL)
2927 g_error_free(error);
2928 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2929 rsvg_handle_get_dimensions(svg_handle,&dimension_info);
2930 image->columns=image->resolution.x*dimension_info.width/72.0;
2931 image->rows=image->resolution.y*dimension_info.height/72.0;
2932 pixels=(unsigned char *) NULL;
2934 pixel_info=rsvg_handle_get_pixbuf(svg_handle);
2935 rsvg_handle_free(svg_handle);
2936 image->columns=gdk_pixbuf_get_width(pixel_info);
2937 image->rows=gdk_pixbuf_get_height(pixel_info);
2939 image->alpha_trait=BlendPixelTrait;
2940 SetImageProperty(image,"svg:base-uri",
2941 rsvg_handle_get_base_uri(svg_handle),exception);
2942 if ((image->columns == 0) || (image->rows == 0))
2944 #if !defined(MAGICKCORE_CAIRO_DELEGATE)
2945 g_object_unref(G_OBJECT(pixel_info));
2947 g_object_unref(svg_handle);
2948 ThrowReaderException(MissingDelegateError,
2949 "NoDecodeDelegateForThisImageFormat");
2951 if (image_info->ping == MagickFalse)
2956 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2957 stride=4*image->columns;
2958 #if defined(MAGICKCORE_PANGOCAIRO_DELEGATE)
2959 stride=(size_t) cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32,
2962 pixels=(unsigned char *) AcquireQuantumMemory(stride,image->rows*
2964 if (pixels == (unsigned char *) NULL)
2966 g_object_unref(svg_handle);
2967 ThrowReaderException(ResourceLimitError,
2968 "MemoryAllocationFailed");
2971 (void) SetImageBackgroundColor(image,exception);
2972 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2973 cairo_surface=cairo_image_surface_create_for_data(pixels,
2974 CAIRO_FORMAT_ARGB32,image->columns,image->rows,stride);
2975 if (cairo_surface == (cairo_surface_t *) NULL)
2977 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2978 g_object_unref(svg_handle);
2979 ThrowReaderException(ResourceLimitError,
2980 "MemoryAllocationFailed");
2982 cairo_image=cairo_create(cairo_surface);
2983 cairo_set_operator(cairo_image,CAIRO_OPERATOR_CLEAR);
2984 cairo_paint(cairo_image);
2985 cairo_set_operator(cairo_image,CAIRO_OPERATOR_OVER);
2986 cairo_scale(cairo_image,image->resolution.x/72.0,
2987 image->resolution.y/72.0);
2988 rsvg_handle_render_cairo(svg_handle,cairo_image);
2989 cairo_destroy(cairo_image);
2990 cairo_surface_destroy(cairo_surface);
2991 g_object_unref(svg_handle);
2994 p=gdk_pixbuf_get_pixels(pixel_info);
2996 GetPixelInfo(image,&fill_color);
2997 for (y=0; y < (ssize_t) image->rows; y++)
2999 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3000 if (q == (Quantum *) NULL)
3002 for (x=0; x < (ssize_t) image->columns; x++)
3004 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3005 fill_color.blue=ScaleCharToQuantum(*p++);
3006 fill_color.green=ScaleCharToQuantum(*p++);
3007 fill_color.red=ScaleCharToQuantum(*p++);
3009 fill_color.red=ScaleCharToQuantum(*p++);
3010 fill_color.green=ScaleCharToQuantum(*p++);
3011 fill_color.blue=ScaleCharToQuantum(*p++);
3013 fill_color.alpha=ScaleCharToQuantum(*p++);
3014 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3019 gamma=QuantumScale*fill_color.alpha;
3020 gamma=PerceptibleReciprocal(gamma);
3021 fill_color.blue*=gamma;
3022 fill_color.green*=gamma;
3023 fill_color.red*=gamma;
3026 CompositePixelOver(image,&fill_color,fill_color.alpha,q,(double)
3027 GetPixelAlpha(image,q),q);
3028 q+=GetPixelChannels(image);
3030 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3032 if (image->previous == (Image *) NULL)
3034 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
3036 if (status == MagickFalse)
3041 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3042 if (pixels != (unsigned char *) NULL)
3043 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
3045 g_object_unref(G_OBJECT(pixel_info));
3047 (void) CloseBlob(image);
3048 return(GetFirstImageInList(image));
3056 unique_file=AcquireUniqueFileResource(filename);
3057 if (unique_file != -1)
3058 file=fdopen(unique_file,"w");
3059 if ((unique_file == -1) || (file == (FILE *) NULL))
3061 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
3062 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
3064 image=DestroyImageList(image);
3065 return((Image *) NULL);
3070 svg_info=AcquireSVGInfo();
3071 if (svg_info == (SVGInfo *) NULL)
3072 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3073 svg_info->file=file;
3074 svg_info->exception=exception;
3075 svg_info->image=image;
3076 svg_info->image_info=image_info;
3077 svg_info->bounds.width=image->columns;
3078 svg_info->bounds.height=image->rows;
3079 if (image_info->size != (char *) NULL)
3080 (void) CloneString(&svg_info->size,image_info->size);
3081 if (image->debug != MagickFalse)
3082 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"begin SAX");
3084 (void) xmlSubstituteEntitiesDefault(1);
3085 (void) ResetMagickMemory(&sax_modules,0,sizeof(sax_modules));
3086 sax_modules.internalSubset=SVGInternalSubset;
3087 sax_modules.isStandalone=SVGIsStandalone;
3088 sax_modules.hasInternalSubset=SVGHasInternalSubset;
3089 sax_modules.hasExternalSubset=SVGHasExternalSubset;
3090 sax_modules.resolveEntity=SVGResolveEntity;
3091 sax_modules.getEntity=SVGGetEntity;
3092 sax_modules.entityDecl=SVGEntityDeclaration;
3093 sax_modules.notationDecl=SVGNotationDeclaration;
3094 sax_modules.attributeDecl=SVGAttributeDeclaration;
3095 sax_modules.elementDecl=SVGElementDeclaration;
3096 sax_modules.unparsedEntityDecl=SVGUnparsedEntityDeclaration;
3097 sax_modules.setDocumentLocator=SVGSetDocumentLocator;
3098 sax_modules.startDocument=SVGStartDocument;
3099 sax_modules.endDocument=SVGEndDocument;
3100 sax_modules.startElement=SVGStartElement;
3101 sax_modules.endElement=SVGEndElement;
3102 sax_modules.reference=SVGReference;
3103 sax_modules.characters=SVGCharacters;
3104 sax_modules.ignorableWhitespace=SVGIgnorableWhitespace;
3105 sax_modules.processingInstruction=SVGProcessingInstructions;
3106 sax_modules.comment=SVGComment;
3107 sax_modules.warning=SVGWarning;
3108 sax_modules.error=SVGError;
3109 sax_modules.fatalError=SVGError;
3110 sax_modules.getParameterEntity=SVGGetParameterEntity;
3111 sax_modules.cdataBlock=SVGCDataBlock;
3112 sax_modules.externalSubset=SVGExternalSubset;
3113 sax_handler=(&sax_modules);
3114 n=ReadBlob(image,MaxTextExtent,message);
3117 svg_info->parser=xmlCreatePushParserCtxt(sax_handler,svg_info,(char *)
3118 message,n,image->filename);
3119 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
3121 status=xmlParseChunk(svg_info->parser,(char *) message,(int) n,0);
3126 (void) xmlParseChunk(svg_info->parser,(char *) message,0,1);
3127 xmlFreeParserCtxt(svg_info->parser);
3128 if (image->debug != MagickFalse)
3129 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"end SAX");
3131 (void) fclose(file);
3132 (void) CloseBlob(image);
3133 image->columns=svg_info->width;
3134 image->rows=svg_info->height;
3135 if (exception->severity >= ErrorException)
3137 image=DestroyImage(image);
3138 return((Image *) NULL);
3140 if (image_info->ping == MagickFalse)
3148 image=DestroyImage(image);
3149 image=(Image *) NULL;
3150 read_info=CloneImageInfo(image_info);
3151 SetImageInfoBlob(read_info,(void *) NULL,0);
3152 if (read_info->density != (char *) NULL)
3153 read_info->density=DestroyString(read_info->density);
3154 (void) FormatLocaleString(read_info->filename,MaxTextExtent,"mvg:%s",
3156 image=ReadImage(read_info,exception);
3157 read_info=DestroyImageInfo(read_info);
3158 if (image != (Image *) NULL)
3159 (void) CopyMagickString(image->filename,image_info->filename,
3163 Relinquish resources.
3165 if (image != (Image *) NULL)
3167 if (svg_info->title != (char *) NULL)
3168 (void) SetImageProperty(image,"svg:title",svg_info->title,exception);
3169 if (svg_info->comment != (char *) NULL)
3170 (void) SetImageProperty(image,"svg:comment",svg_info->comment,
3173 svg_info=DestroySVGInfo(svg_info);
3174 (void) RelinquishUniqueFileResource(filename);
3175 return(GetFirstImageInList(image));
3180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3184 % R e g i s t e r S V G I m a g e %
3188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3190 % RegisterSVGImage() adds attributes for the SVG image format to
3191 % the list of supported formats. The attributes include the image format
3192 % tag, a method to read and/or write the format, whether the format
3193 % supports the saving of more than one frame to the same file or blob,
3194 % whether the format supports native in-memory I/O, and a brief
3195 % description of the format.
3197 % The format of the RegisterSVGImage method is:
3199 % size_t RegisterSVGImage(void)
3202 ModuleExport size_t RegisterSVGImage(void)
3205 version[MaxTextExtent];
3211 #if defined(LIBXML_DOTTED_VERSION)
3212 (void) CopyMagickString(version,"XML " LIBXML_DOTTED_VERSION,MaxTextExtent);
3214 #if defined(MAGICKCORE_RSVG_DELEGATE)
3216 (void) FormatLocaleString(version,MaxTextExtent,"RSVG %d.%d.%d",
3217 LIBRSVG_MAJOR_VERSION,LIBRSVG_MINOR_VERSION,LIBRSVG_MICRO_VERSION);
3219 entry=SetMagickInfo("SVG");
3220 #if defined(MAGICKCORE_XML_DELEGATE)
3221 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3223 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3224 entry->blob_support=MagickFalse;
3225 entry->seekable_stream=MagickFalse;
3226 entry->description=ConstantString("Scalable Vector Graphics");
3227 if (*version != '\0')
3228 entry->version=ConstantString(version);
3229 entry->magick=(IsImageFormatHandler *) IsSVG;
3230 entry->module=ConstantString("SVG");
3231 (void) RegisterMagickInfo(entry);
3232 entry=SetMagickInfo("SVGZ");
3233 #if defined(MAGICKCORE_XML_DELEGATE)
3234 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3236 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3237 entry->blob_support=MagickFalse;
3238 entry->seekable_stream=MagickFalse;
3239 entry->description=ConstantString("Compressed Scalable Vector Graphics");
3240 if (*version != '\0')
3241 entry->version=ConstantString(version);
3242 entry->magick=(IsImageFormatHandler *) IsSVG;
3243 entry->module=ConstantString("SVG");
3244 (void) RegisterMagickInfo(entry);
3245 entry=SetMagickInfo("MSVG");
3246 #if defined(MAGICKCORE_XML_DELEGATE)
3247 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3249 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3250 entry->blob_support=MagickFalse;
3251 entry->seekable_stream=MagickFalse;
3252 entry->description=ConstantString("ImageMagick's own SVG internal renderer");
3253 entry->magick=(IsImageFormatHandler *) IsSVG;
3254 entry->module=ConstantString("SVG");
3255 (void) RegisterMagickInfo(entry);
3256 return(MagickImageCoderSignature);
3260 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3264 % U n r e g i s t e r S V G I m a g e %
3268 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3270 % UnregisterSVGImage() removes format registrations made by the
3271 % SVG module from the list of supported formats.
3273 % The format of the UnregisterSVGImage method is:
3275 % UnregisterSVGImage(void)
3278 ModuleExport void UnregisterSVGImage(void)
3280 (void) UnregisterMagickInfo("SVGZ");
3281 (void) UnregisterMagickInfo("SVG");
3282 (void) UnregisterMagickInfo("MSVG");
3286 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3290 % W r i t e S V G I m a g e %
3294 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3296 % WriteSVGImage() writes a image in the SVG - XML based W3C standard
3299 % The format of the WriteSVGImage method is:
3301 % MagickBooleanType WriteSVGImage(const ImageInfo *image_info,
3302 % Image *image,ExceptionInfo *exception)
3304 % A description of each parameter follows.
3306 % o image_info: the image info.
3308 % o image: The image.
3310 % o exception: return any errors or warnings in this structure.
3314 static void AffineToTransform(Image *image,AffineMatrix *affine)
3317 transform[MaxTextExtent];
3319 if ((fabs(affine->tx) < MagickEpsilon) && (fabs(affine->ty) < MagickEpsilon))
3321 if ((fabs(affine->rx) < MagickEpsilon) &&
3322 (fabs(affine->ry) < MagickEpsilon))
3324 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3325 (fabs(affine->sy-1.0) < MagickEpsilon))
3327 (void) WriteBlobString(image,"\">\n");
3330 (void) FormatLocaleString(transform,MaxTextExtent,
3331 "\" transform=\"scale(%g,%g)\">\n",affine->sx,affine->sy);
3332 (void) WriteBlobString(image,transform);
3337 if ((fabs(affine->sx-affine->sy) < MagickEpsilon) &&
3338 (fabs(affine->rx+affine->ry) < MagickEpsilon) &&
3339 (fabs(affine->sx*affine->sx+affine->rx*affine->rx-1.0) <
3345 theta=(180.0/MagickPI)*atan2(affine->rx,affine->sx);
3346 (void) FormatLocaleString(transform,MaxTextExtent,
3347 "\" transform=\"rotate(%g)\">\n",theta);
3348 (void) WriteBlobString(image,transform);
3355 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3356 (fabs(affine->rx) < MagickEpsilon) &&
3357 (fabs(affine->ry) < MagickEpsilon) &&
3358 (fabs(affine->sy-1.0) < MagickEpsilon))
3360 (void) FormatLocaleString(transform,MaxTextExtent,
3361 "\" transform=\"translate(%g,%g)\">\n",affine->tx,affine->ty);
3362 (void) WriteBlobString(image,transform);
3366 (void) FormatLocaleString(transform,MaxTextExtent,
3367 "\" transform=\"matrix(%g %g %g %g %g %g)\">\n",
3368 affine->sx,affine->rx,affine->ry,affine->sy,affine->tx,affine->ty);
3369 (void) WriteBlobString(image,transform);
3372 static MagickBooleanType IsPoint(const char *point)
3380 value=strtol(point,&p,10);
3382 return(p != point ? MagickTrue : MagickFalse);
3385 static MagickBooleanType TraceSVGImage(Image *image,ExceptionInfo *exception)
3390 register const Quantum
3396 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
3401 at_fitting_opts_type
3420 Trace image and write as SVG.
3422 fitting_options=at_fitting_opts_new();
3423 output_options=at_output_opts_new();
3424 type=GetImageType(image,exception);
3426 if ((type == BilevelType) || (type == GrayscaleType))
3428 trace=at_bitmap_new(image->columns,image->rows,number_planes);
3430 for (y=0; y < (ssize_t) image->rows; y++)
3432 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3433 if (p == (const Quantum *) NULL)
3435 for (x=0; x < (ssize_t) image->columns; x++)
3437 trace->bitmap[i++]=GetPixelRed(image,p);
3438 if (number_planes == 3)
3440 trace->bitmap[i++]=GetPixelGreen(image,p);
3441 trace->bitmap[i++]=GetPixelBlue(image,p);
3443 p+=GetPixelChannels(image);
3446 splines=at_splines_new_full(trace,fitting_options,NULL,NULL,NULL,NULL,NULL,
3448 at_splines_write(at_output_get_handler_by_suffix((char *) "svg"),
3449 GetBlobFileHandle(image),image->filename,output_options,splines,NULL,
3454 at_splines_free(splines);
3455 at_bitmap_free(trace);
3456 at_output_opts_free(output_options);
3457 at_fitting_opts_free(fitting_options);
3462 message[MaxTextExtent],
3463 tuple[MaxTextExtent];
3468 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3469 (void) WriteBlobString(image,
3470 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3471 (void) WriteBlobString(image,
3472 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3473 (void) FormatLocaleString(message,MaxTextExtent,
3474 "<svg width=\"%.20g\" height=\"%.20g\">\n",(double) image->columns,
3475 (double) image->rows);
3476 (void) WriteBlobString(image,message);
3477 GetPixelInfo(image,&pixel);
3478 for (y=0; y < (ssize_t) image->rows; y++)
3480 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3481 if (p == (const Quantum *) NULL)
3483 for (x=0; x < (ssize_t) image->columns; x++)
3485 GetPixelInfoPixel(image,p,&pixel);
3486 (void) QueryColorname(image,&pixel,SVGCompliance,tuple,exception);
3487 (void) FormatLocaleString(message,MaxTextExtent,
3488 " <circle cx=\"%.20g\" cy=\"%.20g\" r=\"1\" fill=\"%s\"/>\n",
3489 (double) x,(double) y,tuple);
3490 (void) WriteBlobString(image,message);
3491 p+=GetPixelChannels(image);
3494 (void) WriteBlobString(image,"</svg>\n");
3500 static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
3501 ExceptionInfo *exception)
3503 #define BezierQuantum 200
3509 keyword[MaxTextExtent],
3510 message[MaxTextExtent],
3511 name[MaxTextExtent],
3513 type[MaxTextExtent];
3555 Open output image file.
3557 assert(image_info != (const ImageInfo *) NULL);
3558 assert(image_info->signature == MagickSignature);
3559 assert(image != (Image *) NULL);
3560 assert(image->signature == MagickSignature);
3561 if (image->debug != MagickFalse)
3562 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3563 assert(exception != (ExceptionInfo *) NULL);
3564 assert(exception->signature == MagickSignature);
3565 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
3566 if (status == MagickFalse)
3568 value=GetImageArtifact(image,"SVG");
3569 if (value != (char *) NULL)
3571 (void) WriteBlobString(image,value);
3572 (void) CloseBlob(image);
3575 value=GetImageArtifact(image,"MVG");
3576 if (value == (char *) NULL)
3577 return(TraceSVGImage(image,exception));
3581 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3582 (void) WriteBlobString(image,
3583 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3584 (void) WriteBlobString(image,
3585 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3586 (void) FormatLocaleString(message,MaxTextExtent,
3587 "<svg width=\"%.20g\" height=\"%.20g\">\n",(double) image->columns,(double)
3589 (void) WriteBlobString(image,message);
3591 Allocate primitive info memory.
3594 primitive_info=(PrimitiveInfo *) AcquireQuantumMemory(number_points,
3595 sizeof(*primitive_info));
3596 if (primitive_info == (PrimitiveInfo *) NULL)
3597 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3598 GetAffineMatrix(&affine);
3599 token=AcquireString(value);
3603 for (q=(const char *) value; *q != '\0'; )
3606 Interpret graphic primitive.
3608 GetMagickToken(q,&q,keyword);
3609 if (*keyword == '\0')
3611 if (*keyword == '#')
3616 if (active != MagickFalse)
3618 AffineToTransform(image,&affine);
3621 (void) WriteBlobString(image,"<desc>");
3622 (void) WriteBlobString(image,keyword+1);
3623 for ( ; (*q != '\n') && (*q != '\0'); q++)
3626 case '<': (void) WriteBlobString(image,"<"); break;
3627 case '>': (void) WriteBlobString(image,">"); break;
3628 case '&': (void) WriteBlobString(image,"&"); break;
3629 default: (void) WriteBlobByte(image,*q); break;
3631 (void) WriteBlobString(image,"</desc>\n");
3634 primitive_type=UndefinedPrimitive;
3642 if (LocaleCompare("affine",keyword) == 0)
3644 GetMagickToken(q,&q,token);
3645 affine.sx=StringToDouble(token,(char **) NULL);
3646 GetMagickToken(q,&q,token);
3648 GetMagickToken(q,&q,token);
3649 affine.rx=StringToDouble(token,(char **) NULL);
3650 GetMagickToken(q,&q,token);
3652 GetMagickToken(q,&q,token);
3653 affine.ry=StringToDouble(token,(char **) NULL);
3654 GetMagickToken(q,&q,token);
3656 GetMagickToken(q,&q,token);
3657 affine.sy=StringToDouble(token,(char **) NULL);
3658 GetMagickToken(q,&q,token);
3660 GetMagickToken(q,&q,token);
3661 affine.tx=StringToDouble(token,(char **) NULL);
3662 GetMagickToken(q,&q,token);
3664 GetMagickToken(q,&q,token);
3665 affine.ty=StringToDouble(token,(char **) NULL);
3668 if (LocaleCompare("angle",keyword) == 0)
3670 GetMagickToken(q,&q,token);
3671 affine.rx=StringToDouble(token,(char **) NULL);
3672 affine.ry=StringToDouble(token,(char **) NULL);
3675 if (LocaleCompare("arc",keyword) == 0)
3677 primitive_type=ArcPrimitive;
3686 if (LocaleCompare("bezier",keyword) == 0)
3688 primitive_type=BezierPrimitive;
3697 if (LocaleCompare("clip-path",keyword) == 0)
3699 GetMagickToken(q,&q,token);
3700 (void) FormatLocaleString(message,MaxTextExtent,
3701 "clip-path:url(#%s);",token);
3702 (void) WriteBlobString(image,message);
3705 if (LocaleCompare("clip-rule",keyword) == 0)
3707 GetMagickToken(q,&q,token);
3708 (void) FormatLocaleString(message,MaxTextExtent,
3709 "clip-rule:%s;",token);
3710 (void) WriteBlobString(image,message);
3713 if (LocaleCompare("clip-units",keyword) == 0)
3715 GetMagickToken(q,&q,token);
3716 (void) FormatLocaleString(message,MaxTextExtent,
3717 "clipPathUnits=%s;",token);
3718 (void) WriteBlobString(image,message);
3721 if (LocaleCompare("circle",keyword) == 0)
3723 primitive_type=CirclePrimitive;
3726 if (LocaleCompare("color",keyword) == 0)
3728 primitive_type=ColorPrimitive;
3737 if (LocaleCompare("decorate",keyword) == 0)
3739 GetMagickToken(q,&q,token);
3740 (void) FormatLocaleString(message,MaxTextExtent,
3741 "text-decoration:%s;",token);
3742 (void) WriteBlobString(image,message);
3751 if (LocaleCompare("ellipse",keyword) == 0)
3753 primitive_type=EllipsePrimitive;
3762 if (LocaleCompare("fill",keyword) == 0)
3764 GetMagickToken(q,&q,token);
3765 (void) FormatLocaleString(message,MaxTextExtent,"fill:%s;",
3767 (void) WriteBlobString(image,message);
3770 if (LocaleCompare("fill-rule",keyword) == 0)
3772 GetMagickToken(q,&q,token);
3773 (void) FormatLocaleString(message,MaxTextExtent,
3774 "fill-rule:%s;",token);
3775 (void) WriteBlobString(image,message);
3778 if (LocaleCompare("fill-alpha",keyword) == 0)
3780 GetMagickToken(q,&q,token);
3781 (void) FormatLocaleString(message,MaxTextExtent,
3782 "fill-alpha:%s;",token);
3783 (void) WriteBlobString(image,message);
3786 if (LocaleCompare("font-family",keyword) == 0)
3788 GetMagickToken(q,&q,token);
3789 (void) FormatLocaleString(message,MaxTextExtent,
3790 "font-family:%s;",token);
3791 (void) WriteBlobString(image,message);
3794 if (LocaleCompare("font-stretch",keyword) == 0)
3796 GetMagickToken(q,&q,token);
3797 (void) FormatLocaleString(message,MaxTextExtent,
3798 "font-stretch:%s;",token);
3799 (void) WriteBlobString(image,message);
3802 if (LocaleCompare("font-style",keyword) == 0)
3804 GetMagickToken(q,&q,token);
3805 (void) FormatLocaleString(message,MaxTextExtent,
3806 "font-style:%s;",token);
3807 (void) WriteBlobString(image,message);
3810 if (LocaleCompare("font-size",keyword) == 0)
3812 GetMagickToken(q,&q,token);
3813 (void) FormatLocaleString(message,MaxTextExtent,
3814 "font-size:%s;",token);
3815 (void) WriteBlobString(image,message);
3818 if (LocaleCompare("font-weight",keyword) == 0)
3820 GetMagickToken(q,&q,token);
3821 (void) FormatLocaleString(message,MaxTextExtent,
3822 "font-weight:%s;",token);
3823 (void) WriteBlobString(image,message);
3832 if (LocaleCompare("gradient-units",keyword) == 0)
3834 GetMagickToken(q,&q,token);
3837 if (LocaleCompare("text-align",keyword) == 0)
3839 GetMagickToken(q,&q,token);
3840 (void) FormatLocaleString(message,MaxTextExtent,
3841 "text-align %s ",token);
3842 (void) WriteBlobString(image,message);
3845 if (LocaleCompare("text-anchor",keyword) == 0)
3847 GetMagickToken(q,&q,token);
3848 (void) FormatLocaleString(message,MaxTextExtent,
3849 "text-anchor %s ",token);
3850 (void) WriteBlobString(image,message);
3859 if (LocaleCompare("image",keyword) == 0)
3861 GetMagickToken(q,&q,token);
3862 primitive_type=ImagePrimitive;
3871 if (LocaleCompare("line",keyword) == 0)
3873 primitive_type=LinePrimitive;
3882 if (LocaleCompare("matte",keyword) == 0)
3884 primitive_type=MattePrimitive;
3893 if (LocaleCompare("opacity",keyword) == 0)
3895 GetMagickToken(q,&q,token);
3896 (void) FormatLocaleString(message,MaxTextExtent,"opacity %s ",
3898 (void) WriteBlobString(image,message);
3907 if (LocaleCompare("path",keyword) == 0)
3909 primitive_type=PathPrimitive;
3912 if (LocaleCompare("point",keyword) == 0)
3914 primitive_type=PointPrimitive;
3917 if (LocaleCompare("polyline",keyword) == 0)
3919 primitive_type=PolylinePrimitive;
3922 if (LocaleCompare("polygon",keyword) == 0)
3924 primitive_type=PolygonPrimitive;
3927 if (LocaleCompare("pop",keyword) == 0)
3929 GetMagickToken(q,&q,token);
3930 if (LocaleCompare("clip-path",token) == 0)
3932 (void) WriteBlobString(image,"</clipPath>\n");
3935 if (LocaleCompare("defs",token) == 0)
3937 (void) WriteBlobString(image,"</defs>\n");
3940 if (LocaleCompare("gradient",token) == 0)
3942 (void) FormatLocaleString(message,MaxTextExtent,
3943 "</%sGradient>\n",type);
3944 (void) WriteBlobString(image,message);
3947 if (LocaleCompare("graphic-context",token) == 0)
3951 ThrowWriterException(DrawError,
3952 "UnbalancedGraphicContextPushPop");
3953 (void) WriteBlobString(image,"</g>\n");
3955 if (LocaleCompare("pattern",token) == 0)
3957 (void) WriteBlobString(image,"</pattern>\n");
3960 if (LocaleCompare("defs",token) == 0)
3961 (void) WriteBlobString(image,"</g>\n");
3964 if (LocaleCompare("push",keyword) == 0)
3966 GetMagickToken(q,&q,token);
3967 if (LocaleCompare("clip-path",token) == 0)
3969 GetMagickToken(q,&q,token);
3970 (void) FormatLocaleString(message,MaxTextExtent,
3971 "<clipPath id=\"%s\">\n",token);
3972 (void) WriteBlobString(image,message);
3975 if (LocaleCompare("defs",token) == 0)
3977 (void) WriteBlobString(image,"<defs>\n");
3980 if (LocaleCompare("gradient",token) == 0)
3982 GetMagickToken(q,&q,token);
3983 (void) CopyMagickString(name,token,MaxTextExtent);
3984 GetMagickToken(q,&q,token);
3985 (void) CopyMagickString(type,token,MaxTextExtent);
3986 GetMagickToken(q,&q,token);
3987 svg_info.segment.x1=StringToDouble(token,(char **) NULL);
3988 svg_info.element.cx=StringToDouble(token,(char **) NULL);
3989 GetMagickToken(q,&q,token);
3991 GetMagickToken(q,&q,token);
3992 svg_info.segment.y1=StringToDouble(token,(char **) NULL);
3993 svg_info.element.cy=StringToDouble(token,(char **) NULL);
3994 GetMagickToken(q,&q,token);
3996 GetMagickToken(q,&q,token);
3997 svg_info.segment.x2=StringToDouble(token,(char **) NULL);
3998 svg_info.element.major=StringToDouble(token,
4000 GetMagickToken(q,&q,token);
4002 GetMagickToken(q,&q,token);
4003 svg_info.segment.y2=StringToDouble(token,(char **) NULL);
4004 svg_info.element.minor=StringToDouble(token,
4006 (void) FormatLocaleString(message,MaxTextExtent,
4007 "<%sGradient id=\"%s\" x1=\"%g\" y1=\"%g\" x2=\"%g\" "
4008 "y2=\"%g\">\n",type,name,svg_info.segment.x1,
4009 svg_info.segment.y1,svg_info.segment.x2,svg_info.segment.y2);
4010 if (LocaleCompare(type,"radial") == 0)
4012 GetMagickToken(q,&q,token);
4014 GetMagickToken(q,&q,token);
4015 svg_info.element.angle=StringToDouble(token,
4017 (void) FormatLocaleString(message,MaxTextExtent,
4018 "<%sGradient id=\"%s\" cx=\"%g\" cy=\"%g\" r=\"%g\" "
4019 "fx=\"%g\" fy=\"%g\">\n",type,name,
4020 svg_info.element.cx,svg_info.element.cy,
4021 svg_info.element.angle,svg_info.element.major,
4022 svg_info.element.minor);
4024 (void) WriteBlobString(image,message);
4027 if (LocaleCompare("graphic-context",token) == 0)
4032 AffineToTransform(image,&affine);
4035 (void) WriteBlobString(image,"<g style=\"");
4038 if (LocaleCompare("pattern",token) == 0)
4040 GetMagickToken(q,&q,token);
4041 (void) CopyMagickString(name,token,MaxTextExtent);
4042 GetMagickToken(q,&q,token);
4043 svg_info.bounds.x=StringToDouble(token,(char **) NULL);
4044 GetMagickToken(q,&q,token);
4046 GetMagickToken(q,&q,token);
4047 svg_info.bounds.y=StringToDouble(token,(char **) NULL);
4048 GetMagickToken(q,&q,token);
4050 GetMagickToken(q,&q,token);
4051 svg_info.bounds.width=StringToDouble(token,
4053 GetMagickToken(q,&q,token);
4055 GetMagickToken(q,&q,token);
4056 svg_info.bounds.height=StringToDouble(token,
4058 (void) FormatLocaleString(message,MaxTextExtent,
4059 "<pattern id=\"%s\" x=\"%g\" y=\"%g\" width=\"%g\" "
4060 "height=\"%g\">\n",name,svg_info.bounds.x,
4061 svg_info.bounds.y,svg_info.bounds.width,
4062 svg_info.bounds.height);
4063 (void) WriteBlobString(image,message);
4074 if (LocaleCompare("rectangle",keyword) == 0)
4076 primitive_type=RectanglePrimitive;
4079 if (LocaleCompare("roundRectangle",keyword) == 0)
4081 primitive_type=RoundRectanglePrimitive;
4084 if (LocaleCompare("rotate",keyword) == 0)
4086 GetMagickToken(q,&q,token);
4087 (void) FormatLocaleString(message,MaxTextExtent,"rotate(%s) ",
4089 (void) WriteBlobString(image,message);
4098 if (LocaleCompare("scale",keyword) == 0)
4100 GetMagickToken(q,&q,token);
4101 affine.sx=StringToDouble(token,(char **) NULL);
4102 GetMagickToken(q,&q,token);
4104 GetMagickToken(q,&q,token);
4105 affine.sy=StringToDouble(token,(char **) NULL);
4108 if (LocaleCompare("skewX",keyword) == 0)
4110 GetMagickToken(q,&q,token);
4111 (void) FormatLocaleString(message,MaxTextExtent,"skewX(%s) ",
4113 (void) WriteBlobString(image,message);
4116 if (LocaleCompare("skewY",keyword) == 0)
4118 GetMagickToken(q,&q,token);
4119 (void) FormatLocaleString(message,MaxTextExtent,"skewY(%s) ",
4121 (void) WriteBlobString(image,message);
4124 if (LocaleCompare("stop-color",keyword) == 0)
4127 color[MaxTextExtent];
4129 GetMagickToken(q,&q,token);
4130 (void) CopyMagickString(color,token,MaxTextExtent);
4131 GetMagickToken(q,&q,token);
4132 (void) FormatLocaleString(message,MaxTextExtent,
4133 " <stop offset=\"%s\" stop-color=\"%s\" />\n",token,color);
4134 (void) WriteBlobString(image,message);
4137 if (LocaleCompare("stroke",keyword) == 0)
4139 GetMagickToken(q,&q,token);
4140 (void) FormatLocaleString(message,MaxTextExtent,"stroke:%s;",
4142 (void) WriteBlobString(image,message);
4145 if (LocaleCompare("stroke-antialias",keyword) == 0)
4147 GetMagickToken(q,&q,token);
4148 (void) FormatLocaleString(message,MaxTextExtent,
4149 "stroke-antialias:%s;",token);
4150 (void) WriteBlobString(image,message);
4153 if (LocaleCompare("stroke-dasharray",keyword) == 0)
4161 GetMagickToken(p,&p,token);
4162 for (k=0; IsPoint(token); k++)
4163 GetMagickToken(p,&p,token);
4164 (void) WriteBlobString(image,"stroke-dasharray:");
4165 for (j=0; j < k; j++)
4167 GetMagickToken(q,&q,token);
4168 (void) FormatLocaleString(message,MaxTextExtent,"%s ",
4170 (void) WriteBlobString(image,message);
4172 (void) WriteBlobString(image,";");
4175 GetMagickToken(q,&q,token);
4176 (void) FormatLocaleString(message,MaxTextExtent,
4177 "stroke-dasharray:%s;",token);
4178 (void) WriteBlobString(image,message);
4181 if (LocaleCompare("stroke-dashoffset",keyword) == 0)
4183 GetMagickToken(q,&q,token);
4184 (void) FormatLocaleString(message,MaxTextExtent,
4185 "stroke-dashoffset:%s;",token);
4186 (void) WriteBlobString(image,message);
4189 if (LocaleCompare("stroke-linecap",keyword) == 0)
4191 GetMagickToken(q,&q,token);
4192 (void) FormatLocaleString(message,MaxTextExtent,
4193 "stroke-linecap:%s;",token);
4194 (void) WriteBlobString(image,message);
4197 if (LocaleCompare("stroke-linejoin",keyword) == 0)
4199 GetMagickToken(q,&q,token);
4200 (void) FormatLocaleString(message,MaxTextExtent,
4201 "stroke-linejoin:%s;",token);
4202 (void) WriteBlobString(image,message);
4205 if (LocaleCompare("stroke-miterlimit",keyword) == 0)
4207 GetMagickToken(q,&q,token);
4208 (void) FormatLocaleString(message,MaxTextExtent,
4209 "stroke-miterlimit:%s;",token);
4210 (void) WriteBlobString(image,message);
4213 if (LocaleCompare("stroke-opacity",keyword) == 0)
4215 GetMagickToken(q,&q,token);
4216 (void) FormatLocaleString(message,MaxTextExtent,
4217 "stroke-opacity:%s;",token);
4218 (void) WriteBlobString(image,message);
4221 if (LocaleCompare("stroke-width",keyword) == 0)
4223 GetMagickToken(q,&q,token);
4224 (void) FormatLocaleString(message,MaxTextExtent,
4225 "stroke-width:%s;",token);
4226 (void) WriteBlobString(image,message);
4235 if (LocaleCompare("text",keyword) == 0)
4237 primitive_type=TextPrimitive;
4240 if (LocaleCompare("text-antialias",keyword) == 0)
4242 GetMagickToken(q,&q,token);
4243 (void) FormatLocaleString(message,MaxTextExtent,
4244 "text-antialias:%s;",token);
4245 (void) WriteBlobString(image,message);
4248 if (LocaleCompare("tspan",keyword) == 0)
4250 primitive_type=TextPrimitive;
4253 if (LocaleCompare("translate",keyword) == 0)
4255 GetMagickToken(q,&q,token);
4256 affine.tx=StringToDouble(token,(char **) NULL);
4257 GetMagickToken(q,&q,token);
4259 GetMagickToken(q,&q,token);
4260 affine.ty=StringToDouble(token,(char **) NULL);
4269 if (LocaleCompare("viewbox",keyword) == 0)
4271 GetMagickToken(q,&q,token);
4273 GetMagickToken(q,&q,token);
4274 GetMagickToken(q,&q,token);
4276 GetMagickToken(q,&q,token);
4277 GetMagickToken(q,&q,token);
4279 GetMagickToken(q,&q,token);
4280 GetMagickToken(q,&q,token);
4292 if (status == MagickFalse)
4294 if (primitive_type == UndefinedPrimitive)
4297 Parse the primitive attributes.
4301 for (x=0; *q != '\0'; x++)
4306 if (IsPoint(q) == MagickFalse)
4308 GetMagickToken(q,&q,token);
4309 point.x=StringToDouble(token,(char **) NULL);
4310 GetMagickToken(q,&q,token);
4312 GetMagickToken(q,&q,token);
4313 point.y=StringToDouble(token,(char **) NULL);
4314 GetMagickToken(q,(const char **) NULL,token);
4316 GetMagickToken(q,&q,token);
4317 primitive_info[i].primitive=primitive_type;
4318 primitive_info[i].point=point;
4319 primitive_info[i].coordinates=0;
4320 primitive_info[i].method=FloodfillMethod;
4322 if (i < (ssize_t) (number_points-6*BezierQuantum-360))
4324 number_points+=6*BezierQuantum+360;
4325 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4326 number_points,sizeof(*primitive_info));
4327 if (primitive_info == (PrimitiveInfo *) NULL)
4329 (void) ThrowMagickException(exception,GetMagickModule(),
4330 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
4334 primitive_info[j].primitive=primitive_type;
4335 primitive_info[j].coordinates=x;
4336 primitive_info[j].method=FloodfillMethod;
4337 primitive_info[j].text=(char *) NULL;
4340 AffineToTransform(image,&affine);
4344 switch (primitive_type)
4346 case PointPrimitive:
4349 if (primitive_info[j].coordinates != 1)
4358 if (primitive_info[j].coordinates != 2)
4363 (void) FormatLocaleString(message,MaxTextExtent,
4364 " <line x1=\"%g\" y1=\"%g\" x2=\"%g\" y2=\"%g\"/>\n",
4365 primitive_info[j].point.x,primitive_info[j].point.y,
4366 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4367 (void) WriteBlobString(image,message);
4370 case RectanglePrimitive:
4372 if (primitive_info[j].coordinates != 2)
4377 (void) FormatLocaleString(message,MaxTextExtent,
4378 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"/>\n",
4379 primitive_info[j].point.x,primitive_info[j].point.y,
4380 primitive_info[j+1].point.x-primitive_info[j].point.x,
4381 primitive_info[j+1].point.y-primitive_info[j].point.y);
4382 (void) WriteBlobString(image,message);
4385 case RoundRectanglePrimitive:
4387 if (primitive_info[j].coordinates != 3)
4392 (void) FormatLocaleString(message,MaxTextExtent,
4393 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" rx=\"%g\" "
4394 "ry=\"%g\"/>\n",primitive_info[j].point.x,
4395 primitive_info[j].point.y,primitive_info[j+1].point.x-
4396 primitive_info[j].point.x,primitive_info[j+1].point.y-
4397 primitive_info[j].point.y,primitive_info[j+2].point.x,
4398 primitive_info[j+2].point.y);
4399 (void) WriteBlobString(image,message);
4404 if (primitive_info[j].coordinates != 3)
4411 case EllipsePrimitive:
4413 if (primitive_info[j].coordinates != 3)
4418 (void) FormatLocaleString(message,MaxTextExtent,
4419 " <ellipse cx=\"%g\" cy=\"%g\" rx=\"%g\" ry=\"%g\"/>\n",
4420 primitive_info[j].point.x,primitive_info[j].point.y,
4421 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4422 (void) WriteBlobString(image,message);
4425 case CirclePrimitive:
4431 if (primitive_info[j].coordinates != 2)
4436 alpha=primitive_info[j+1].point.x-primitive_info[j].point.x;
4437 beta=primitive_info[j+1].point.y-primitive_info[j].point.y;
4438 (void) FormatLocaleString(message,MaxTextExtent,
4439 " <circle cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
4440 primitive_info[j].point.x,primitive_info[j].point.y,
4442 (void) WriteBlobString(image,message);
4445 case PolylinePrimitive:
4447 if (primitive_info[j].coordinates < 2)
4452 (void) CopyMagickString(message," <polyline points=\"",MaxTextExtent);
4453 (void) WriteBlobString(image,message);
4454 length=strlen(message);
4457 (void) FormatLocaleString(message,MaxTextExtent,"%g,%g ",
4458 primitive_info[j].point.x,primitive_info[j].point.y);
4459 length+=strlen(message);
4462 (void) WriteBlobString(image,"\n ");
4463 length=strlen(message)+5;
4465 (void) WriteBlobString(image,message);
4467 (void) WriteBlobString(image,"\"/>\n");
4470 case PolygonPrimitive:
4472 if (primitive_info[j].coordinates < 3)
4477 primitive_info[i]=primitive_info[j];
4478 primitive_info[i].coordinates=0;
4479 primitive_info[j].coordinates++;
4481 (void) CopyMagickString(message," <polygon points=\"",MaxTextExtent);
4482 (void) WriteBlobString(image,message);
4483 length=strlen(message);
4486 (void) FormatLocaleString(message,MaxTextExtent,"%g,%g ",
4487 primitive_info[j].point.x,primitive_info[j].point.y);
4488 length+=strlen(message);
4491 (void) WriteBlobString(image,"\n ");
4492 length=strlen(message)+5;
4494 (void) WriteBlobString(image,message);
4496 (void) WriteBlobString(image,"\"/>\n");
4499 case BezierPrimitive:
4501 if (primitive_info[j].coordinates < 3)
4513 GetMagickToken(q,&q,token);
4514 number_attributes=1;
4515 for (p=token; *p != '\0'; p++)
4516 if (isalpha((int) *p))
4517 number_attributes++;
4518 if (i > (ssize_t) (number_points-6*BezierQuantum*number_attributes-1))
4520 number_points+=6*BezierQuantum*number_attributes;
4521 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4522 number_points,sizeof(*primitive_info));
4523 if (primitive_info == (PrimitiveInfo *) NULL)
4525 (void) ThrowMagickException(exception,GetMagickModule(),
4526 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4531 (void) WriteBlobString(image," <path d=\"");
4532 (void) WriteBlobString(image,token);
4533 (void) WriteBlobString(image,"\"/>\n");
4536 case ColorPrimitive:
4537 case MattePrimitive:
4539 if (primitive_info[j].coordinates != 1)
4544 GetMagickToken(q,&q,token);
4545 if (LocaleCompare("point",token) == 0)
4546 primitive_info[j].method=PointMethod;
4547 if (LocaleCompare("replace",token) == 0)
4548 primitive_info[j].method=ReplaceMethod;
4549 if (LocaleCompare("floodfill",token) == 0)
4550 primitive_info[j].method=FloodfillMethod;
4551 if (LocaleCompare("filltoborder",token) == 0)
4552 primitive_info[j].method=FillToBorderMethod;
4553 if (LocaleCompare("reset",token) == 0)
4554 primitive_info[j].method=ResetMethod;
4562 if (primitive_info[j].coordinates != 1)
4567 GetMagickToken(q,&q,token);
4568 (void) FormatLocaleString(message,MaxTextExtent,
4569 " <text x=\"%g\" y=\"%g\">",primitive_info[j].point.x,
4570 primitive_info[j].point.y);
4571 (void) WriteBlobString(image,message);
4572 for (p=token; *p != '\0'; p++)
4575 case '<': (void) WriteBlobString(image,"<"); break;
4576 case '>': (void) WriteBlobString(image,">"); break;
4577 case '&': (void) WriteBlobString(image,"&"); break;
4578 default: (void) WriteBlobByte(image,*p); break;
4580 (void) WriteBlobString(image,"</text>\n");
4583 case ImagePrimitive:
4585 if (primitive_info[j].coordinates != 2)
4590 GetMagickToken(q,&q,token);
4591 (void) FormatLocaleString(message,MaxTextExtent,
4592 " <image x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" "
4593 "xlink:href=\"%s\"/>\n",primitive_info[j].point.x,
4594 primitive_info[j].point.y,primitive_info[j+1].point.x,
4595 primitive_info[j+1].point.y,token);
4596 (void) WriteBlobString(image,message);
4600 if (primitive_info == (PrimitiveInfo *) NULL)
4602 primitive_info[i].primitive=UndefinedPrimitive;
4603 if (status == MagickFalse)
4606 (void) WriteBlobString(image,"</svg>\n");
4608 Relinquish resources.
4610 token=DestroyString(token);
4611 if (primitive_info != (PrimitiveInfo *) NULL)
4612 primitive_info=(PrimitiveInfo *) RelinquishMagickMemory(primitive_info);
4613 (void) CloseBlob(image);