2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Scalable Vector Graphics Format %
21 % Copyright 1999-2017 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 % https://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 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
44 #include "MagickCore/studio.h"
45 #include "MagickCore/annotate.h"
46 #include "MagickCore/artifact.h"
47 #include "MagickCore/attribute.h"
48 #include "MagickCore/blob.h"
49 #include "MagickCore/blob-private.h"
50 #include "MagickCore/cache.h"
51 #include "MagickCore/constitute.h"
52 #include "MagickCore/composite-private.h"
53 #include "MagickCore/delegate.h"
54 #include "MagickCore/delegate-private.h"
55 #include "MagickCore/draw.h"
56 #include "MagickCore/exception.h"
57 #include "MagickCore/exception-private.h"
58 #include "MagickCore/gem.h"
59 #include "MagickCore/image.h"
60 #include "MagickCore/image-private.h"
61 #include "MagickCore/list.h"
62 #include "MagickCore/log.h"
63 #include "MagickCore/magick.h"
64 #include "MagickCore/memory_.h"
65 #include "MagickCore/module.h"
66 #include "MagickCore/monitor.h"
67 #include "MagickCore/monitor-private.h"
68 #include "MagickCore/quantum-private.h"
69 #include "MagickCore/pixel-accessor.h"
70 #include "MagickCore/property.h"
71 #include "MagickCore/resource_.h"
72 #include "MagickCore/static.h"
73 #include "MagickCore/string_.h"
74 #include "MagickCore/string-private.h"
75 #include "MagickCore/token.h"
76 #include "MagickCore/utility.h"
77 #if defined(MAGICKCORE_XML_DELEGATE)
78 # if defined(MAGICKCORE_WINDOWS_SUPPORT)
79 # if !defined(__MINGW32__)
80 # include <win32config.h>
83 # include <libxml/parser.h>
84 # include <libxml/xmlmemory.h>
85 # include <libxml/parserInternals.h>
86 # include <libxml/xmlerror.h>
89 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
90 #include "autotrace/autotrace.h"
93 #if defined(MAGICKCORE_RSVG_DELEGATE)
94 #include "librsvg/rsvg.h"
95 #if !defined(LIBRSVG_CHECK_VERSION)
96 #include "librsvg/rsvg-cairo.h"
97 #include "librsvg/librsvg-features.h"
98 #elif !LIBRSVG_CHECK_VERSION(2,36,2)
99 #include "librsvg/rsvg-cairo.h"
100 #include "librsvg/librsvg-features.h"
106 Typedef declarations.
108 typedef struct _BoundingBox
117 typedef struct _ElementInfo
127 typedef struct _SVGInfo
181 #if defined(MAGICKCORE_XML_DELEGATE)
192 Forward declarations.
194 static MagickBooleanType
195 WriteSVGImage(const ImageInfo *,Image *,ExceptionInfo *);
199 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
207 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
209 % IsSVG()() returns MagickTrue if the image format type, identified by the
210 % magick string, is SVG.
212 % The format of the IsSVG method is:
214 % MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
216 % A description of each parameter follows:
218 % o magick: compare image format pattern against these bytes.
220 % o length: Specifies the length of the magick string.
223 static MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
227 if (LocaleNCompare((const char *) magick,"?xml",4) == 0)
232 #if defined(MAGICKCORE_XML_DELEGATE)
234 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
238 % R e a d S V G I m a g e %
242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
244 % ReadSVGImage() reads a Scalable Vector Gaphics file and returns it. It
245 % allocates the memory necessary for the new Image structure and returns a
246 % pointer to the new image.
248 % The format of the ReadSVGImage method is:
250 % Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
252 % A description of each parameter follows:
254 % o image_info: the image info.
256 % o exception: return any errors or warnings in this structure.
260 static SVGInfo *AcquireSVGInfo(void)
265 svg_info=(SVGInfo *) AcquireMagickMemory(sizeof(*svg_info));
266 if (svg_info == (SVGInfo *) NULL)
267 return((SVGInfo *) NULL);
268 (void) ResetMagickMemory(svg_info,0,sizeof(*svg_info));
269 svg_info->text=AcquireString("");
270 svg_info->scale=(double *) AcquireMagickMemory(sizeof(*svg_info->scale));
271 if (svg_info->scale == (double *) NULL)
272 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
273 GetAffineMatrix(&svg_info->affine);
274 svg_info->scale[0]=ExpandAffine(&svg_info->affine);
278 static SVGInfo *DestroySVGInfo(SVGInfo *svg_info)
280 if (svg_info->text != (char *) NULL)
281 svg_info->text=DestroyString(svg_info->text);
282 if (svg_info->scale != (double *) NULL)
283 svg_info->scale=(double *) RelinquishMagickMemory(svg_info->scale);
284 if (svg_info->title != (char *) NULL)
285 svg_info->title=DestroyString(svg_info->title);
286 if (svg_info->comment != (char *) NULL)
287 svg_info->comment=DestroyString(svg_info->comment);
288 return((SVGInfo *) RelinquishMagickMemory(svg_info));
291 static double GetUserSpaceCoordinateValue(const SVGInfo *svg_info,int type,
296 token[MagickPathExtent];
304 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",string);
305 assert(string != (const char *) NULL);
306 p=(const char *) string;
307 GetNextToken(p,&p,MagickPathExtent,token);
308 value=StringToDouble(token,&next_token);
309 if (strchr(token,'%') != (char *) NULL)
317 if (svg_info->view_box.width == 0.0)
319 return(svg_info->view_box.width*value/100.0);
323 if (svg_info->view_box.height == 0.0)
325 return(svg_info->view_box.height*value/100.0);
327 alpha=value-svg_info->view_box.width;
328 beta=value-svg_info->view_box.height;
329 return(hypot(alpha,beta)/sqrt(2.0)/100.0);
331 GetNextToken(p,&p,MagickPathExtent,token);
332 if (LocaleNCompare(token,"cm",2) == 0)
333 return(96.0*svg_info->scale[0]/2.54*value);
334 if (LocaleNCompare(token,"em",2) == 0)
335 return(svg_info->pointsize*value);
336 if (LocaleNCompare(token,"ex",2) == 0)
337 return(svg_info->pointsize*value/2.0);
338 if (LocaleNCompare(token,"in",2) == 0)
339 return(96.0*svg_info->scale[0]*value);
340 if (LocaleNCompare(token,"mm",2) == 0)
341 return(96.0*svg_info->scale[0]/25.4*value);
342 if (LocaleNCompare(token,"pc",2) == 0)
343 return(96.0*svg_info->scale[0]/6.0*value);
344 if (LocaleNCompare(token,"pt",2) == 0)
345 return(1.25*svg_info->scale[0]*value);
346 if (LocaleNCompare(token,"px",2) == 0)
351 static void StripStyleTokens(char *message)
360 assert(message != (char *) NULL);
361 if (*message == '\0')
363 length=strlen(message);
365 while (isspace((int) ((unsigned char) *p)) != 0)
368 while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
370 (void) CopyMagickMemory(message,p,(size_t) (q-p+1));
372 StripString(message);
375 static char **GetStyleTokens(void *context,const char *style,
376 size_t *number_tokens)
388 svg_info=(SVGInfo *) context;
391 if (style == (const char *) NULL)
392 return((char **) NULL);
393 text=AcquireString(style);
394 (void) SubstituteString(&text,":","\n");
395 (void) SubstituteString(&text,";","\n");
396 tokens=StringToList(text);
397 text=DestroyString(text);
398 for (i=0; tokens[i] != (char *) NULL; i++)
399 StripStyleTokens(tokens[i]);
400 *number_tokens=(size_t) i;
404 static char **GetTransformTokens(void *context,const char *text,
405 size_t *number_tokens)
423 svg_info=(SVGInfo *) context;
425 if (text == (const char *) NULL)
426 return((char **) NULL);
428 tokens=(char **) AcquireQuantumMemory(extent+2UL,sizeof(*tokens));
429 if (tokens == (char **) NULL)
431 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
432 ResourceLimitError,"MemoryAllocationFailed","`%s'",text);
433 return((char **) NULL);
436 Convert string to an ASCII list.
440 for (q=p; *q != '\0'; q++)
442 if ((*q != '(') && (*q != ')') && (*q != '\0'))
444 if (i == (ssize_t) extent)
447 tokens=(char **) ResizeQuantumMemory(tokens,extent+2,sizeof(*tokens));
448 if (tokens == (char **) NULL)
450 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
451 ResourceLimitError,"MemoryAllocationFailed","`%s'",text);
452 return((char **) NULL);
455 tokens[i]=AcquireString(p);
456 (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
457 StripString(tokens[i]);
461 tokens[i]=AcquireString(p);
462 (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
463 StripString(tokens[i++]);
464 tokens[i]=(char *) NULL;
465 *number_tokens=(size_t) i;
469 #if defined(__cplusplus) || defined(c_plusplus)
473 static int SVGIsStandalone(void *context)
479 Is this document tagged standalone?
481 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGIsStandalone()");
482 svg_info=(SVGInfo *) context;
483 return(svg_info->document->standalone == 1);
486 static int SVGHasInternalSubset(void *context)
492 Does this document has an internal subset?
494 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
495 " SAX.SVGHasInternalSubset()");
496 svg_info=(SVGInfo *) context;
497 return(svg_info->document->intSubset != NULL);
500 static int SVGHasExternalSubset(void *context)
506 Does this document has an external subset?
508 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
509 " SAX.SVGHasExternalSubset()");
510 svg_info=(SVGInfo *) context;
511 return(svg_info->document->extSubset != NULL);
514 static void SVGInternalSubset(void *context,const xmlChar *name,
515 const xmlChar *external_id,const xmlChar *system_id)
521 Does this document has an internal subset?
523 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
524 " SAX.internalSubset(%s, %s, %s)",(const char *) name,
525 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
526 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
527 svg_info=(SVGInfo *) context;
528 (void) xmlCreateIntSubset(svg_info->document,name,external_id,system_id);
531 static xmlParserInputPtr SVGResolveEntity(void *context,
532 const xmlChar *public_id,const xmlChar *system_id)
541 Special entity resolver, better left to the parser, it has more
542 context than the application layer. The default behaviour is to
543 not resolve the entities, in that case the ENTITY_REF nodes are
544 built in the structure (and the parameter values).
546 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
547 " SAX.resolveEntity(%s, %s)",
548 (public_id != (const xmlChar *) NULL ? (const char *) public_id : "none"),
549 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
550 svg_info=(SVGInfo *) context;
551 stream=xmlLoadExternalEntity((const char *) system_id,(const char *)
552 public_id,svg_info->parser);
556 static xmlEntityPtr SVGGetEntity(void *context,const xmlChar *name)
562 Get an entity by name.
564 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGGetEntity(%s)",
566 svg_info=(SVGInfo *) context;
567 return(xmlGetDocEntity(svg_info->document,name));
570 static xmlEntityPtr SVGGetParameterEntity(void *context,const xmlChar *name)
576 Get a parameter entity by name.
578 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
579 " SAX.getParameterEntity(%s)",name);
580 svg_info=(SVGInfo *) context;
581 return(xmlGetParameterEntity(svg_info->document,name));
584 static void SVGEntityDeclaration(void *context,const xmlChar *name,int type,
585 const xmlChar *public_id,const xmlChar *system_id,xmlChar *content)
591 An entity definition has been parsed.
593 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
594 " SAX.entityDecl(%s, %d, %s, %s, %s)",name,type,
595 public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
596 system_id != (xmlChar *) NULL ? (const char *) system_id : "none",content);
597 svg_info=(SVGInfo *) context;
598 if (svg_info->parser->inSubset == 1)
599 (void) xmlAddDocEntity(svg_info->document,name,type,public_id,system_id,
602 if (svg_info->parser->inSubset == 2)
603 (void) xmlAddDtdEntity(svg_info->document,name,type,public_id,system_id,
607 static void SVGAttributeDeclaration(void *context,const xmlChar *element,
608 const xmlChar *name,int type,int value,const xmlChar *default_value,
609 xmlEnumerationPtr tree)
622 An attribute definition has been parsed.
624 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
625 " SAX.attributeDecl(%s, %s, %d, %d, %s, ...)",element,name,type,value,
627 svg_info=(SVGInfo *) context;
628 fullname=(xmlChar *) NULL;
629 prefix=(xmlChar *) NULL;
630 parser=svg_info->parser;
631 fullname=(xmlChar *) xmlSplitQName(parser,name,&prefix);
632 if (parser->inSubset == 1)
633 (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->intSubset,
634 element,fullname,prefix,(xmlAttributeType) type,
635 (xmlAttributeDefault) value,default_value,tree);
637 if (parser->inSubset == 2)
638 (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->extSubset,
639 element,fullname,prefix,(xmlAttributeType) type,
640 (xmlAttributeDefault) value,default_value,tree);
641 if (prefix != (xmlChar *) NULL)
643 if (fullname != (xmlChar *) NULL)
647 static void SVGElementDeclaration(void *context,const xmlChar *name,int type,
648 xmlElementContentPtr content)
657 An element definition has been parsed.
659 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
660 " SAX.elementDecl(%s, %d, ...)",name,type);
661 svg_info=(SVGInfo *) context;
662 parser=svg_info->parser;
663 if (parser->inSubset == 1)
664 (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->intSubset,
665 name,(xmlElementTypeVal) type,content);
667 if (parser->inSubset == 2)
668 (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->extSubset,
669 name,(xmlElementTypeVal) type,content);
672 static void SVGNotationDeclaration(void *context,const xmlChar *name,
673 const xmlChar *public_id,const xmlChar *system_id)
682 What to do when a notation declaration has been parsed.
684 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
685 " SAX.notationDecl(%s, %s, %s)",name,
686 public_id != (const xmlChar *) NULL ? (const char *) public_id : "none",
687 system_id != (const xmlChar *) NULL ? (const char *) system_id : "none");
688 svg_info=(SVGInfo *) context;
689 parser=svg_info->parser;
690 if (parser->inSubset == 1)
691 (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
692 name,public_id,system_id);
694 if (parser->inSubset == 2)
695 (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
696 name,public_id,system_id);
699 static void SVGUnparsedEntityDeclaration(void *context,const xmlChar *name,
700 const xmlChar *public_id,const xmlChar *system_id,const xmlChar *notation)
706 What to do when an unparsed entity declaration is parsed.
708 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
709 " SAX.unparsedEntityDecl(%s, %s, %s, %s)",name,
710 public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
711 system_id != (xmlChar *) NULL ? (const char *) system_id : "none",notation);
712 svg_info=(SVGInfo *) context;
713 (void) xmlAddDocEntity(svg_info->document,name,
714 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,public_id,system_id,notation);
718 static void SVGSetDocumentLocator(void *context,xmlSAXLocatorPtr location)
724 Receive the document locator at startup, actually xmlDefaultSAXLocator.
727 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
728 " SAX.setDocumentLocator()");
729 svg_info=(SVGInfo *) context;
733 static void SVGStartDocument(void *context)
742 Called when the document start being processed.
744 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startDocument()");
745 svg_info=(SVGInfo *) context;
746 parser=svg_info->parser;
747 svg_info->document=xmlNewDoc(parser->version);
748 if (svg_info->document == (xmlDocPtr) NULL)
750 if (parser->encoding == NULL)
751 svg_info->document->encoding=(const xmlChar *) NULL;
753 svg_info->document->encoding=xmlStrdup(parser->encoding);
754 svg_info->document->standalone=parser->standalone;
757 static void SVGEndDocument(void *context)
763 Called when the document end has been detected.
765 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.endDocument()");
766 svg_info=(SVGInfo *) context;
767 if (svg_info->offset != (char *) NULL)
768 svg_info->offset=DestroyString(svg_info->offset);
769 if (svg_info->stop_color != (char *) NULL)
770 svg_info->stop_color=DestroyString(svg_info->stop_color);
771 if (svg_info->scale != (double *) NULL)
772 svg_info->scale=(double *) RelinquishMagickMemory(svg_info->scale);
773 if (svg_info->text != (char *) NULL)
774 svg_info->text=DestroyString(svg_info->text);
775 if (svg_info->vertices != (char *) NULL)
776 svg_info->vertices=DestroyString(svg_info->vertices);
777 if (svg_info->url != (char *) NULL)
778 svg_info->url=DestroyString(svg_info->url);
779 #if defined(MAGICKCORE_XML_DELEGATE)
780 if (svg_info->document != (xmlDocPtr) NULL)
782 xmlFreeDoc(svg_info->document);
783 svg_info->document=(xmlDocPtr) NULL;
788 static void SVGStartElement(void *context,const xmlChar *name,
789 const xmlChar **attributes)
793 id[MagickPathExtent],
795 token[MagickPathExtent],
815 Called when an opening tag has been processed.
817 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startElement(%s",
819 svg_info=(SVGInfo *) context;
821 svg_info->scale=(double *) ResizeQuantumMemory(svg_info->scale,
822 svg_info->n+1UL,sizeof(*svg_info->scale));
823 if (svg_info->scale == (double *) NULL)
825 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
826 ResourceLimitError,"MemoryAllocationFailed","`%s'",name);
829 svg_info->scale[svg_info->n]=svg_info->scale[svg_info->n-1];
830 color=AcquireString("none");
831 units=AcquireString("userSpaceOnUse");
834 value=(const char *) NULL;
835 if (attributes != (const xmlChar **) NULL)
836 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
838 keyword=(const char *) attributes[i];
839 value=(const char *) attributes[i+1];
845 if (LocaleCompare(keyword,"cx") == 0)
847 svg_info->element.cx=
848 GetUserSpaceCoordinateValue(svg_info,1,value);
851 if (LocaleCompare(keyword,"cy") == 0)
853 svg_info->element.cy=
854 GetUserSpaceCoordinateValue(svg_info,-1,value);
862 if (LocaleCompare(keyword,"fx") == 0)
864 svg_info->element.major=
865 GetUserSpaceCoordinateValue(svg_info,1,value);
868 if (LocaleCompare(keyword,"fy") == 0)
870 svg_info->element.minor=
871 GetUserSpaceCoordinateValue(svg_info,-1,value);
879 if (LocaleCompare(keyword,"height") == 0)
881 svg_info->bounds.height=
882 GetUserSpaceCoordinateValue(svg_info,-1,value);
890 if (LocaleCompare(keyword,"id") == 0)
892 (void) CopyMagickString(id,value,MagickPathExtent);
900 if (LocaleCompare(keyword,"r") == 0)
902 svg_info->element.angle=
903 GetUserSpaceCoordinateValue(svg_info,0,value);
911 if (LocaleCompare(keyword,"width") == 0)
913 svg_info->bounds.width=
914 GetUserSpaceCoordinateValue(svg_info,1,value);
922 if (LocaleCompare(keyword,"x") == 0)
924 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value)-
928 if (LocaleCompare(keyword,"x1") == 0)
930 svg_info->segment.x1=GetUserSpaceCoordinateValue(svg_info,1,
934 if (LocaleCompare(keyword,"x2") == 0)
936 svg_info->segment.x2=GetUserSpaceCoordinateValue(svg_info,1,
945 if (LocaleCompare(keyword,"y") == 0)
947 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value)-
951 if (LocaleCompare(keyword,"y1") == 0)
953 svg_info->segment.y1=
954 GetUserSpaceCoordinateValue(svg_info,-1,value);
957 if (LocaleCompare(keyword,"y2") == 0)
959 svg_info->segment.y2=
960 GetUserSpaceCoordinateValue(svg_info,-1,value);
969 if (strchr((char *) name,':') != (char *) NULL)
974 for ( ; *name != ':'; name++) ;
982 if (LocaleCompare((const char *) name,"circle") == 0)
984 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
987 if (LocaleCompare((const char *) name,"clipPath") == 0)
989 (void) FormatLocaleFile(svg_info->file,"push clip-path '%s'\n",id);
997 if (LocaleCompare((const char *) name,"defs") == 0)
999 (void) FormatLocaleFile(svg_info->file,"push defs\n");
1007 if (LocaleCompare((const char *) name,"ellipse") == 0)
1009 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1017 if (LocaleCompare((const char *) name,"g") == 0)
1019 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1027 if (LocaleCompare((const char *) name,"image") == 0)
1029 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1037 if (LocaleCompare((const char *) name,"line") == 0)
1039 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1042 if (LocaleCompare((const char *) name,"linearGradient") == 0)
1044 (void) FormatLocaleFile(svg_info->file,
1045 "push gradient '%s' linear %g,%g %g,%g\n",id,
1046 svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
1047 svg_info->segment.y2);
1055 if (LocaleCompare((const char *) name,"path") == 0)
1057 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1060 if (LocaleCompare((const char *) name,"pattern") == 0)
1062 (void) FormatLocaleFile(svg_info->file,
1063 "push pattern '%s' %g,%g %g,%g\n",id,
1064 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.width,
1065 svg_info->bounds.height);
1068 if (LocaleCompare((const char *) name,"polygon") == 0)
1070 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1073 if (LocaleCompare((const char *) name,"polyline") == 0)
1075 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1083 if (LocaleCompare((const char *) name,"radialGradient") == 0)
1085 (void) FormatLocaleFile(svg_info->file,
1086 "push gradient '%s' radial %g,%g %g,%g %g\n",
1087 id,svg_info->element.cx,svg_info->element.cy,
1088 svg_info->element.major,svg_info->element.minor,
1089 svg_info->element.angle);
1092 if (LocaleCompare((const char *) name,"rect") == 0)
1094 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1102 if (LocaleCompare((const char *) name,"svg") == 0)
1104 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1112 if (LocaleCompare((const char *) name,"text") == 0)
1114 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1115 svg_info->bounds.x=0.0;
1116 svg_info->bounds.y=0.0;
1117 svg_info->bounds.width=0.0;
1118 svg_info->bounds.height=0.0;
1121 if (LocaleCompare((const char *) name,"tspan") == 0)
1123 if (*svg_info->text != '\0')
1134 text=EscapeString(svg_info->text,'\'');
1135 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
1136 svg_info->bounds.x-svg_info->center.x,svg_info->bounds.y-
1137 svg_info->center.y,text);
1138 text=DestroyString(text);
1139 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
1140 draw_info->pointsize=svg_info->pointsize;
1141 draw_info->text=AcquireString(svg_info->text);
1142 (void) ConcatenateString(&draw_info->text," ");
1143 (void) GetTypeMetrics(svg_info->image,draw_info,
1144 &metrics,svg_info->exception);
1145 svg_info->bounds.x+=metrics.width;
1146 draw_info=DestroyDrawInfo(draw_info);
1147 *svg_info->text='\0';
1149 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1157 if (attributes != (const xmlChar **) NULL)
1158 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
1160 keyword=(const char *) attributes[i];
1161 value=(const char *) attributes[i+1];
1162 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1163 " %s = %s",keyword,value);
1169 if (LocaleCompare(keyword,"angle") == 0)
1171 (void) FormatLocaleFile(svg_info->file,"angle %g\n",
1172 GetUserSpaceCoordinateValue(svg_info,0,value));
1180 if (LocaleCompare(keyword,"clip-path") == 0)
1182 (void) FormatLocaleFile(svg_info->file,"clip-path '%s'\n",value);
1185 if (LocaleCompare(keyword,"clip-rule") == 0)
1187 (void) FormatLocaleFile(svg_info->file,"clip-rule '%s'\n",value);
1190 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1192 (void) CloneString(&units,value);
1193 (void) FormatLocaleFile(svg_info->file,"clip-units '%s'\n",value);
1196 if (LocaleCompare(keyword,"color") == 0)
1198 (void) CloneString(&color,value);
1201 if (LocaleCompare(keyword,"cx") == 0)
1203 svg_info->element.cx=
1204 GetUserSpaceCoordinateValue(svg_info,1,value);
1207 if (LocaleCompare(keyword,"cy") == 0)
1209 svg_info->element.cy=
1210 GetUserSpaceCoordinateValue(svg_info,-1,value);
1218 if (LocaleCompare(keyword,"d") == 0)
1220 (void) CloneString(&svg_info->vertices,value);
1223 if (LocaleCompare(keyword,"dx") == 0)
1225 svg_info->bounds.x+=GetUserSpaceCoordinateValue(svg_info,1,value);
1228 if (LocaleCompare(keyword,"dy") == 0)
1230 svg_info->bounds.y+=
1231 GetUserSpaceCoordinateValue(svg_info,-1,value);
1239 if (LocaleCompare(keyword,"fill") == 0)
1241 if (LocaleCompare(value,"currentColor") == 0)
1243 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",color);
1246 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",value);
1249 if (LocaleCompare(keyword,"fillcolor") == 0)
1251 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",value);
1254 if (LocaleCompare(keyword,"fill-rule") == 0)
1256 (void) FormatLocaleFile(svg_info->file,"fill-rule '%s'\n",value);
1259 if (LocaleCompare(keyword,"fill-opacity") == 0)
1261 (void) FormatLocaleFile(svg_info->file,"fill-opacity '%s'\n",
1265 if (LocaleCompare(keyword,"font-family") == 0)
1267 (void) FormatLocaleFile(svg_info->file,"font-family '%s'\n",
1271 if (LocaleCompare(keyword,"font-stretch") == 0)
1273 (void) FormatLocaleFile(svg_info->file,"font-stretch '%s'\n",
1277 if (LocaleCompare(keyword,"font-style") == 0)
1279 (void) FormatLocaleFile(svg_info->file,"font-style '%s'\n",value);
1282 if (LocaleCompare(keyword,"font-size") == 0)
1284 if (LocaleCompare(value,"xx-small") == 0)
1285 svg_info->pointsize=6.144;
1286 else if (LocaleCompare(value,"x-small") == 0)
1287 svg_info->pointsize=7.68;
1288 else if (LocaleCompare(value,"small") == 0)
1289 svg_info->pointsize=9.6;
1290 else if (LocaleCompare(value,"medium") == 0)
1291 svg_info->pointsize=12.0;
1292 else if (LocaleCompare(value,"large") == 0)
1293 svg_info->pointsize=14.4;
1294 else if (LocaleCompare(value,"x-large") == 0)
1295 svg_info->pointsize=17.28;
1296 else if (LocaleCompare(value,"xx-large") == 0)
1297 svg_info->pointsize=20.736;
1299 svg_info->pointsize=GetUserSpaceCoordinateValue(svg_info,0,
1301 (void) FormatLocaleFile(svg_info->file,"font-size %g\n",
1302 svg_info->pointsize);
1305 if (LocaleCompare(keyword,"font-weight") == 0)
1307 (void) FormatLocaleFile(svg_info->file,"font-weight '%s'\n",
1316 if (LocaleCompare(keyword,"gradientTransform") == 0)
1323 GetAffineMatrix(&transform);
1324 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1325 tokens=GetTransformTokens(context,value,&number_tokens);
1326 if (tokens == (char **) NULL)
1328 for (j=0; j < (ssize_t) (number_tokens-1); j+=2)
1330 keyword=(char *) tokens[j];
1331 if (keyword == (char *) NULL)
1333 value=(char *) tokens[j+1];
1334 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1335 " %s: %s",keyword,value);
1337 GetAffineMatrix(&affine);
1343 if (LocaleCompare(keyword,"matrix") == 0)
1345 p=(const char *) value;
1346 GetNextToken(p,&p,MagickPathExtent,token);
1347 affine.sx=StringToDouble(value,(char **) NULL);
1348 GetNextToken(p,&p,MagickPathExtent,token);
1350 GetNextToken(p,&p,MagickPathExtent,token);
1351 affine.rx=StringToDouble(token,&next_token);
1352 GetNextToken(p,&p,MagickPathExtent,token);
1354 GetNextToken(p,&p,MagickPathExtent,token);
1355 affine.ry=StringToDouble(token,&next_token);
1356 GetNextToken(p,&p,MagickPathExtent,token);
1358 GetNextToken(p,&p,MagickPathExtent,token);
1359 affine.sy=StringToDouble(token,&next_token);
1360 GetNextToken(p,&p,MagickPathExtent,token);
1362 GetNextToken(p,&p,MagickPathExtent,token);
1363 affine.tx=StringToDouble(token,&next_token);
1364 GetNextToken(p,&p,MagickPathExtent,token);
1366 GetNextToken(p,&p,MagickPathExtent,token);
1367 affine.ty=StringToDouble(token,&next_token);
1375 if (LocaleCompare(keyword,"rotate") == 0)
1380 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1381 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1382 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1383 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1384 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1392 if (LocaleCompare(keyword,"scale") == 0)
1394 for (p=(const char *) value; *p != '\0'; p++)
1395 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1398 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1399 affine.sy=affine.sx;
1402 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1403 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
1406 if (LocaleCompare(keyword,"skewX") == 0)
1408 affine.sx=svg_info->affine.sx;
1409 affine.ry=tan(DegreesToRadians(fmod(
1410 GetUserSpaceCoordinateValue(svg_info,1,value),
1412 affine.sy=svg_info->affine.sy;
1415 if (LocaleCompare(keyword,"skewY") == 0)
1417 affine.sx=svg_info->affine.sx;
1418 affine.rx=tan(DegreesToRadians(fmod(
1419 GetUserSpaceCoordinateValue(svg_info,-1,value),
1421 affine.sy=svg_info->affine.sy;
1429 if (LocaleCompare(keyword,"translate") == 0)
1431 for (p=(const char *) value; *p != '\0'; p++)
1432 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1435 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
1436 affine.ty=affine.tx;
1439 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1447 transform.sx=affine.sx*current.sx+affine.ry*current.rx;
1448 transform.rx=affine.rx*current.sx+affine.sy*current.rx;
1449 transform.ry=affine.sx*current.ry+affine.ry*current.sy;
1450 transform.sy=affine.rx*current.ry+affine.sy*current.sy;
1451 transform.tx=affine.tx*current.sx+affine.ty*current.ry+
1453 transform.ty=affine.tx*current.rx+affine.ty*current.sy+
1456 (void) FormatLocaleFile(svg_info->file,
1457 "affine %g %g %g %g %g %g\n",transform.sx,
1458 transform.rx,transform.ry,transform.sy,transform.tx,
1460 for (j=0; tokens[j] != (char *) NULL; j++)
1461 tokens[j]=DestroyString(tokens[j]);
1462 tokens=(char **) RelinquishMagickMemory(tokens);
1465 if (LocaleCompare(keyword,"gradientUnits") == 0)
1467 (void) CloneString(&units,value);
1468 (void) FormatLocaleFile(svg_info->file,"gradient-units '%s'\n",
1477 if (LocaleCompare(keyword,"height") == 0)
1479 svg_info->bounds.height=
1480 GetUserSpaceCoordinateValue(svg_info,-1,value);
1483 if (LocaleCompare(keyword,"href") == 0)
1485 (void) CloneString(&svg_info->url,value);
1493 if (LocaleCompare(keyword,"major") == 0)
1495 svg_info->element.major=
1496 GetUserSpaceCoordinateValue(svg_info,1,value);
1499 if (LocaleCompare(keyword,"minor") == 0)
1501 svg_info->element.minor=
1502 GetUserSpaceCoordinateValue(svg_info,-1,value);
1510 if (LocaleCompare(keyword,"offset") == 0)
1512 (void) CloneString(&svg_info->offset,value);
1515 if (LocaleCompare(keyword,"opacity") == 0)
1517 (void) FormatLocaleFile(svg_info->file,"opacity '%s'\n",value);
1525 if (LocaleCompare(keyword,"path") == 0)
1527 (void) CloneString(&svg_info->url,value);
1530 if (LocaleCompare(keyword,"points") == 0)
1532 (void) CloneString(&svg_info->vertices,value);
1540 if (LocaleCompare(keyword,"r") == 0)
1542 svg_info->element.major=
1543 GetUserSpaceCoordinateValue(svg_info,1,value);
1544 svg_info->element.minor=
1545 GetUserSpaceCoordinateValue(svg_info,-1,value);
1548 if (LocaleCompare(keyword,"rotate") == 0)
1553 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1554 (void) FormatLocaleFile(svg_info->file,"translate %g,%g\n",
1555 svg_info->bounds.x,svg_info->bounds.y);
1556 svg_info->bounds.x=0;
1557 svg_info->bounds.y=0;
1558 (void) FormatLocaleFile(svg_info->file,"rotate %g\n",angle);
1561 if (LocaleCompare(keyword,"rx") == 0)
1563 if (LocaleCompare((const char *) name,"ellipse") == 0)
1564 svg_info->element.major=
1565 GetUserSpaceCoordinateValue(svg_info,1,value);
1568 GetUserSpaceCoordinateValue(svg_info,1,value);
1571 if (LocaleCompare(keyword,"ry") == 0)
1573 if (LocaleCompare((const char *) name,"ellipse") == 0)
1574 svg_info->element.minor=
1575 GetUserSpaceCoordinateValue(svg_info,-1,value);
1578 GetUserSpaceCoordinateValue(svg_info,-1,value);
1586 if (LocaleCompare(keyword,"stop-color") == 0)
1588 (void) CloneString(&svg_info->stop_color,value);
1591 if (LocaleCompare(keyword,"stroke") == 0)
1593 if (LocaleCompare(value,"currentColor") == 0)
1595 (void) FormatLocaleFile(svg_info->file,"stroke '%s'\n",color);
1598 (void) FormatLocaleFile(svg_info->file,"stroke '%s'\n",value);
1601 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1603 (void) FormatLocaleFile(svg_info->file,"stroke-antialias %d\n",
1604 LocaleCompare(value,"true") == 0);
1607 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1609 (void) FormatLocaleFile(svg_info->file,"stroke-dasharray %s\n",
1613 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1615 (void) FormatLocaleFile(svg_info->file,"stroke-dashoffset %g\n",
1616 GetUserSpaceCoordinateValue(svg_info,1,value));
1619 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1621 (void) FormatLocaleFile(svg_info->file,"stroke-linecap '%s'\n",
1625 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1627 (void) FormatLocaleFile(svg_info->file,"stroke-linejoin '%s'\n",
1631 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1633 (void) FormatLocaleFile(svg_info->file,"stroke-miterlimit '%s'\n",
1637 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1639 (void) FormatLocaleFile(svg_info->file,"stroke-opacity '%s'\n",
1643 if (LocaleCompare(keyword,"stroke-width") == 0)
1645 (void) FormatLocaleFile(svg_info->file,"stroke-width %g\n",
1646 GetUserSpaceCoordinateValue(svg_info,1,value));
1649 if (LocaleCompare(keyword,"style") == 0)
1651 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1652 tokens=GetStyleTokens(context,value,&number_tokens);
1653 for (j=0; j < (ssize_t) (number_tokens-1); j+=2)
1655 keyword=(char *) tokens[j];
1656 value=(char *) tokens[j+1];
1657 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1658 " %s: %s",keyword,value);
1664 if (LocaleCompare(keyword,"clip-path") == 0)
1666 (void) FormatLocaleFile(svg_info->file,
1667 "clip-path '%s'\n",value);
1670 if (LocaleCompare(keyword,"clip-rule") == 0)
1672 (void) FormatLocaleFile(svg_info->file,
1673 "clip-rule '%s'\n",value);
1676 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1678 (void) CloneString(&units,value);
1679 (void) FormatLocaleFile(svg_info->file,
1680 "clip-units '%s'\n",value);
1683 if (LocaleCompare(keyword,"color") == 0)
1685 (void) CloneString(&color,value);
1693 if (LocaleCompare(keyword,"fill") == 0)
1695 if (LocaleCompare(value,"currentColor") == 0)
1697 (void) FormatLocaleFile(svg_info->file,
1698 "fill '%s'\n",color);
1701 if (LocaleCompare(value,"#000000ff") == 0)
1702 (void) FormatLocaleFile(svg_info->file,
1703 "fill '#000000'\n");
1705 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",
1709 if (LocaleCompare(keyword,"fillcolor") == 0)
1711 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",
1715 if (LocaleCompare(keyword,"fill-rule") == 0)
1717 (void) FormatLocaleFile(svg_info->file,
1718 "fill-rule '%s'\n",value);
1721 if (LocaleCompare(keyword,"fill-opacity") == 0)
1723 (void) FormatLocaleFile(svg_info->file,
1724 "fill-opacity '%s'\n",value);
1727 if (LocaleCompare(keyword,"font-family") == 0)
1729 (void) FormatLocaleFile(svg_info->file,
1730 "font-family '%s'\n",value);
1733 if (LocaleCompare(keyword,"font-stretch") == 0)
1735 (void) FormatLocaleFile(svg_info->file,
1736 "font-stretch '%s'\n",value);
1739 if (LocaleCompare(keyword,"font-style") == 0)
1741 (void) FormatLocaleFile(svg_info->file,
1742 "font-style '%s'\n",value);
1745 if (LocaleCompare(keyword,"font-size") == 0)
1747 svg_info->pointsize=GetUserSpaceCoordinateValue(
1749 (void) FormatLocaleFile(svg_info->file,"font-size %g\n",
1750 svg_info->pointsize);
1753 if (LocaleCompare(keyword,"font-weight") == 0)
1755 (void) FormatLocaleFile(svg_info->file,
1756 "font-weight '%s'\n",value);
1764 if (LocaleCompare(keyword,"offset") == 0)
1766 (void) FormatLocaleFile(svg_info->file,"offset %g\n",
1767 GetUserSpaceCoordinateValue(svg_info,1,value));
1770 if (LocaleCompare(keyword,"opacity") == 0)
1772 (void) FormatLocaleFile(svg_info->file,
1773 "opacity '%s'\n",value);
1781 if (LocaleCompare(keyword,"stop-color") == 0)
1783 (void) CloneString(&svg_info->stop_color,value);
1786 if (LocaleCompare(keyword,"stroke") == 0)
1788 if (LocaleCompare(value,"currentColor") == 0)
1790 (void) FormatLocaleFile(svg_info->file,
1791 "stroke '%s'\n",color);
1794 if (LocaleCompare(value,"#000000ff") == 0)
1795 (void) FormatLocaleFile(svg_info->file,
1796 "fill '#000000'\n");
1798 (void) FormatLocaleFile(svg_info->file,
1799 "stroke '%s'\n",value);
1802 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1804 (void) FormatLocaleFile(svg_info->file,
1805 "stroke-antialias %d\n",
1806 LocaleCompare(value,"true") == 0);
1809 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1811 (void) FormatLocaleFile(svg_info->file,
1812 "stroke-dasharray %s\n",value);
1815 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1817 (void) FormatLocaleFile(svg_info->file,
1818 "stroke-dashoffset %g\n",
1819 GetUserSpaceCoordinateValue(svg_info,1,value));
1822 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1824 (void) FormatLocaleFile(svg_info->file,
1825 "stroke-linecap '%s'\n",value);
1828 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1830 (void) FormatLocaleFile(svg_info->file,
1831 "stroke-linejoin '%s'\n",value);
1834 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1836 (void) FormatLocaleFile(svg_info->file,
1837 "stroke-miterlimit '%s'\n",value);
1840 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1842 (void) FormatLocaleFile(svg_info->file,
1843 "stroke-opacity '%s'\n",value);
1846 if (LocaleCompare(keyword,"stroke-width") == 0)
1848 (void) FormatLocaleFile(svg_info->file,
1849 "stroke-width %g\n",
1850 GetUserSpaceCoordinateValue(svg_info,1,value));
1858 if (LocaleCompare(keyword,"text-align") == 0)
1860 (void) FormatLocaleFile(svg_info->file,
1861 "text-align '%s'\n",value);
1864 if (LocaleCompare(keyword,"text-anchor") == 0)
1866 (void) FormatLocaleFile(svg_info->file,
1867 "text-anchor '%s'\n",value);
1870 if (LocaleCompare(keyword,"text-decoration") == 0)
1872 if (LocaleCompare(value,"underline") == 0)
1873 (void) FormatLocaleFile(svg_info->file,
1874 "decorate underline\n");
1875 if (LocaleCompare(value,"line-through") == 0)
1876 (void) FormatLocaleFile(svg_info->file,
1877 "decorate line-through\n");
1878 if (LocaleCompare(value,"overline") == 0)
1879 (void) FormatLocaleFile(svg_info->file,
1880 "decorate overline\n");
1883 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1885 (void) FormatLocaleFile(svg_info->file,
1886 "text-antialias %d\n",
1887 LocaleCompare(value,"true") == 0);
1896 for (j=0; tokens[j] != (char *) NULL; j++)
1897 tokens[j]=DestroyString(tokens[j]);
1898 tokens=(char **) RelinquishMagickMemory(tokens);
1906 if (LocaleCompare(keyword,"text-align") == 0)
1908 (void) FormatLocaleFile(svg_info->file,"text-align '%s'\n",
1912 if (LocaleCompare(keyword,"text-anchor") == 0)
1914 (void) FormatLocaleFile(svg_info->file,"text-anchor '%s'\n",
1918 if (LocaleCompare(keyword,"text-decoration") == 0)
1920 if (LocaleCompare(value,"underline") == 0)
1921 (void) FormatLocaleFile(svg_info->file,"decorate underline\n");
1922 if (LocaleCompare(value,"line-through") == 0)
1923 (void) FormatLocaleFile(svg_info->file,
1924 "decorate line-through\n");
1925 if (LocaleCompare(value,"overline") == 0)
1926 (void) FormatLocaleFile(svg_info->file,"decorate overline\n");
1929 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1931 (void) FormatLocaleFile(svg_info->file,"text-antialias %d\n",
1932 LocaleCompare(value,"true") == 0);
1935 if (LocaleCompare(keyword,"transform") == 0)
1942 GetAffineMatrix(&transform);
1943 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1944 tokens=GetTransformTokens(context,value,&number_tokens);
1945 if (tokens == (char **) NULL)
1947 for (j=0; j < (ssize_t) (number_tokens-1); j+=2)
1949 keyword=(char *) tokens[j];
1950 value=(char *) tokens[j+1];
1951 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1952 " %s: %s",keyword,value);
1954 GetAffineMatrix(&affine);
1960 if (LocaleCompare(keyword,"matrix") == 0)
1962 p=(const char *) value;
1963 GetNextToken(p,&p,MagickPathExtent,token);
1964 affine.sx=StringToDouble(value,(char **) NULL);
1965 GetNextToken(p,&p,MagickPathExtent,token);
1967 GetNextToken(p,&p,MagickPathExtent,token);
1968 affine.rx=StringToDouble(token,&next_token);
1969 GetNextToken(p,&p,MagickPathExtent,token);
1971 GetNextToken(p,&p,MagickPathExtent,token);
1972 affine.ry=StringToDouble(token,&next_token);
1973 GetNextToken(p,&p,MagickPathExtent,token);
1975 GetNextToken(p,&p,MagickPathExtent,token);
1976 affine.sy=StringToDouble(token,&next_token);
1977 GetNextToken(p,&p,MagickPathExtent,token);
1979 GetNextToken(p,&p,MagickPathExtent,token);
1980 affine.tx=StringToDouble(token,&next_token);
1981 GetNextToken(p,&p,MagickPathExtent,token);
1983 GetNextToken(p,&p,MagickPathExtent,token);
1984 affine.ty=StringToDouble(token,&next_token);
1992 if (LocaleCompare(keyword,"rotate") == 0)
1999 p=(const char *) value;
2000 GetNextToken(p,&p,MagickPathExtent,token);
2001 angle=StringToDouble(value,(char **) NULL);
2002 GetNextToken(p,&p,MagickPathExtent,token);
2004 GetNextToken(p,&p,MagickPathExtent,token);
2005 x=StringToDouble(token,&next_token);
2006 GetNextToken(p,&p,MagickPathExtent,token);
2008 GetNextToken(p,&p,MagickPathExtent,token);
2009 y=StringToDouble(token,&next_token);
2010 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
2011 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
2012 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
2013 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
2016 svg_info->center.x=x;
2017 svg_info->center.y=y;
2025 if (LocaleCompare(keyword,"scale") == 0)
2027 for (p=(const char *) value; *p != '\0'; p++)
2028 if ((isspace((int) ((unsigned char) *p)) != 0) ||
2031 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
2032 affine.sy=affine.sx;
2034 affine.sy=GetUserSpaceCoordinateValue(svg_info,-1,
2036 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
2039 if (LocaleCompare(keyword,"skewX") == 0)
2041 affine.sx=svg_info->affine.sx;
2042 affine.ry=tan(DegreesToRadians(fmod(
2043 GetUserSpaceCoordinateValue(svg_info,1,value),
2045 affine.sy=svg_info->affine.sy;
2048 if (LocaleCompare(keyword,"skewY") == 0)
2050 affine.sx=svg_info->affine.sx;
2051 affine.rx=tan(DegreesToRadians(fmod(
2052 GetUserSpaceCoordinateValue(svg_info,-1,value),
2054 affine.sy=svg_info->affine.sy;
2062 if (LocaleCompare(keyword,"translate") == 0)
2064 for (p=(const char *) value; *p != '\0'; p++)
2065 if ((isspace((int) ((unsigned char) *p)) != 0) ||
2068 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
2069 affine.ty=affine.tx;
2071 affine.ty=GetUserSpaceCoordinateValue(svg_info,-1,
2080 transform.sx=affine.sx*current.sx+affine.ry*current.rx;
2081 transform.rx=affine.rx*current.sx+affine.sy*current.rx;
2082 transform.ry=affine.sx*current.ry+affine.ry*current.sy;
2083 transform.sy=affine.rx*current.ry+affine.sy*current.sy;
2084 transform.tx=affine.tx*current.sx+affine.ty*current.ry+
2086 transform.ty=affine.tx*current.rx+affine.ty*current.sy+
2089 (void) FormatLocaleFile(svg_info->file,
2090 "affine %g %g %g %g %g %g\n",transform.sx,transform.rx,
2091 transform.ry,transform.sy,transform.tx,transform.ty);
2092 for (j=0; tokens[j] != (char *) NULL; j++)
2093 tokens[j]=DestroyString(tokens[j]);
2094 tokens=(char **) RelinquishMagickMemory(tokens);
2102 if (LocaleCompare(keyword,"verts") == 0)
2104 (void) CloneString(&svg_info->vertices,value);
2107 if (LocaleCompare(keyword,"viewBox") == 0)
2109 p=(const char *) value;
2110 GetNextToken(p,&p,MagickPathExtent,token);
2111 svg_info->view_box.x=StringToDouble(token,&next_token);
2112 GetNextToken(p,&p,MagickPathExtent,token);
2114 GetNextToken(p,&p,MagickPathExtent,token);
2115 svg_info->view_box.y=StringToDouble(token,&next_token);
2116 GetNextToken(p,&p,MagickPathExtent,token);
2118 GetNextToken(p,&p,MagickPathExtent,token);
2119 svg_info->view_box.width=StringToDouble(token,
2121 if (svg_info->bounds.width == 0)
2122 svg_info->bounds.width=svg_info->view_box.width;
2123 GetNextToken(p,&p,MagickPathExtent,token);
2125 GetNextToken(p,&p,MagickPathExtent,token);
2126 svg_info->view_box.height=StringToDouble(token,
2128 if (svg_info->bounds.height == 0)
2129 svg_info->bounds.height=svg_info->view_box.height;
2137 if (LocaleCompare(keyword,"width") == 0)
2139 svg_info->bounds.width=
2140 GetUserSpaceCoordinateValue(svg_info,1,value);
2148 if (LocaleCompare(keyword,"x") == 0)
2150 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value);
2153 if (LocaleCompare(keyword,"xlink:href") == 0)
2155 (void) CloneString(&svg_info->url,value);
2158 if (LocaleCompare(keyword,"x1") == 0)
2160 svg_info->segment.x1=
2161 GetUserSpaceCoordinateValue(svg_info,1,value);
2164 if (LocaleCompare(keyword,"x2") == 0)
2166 svg_info->segment.x2=
2167 GetUserSpaceCoordinateValue(svg_info,1,value);
2175 if (LocaleCompare(keyword,"y") == 0)
2177 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value);
2180 if (LocaleCompare(keyword,"y1") == 0)
2182 svg_info->segment.y1=
2183 GetUserSpaceCoordinateValue(svg_info,-1,value);
2186 if (LocaleCompare(keyword,"y2") == 0)
2188 svg_info->segment.y2=
2189 GetUserSpaceCoordinateValue(svg_info,-1,value);
2198 if (LocaleCompare((const char *) name,"svg") == 0)
2200 if (svg_info->document->encoding != (const xmlChar *) NULL)
2201 (void) FormatLocaleFile(svg_info->file,"encoding \"%s\"\n",
2202 (const char *) svg_info->document->encoding);
2203 if (attributes != (const xmlChar **) NULL)
2211 if ((svg_info->view_box.width == 0.0) ||
2212 (svg_info->view_box.height == 0.0))
2213 svg_info->view_box=svg_info->bounds;
2215 if (svg_info->bounds.width > 0.0)
2216 svg_info->width=(size_t) floor(svg_info->bounds.width+0.5);
2218 if (svg_info->bounds.height > 0.0)
2219 svg_info->height=(size_t) floor(svg_info->bounds.height+0.5);
2220 (void) FormatLocaleFile(svg_info->file,"viewbox 0 0 %.20g %.20g\n",
2221 (double) svg_info->width,(double) svg_info->height);
2222 sx=(double) svg_info->width/svg_info->view_box.width;
2223 sy=(double) svg_info->height/svg_info->view_box.height;
2224 tx=svg_info->view_box.x != 0.0 ? (double) -sx*svg_info->view_box.x :
2226 ty=svg_info->view_box.y != 0.0 ? (double) -sy*svg_info->view_box.y :
2228 (void) FormatLocaleFile(svg_info->file,"affine %g 0 0 %g %g %g\n",
2232 (void) LogMagickEvent(CoderEvent,GetMagickModule()," )");
2233 units=DestroyString(units);
2234 if (color != (char *) NULL)
2235 color=DestroyString(color);
2238 static void SVGEndElement(void *context,const xmlChar *name)
2244 Called when the end of an element has been detected.
2246 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2247 " SAX.endElement(%s)",name);
2248 svg_info=(SVGInfo *) context;
2249 if (strchr((char *) name,':') != (char *) NULL)
2252 Skip over namespace.
2254 for ( ; *name != ':'; name++) ;
2262 if (LocaleCompare((const char *) name,"circle") == 0)
2264 (void) FormatLocaleFile(svg_info->file,"circle %g,%g %g,%g\n",
2265 svg_info->element.cx,svg_info->element.cy,svg_info->element.cx,
2266 svg_info->element.cy+svg_info->element.minor);
2267 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2270 if (LocaleCompare((const char *) name,"clipPath") == 0)
2272 (void) FormatLocaleFile(svg_info->file,"pop clip-path\n");
2280 if (LocaleCompare((const char *) name,"defs") == 0)
2282 (void) FormatLocaleFile(svg_info->file,"pop defs\n");
2285 if (LocaleCompare((const char *) name,"desc") == 0)
2290 if (*svg_info->text == '\0')
2292 (void) fputc('#',svg_info->file);
2293 for (p=svg_info->text; *p != '\0'; p++)
2295 (void) fputc(*p,svg_info->file);
2297 (void) fputc('#',svg_info->file);
2299 (void) fputc('\n',svg_info->file);
2300 *svg_info->text='\0';
2308 if (LocaleCompare((const char *) name,"ellipse") == 0)
2313 angle=svg_info->element.angle;
2314 (void) FormatLocaleFile(svg_info->file,"ellipse %g,%g %g,%g 0,360\n",
2315 svg_info->element.cx,svg_info->element.cy,
2316 angle == 0.0 ? svg_info->element.major : svg_info->element.minor,
2317 angle == 0.0 ? svg_info->element.minor : svg_info->element.major);
2318 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2326 if (LocaleCompare((const char *) name,"g") == 0)
2328 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2336 if (LocaleCompare((const char *) name,"image") == 0)
2338 (void) FormatLocaleFile(svg_info->file,
2339 "image Over %g,%g %g,%g '%s'\n",svg_info->bounds.x,
2340 svg_info->bounds.y,svg_info->bounds.width,svg_info->bounds.height,
2342 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2350 if (LocaleCompare((const char *) name,"line") == 0)
2352 (void) FormatLocaleFile(svg_info->file,"line %g,%g %g,%g\n",
2353 svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
2354 svg_info->segment.y2);
2355 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2358 if (LocaleCompare((const char *) name,"linearGradient") == 0)
2360 (void) FormatLocaleFile(svg_info->file,"pop gradient\n");
2368 if (LocaleCompare((const char *) name,"pattern") == 0)
2370 (void) FormatLocaleFile(svg_info->file,"pop pattern\n");
2373 if (LocaleCompare((const char *) name,"path") == 0)
2375 (void) FormatLocaleFile(svg_info->file,"path '%s'\n",
2376 svg_info->vertices);
2377 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2380 if (LocaleCompare((const char *) name,"polygon") == 0)
2382 (void) FormatLocaleFile(svg_info->file,"polygon %s\n",
2383 svg_info->vertices);
2384 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2387 if (LocaleCompare((const char *) name,"polyline") == 0)
2389 (void) FormatLocaleFile(svg_info->file,"polyline %s\n",
2390 svg_info->vertices);
2391 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2399 if (LocaleCompare((const char *) name,"radialGradient") == 0)
2401 (void) FormatLocaleFile(svg_info->file,"pop gradient\n");
2404 if (LocaleCompare((const char *) name,"rect") == 0)
2406 if ((svg_info->radius.x == 0.0) && (svg_info->radius.y == 0.0))
2408 (void) FormatLocaleFile(svg_info->file,"rectangle %g,%g %g,%g\n",
2409 svg_info->bounds.x,svg_info->bounds.y,
2410 svg_info->bounds.x+svg_info->bounds.width,
2411 svg_info->bounds.y+svg_info->bounds.height);
2412 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2415 if (svg_info->radius.x == 0.0)
2416 svg_info->radius.x=svg_info->radius.y;
2417 if (svg_info->radius.y == 0.0)
2418 svg_info->radius.y=svg_info->radius.x;
2419 (void) FormatLocaleFile(svg_info->file,
2420 "roundRectangle %g,%g %g,%g %g,%g\n",
2421 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.x+
2422 svg_info->bounds.width,svg_info->bounds.y+svg_info->bounds.height,
2423 svg_info->radius.x,svg_info->radius.y);
2424 svg_info->radius.x=0.0;
2425 svg_info->radius.y=0.0;
2426 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2434 if (LocaleCompare((const char *) name,"stop") == 0)
2436 (void) FormatLocaleFile(svg_info->file,"stop-color '%s' %s\n",
2437 svg_info->stop_color,svg_info->offset);
2440 if (LocaleCompare((const char *) name,"svg") == 0)
2442 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2450 if (LocaleCompare((const char *) name,"text") == 0)
2452 if (*svg_info->text != '\0')
2457 text=EscapeString(svg_info->text,'\'');
2458 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
2459 svg_info->bounds.x,svg_info->bounds.y,text);
2460 text=DestroyString(text);
2461 *svg_info->text='\0';
2463 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2466 if (LocaleCompare((const char *) name,"tspan") == 0)
2468 if (*svg_info->text != '\0')
2479 text=EscapeString(svg_info->text,'\'');
2480 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
2481 svg_info->bounds.x,svg_info->bounds.y,text);
2482 text=DestroyString(text);
2483 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
2484 draw_info->pointsize=svg_info->pointsize;
2485 draw_info->text=AcquireString(svg_info->text);
2486 (void) ConcatenateString(&draw_info->text," ");
2487 (void) GetTypeMetrics(svg_info->image,draw_info,&metrics,
2488 svg_info->exception);
2489 svg_info->bounds.x+=metrics.width;
2490 draw_info=DestroyDrawInfo(draw_info);
2491 *svg_info->text='\0';
2493 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2496 if (LocaleCompare((const char *) name,"title") == 0)
2498 if (*svg_info->text == '\0')
2500 (void) CloneString(&svg_info->title,svg_info->text);
2501 *svg_info->text='\0';
2509 *svg_info->text='\0';
2510 (void) ResetMagickMemory(&svg_info->element,0,sizeof(svg_info->element));
2511 (void) ResetMagickMemory(&svg_info->segment,0,sizeof(svg_info->segment));
2515 static void SVGCharacters(void *context,const xmlChar *c,int length)
2530 Receiving some characters from the parser.
2532 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2533 " SAX.characters(%s,%.20g)",c,(double) length);
2534 svg_info=(SVGInfo *) context;
2535 text=(char *) AcquireQuantumMemory(length+1,sizeof(*text));
2536 if (text == (char *) NULL)
2539 for (i=0; i < (ssize_t) length; i++)
2543 if (svg_info->text == (char *) NULL)
2544 svg_info->text=text;
2547 (void) ConcatenateString(&svg_info->text,text);
2548 text=DestroyString(text);
2552 static void SVGReference(void *context,const xmlChar *name)
2561 Called when an entity reference is detected.
2563 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.reference(%s)",
2565 svg_info=(SVGInfo *) context;
2566 parser=svg_info->parser;
2567 if (parser == (xmlParserCtxtPtr) NULL)
2569 if (parser->node == (xmlNodePtr) NULL)
2572 (void) xmlAddChild(parser->node,xmlNewCharRef(svg_info->document,name));
2574 (void) xmlAddChild(parser->node,xmlNewReference(svg_info->document,name));
2577 static void SVGIgnorableWhitespace(void *context,const xmlChar *c,int length)
2583 Receiving some ignorable whitespaces from the parser.
2585 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2586 " SAX.ignorableWhitespace(%.30s, %d)",c,length);
2587 svg_info=(SVGInfo *) context;
2591 static void SVGProcessingInstructions(void *context,const xmlChar *target,
2592 const xmlChar *data)
2598 A processing instruction has been parsed.
2600 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2601 " SAX.processingInstruction(%s, %s)",target,data);
2602 svg_info=(SVGInfo *) context;
2606 static void SVGComment(void *context,const xmlChar *value)
2612 A comment has been parsed.
2614 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.comment(%s)",
2616 svg_info=(SVGInfo *) context;
2617 if (svg_info->comment != (char *) NULL)
2618 (void) ConcatenateString(&svg_info->comment,"\n");
2619 (void) ConcatenateString(&svg_info->comment,(const char *) value);
2622 static void SVGWarning(void *context,const char *format,...)
2626 reason[MagickPathExtent];
2635 Display and format a warning messages, gives file, line, position and
2638 va_start(operands,format);
2639 svg_info=(SVGInfo *) context;
2640 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.warning: ");
2641 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2642 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2643 (void) vsprintf(reason,format,operands);
2645 (void) vsnprintf(reason,MagickPathExtent,format,operands);
2647 message=GetExceptionMessage(errno);
2648 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
2649 DelegateWarning,reason,"`%s`",message);
2650 message=DestroyString(message);
2654 static void SVGError(void *context,const char *format,...)
2658 reason[MagickPathExtent];
2667 Display and format a error formats, gives file, line, position and
2670 va_start(operands,format);
2671 svg_info=(SVGInfo *) context;
2672 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.error: ");
2673 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2674 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2675 (void) vsprintf(reason,format,operands);
2677 (void) vsnprintf(reason,MagickPathExtent,format,operands);
2679 message=GetExceptionMessage(errno);
2680 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),CoderError,
2681 reason,"`%s`",message);
2682 message=DestroyString(message);
2686 static void SVGCDataBlock(void *context,const xmlChar *value,int length)
2698 Called when a pcdata block has been parsed.
2700 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.pcdata(%s, %d)",
2702 svg_info=(SVGInfo *) context;
2703 parser=svg_info->parser;
2704 child=xmlGetLastChild(parser->node);
2705 if ((child != (xmlNodePtr) NULL) && (child->type == XML_CDATA_SECTION_NODE))
2707 xmlTextConcat(child,value,length);
2710 (void) xmlAddChild(parser->node,xmlNewCDataBlock(parser->myDoc,value,length));
2713 static void SVGExternalSubset(void *context,const xmlChar *name,
2714 const xmlChar *external_id,const xmlChar *system_id)
2729 Does this document has an external subset?
2731 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2732 " SAX.externalSubset(%s, %s, %s)",name,
2733 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
2734 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
2735 svg_info=(SVGInfo *) context;
2736 parser=svg_info->parser;
2737 if (((external_id == NULL) && (system_id == NULL)) ||
2738 ((parser->validate == 0) || (parser->wellFormed == 0) ||
2739 (svg_info->document == 0)))
2741 input=SVGResolveEntity(context,external_id,system_id);
2744 (void) xmlNewDtd(svg_info->document,name,external_id,system_id);
2745 parser_context=(*parser);
2746 parser->inputTab=(xmlParserInputPtr *) xmlMalloc(5*sizeof(*parser->inputTab));
2747 if (parser->inputTab == (xmlParserInputPtr *) NULL)
2749 parser->errNo=XML_ERR_NO_MEMORY;
2750 parser->input=parser_context.input;
2751 parser->inputNr=parser_context.inputNr;
2752 parser->inputMax=parser_context.inputMax;
2753 parser->inputTab=parser_context.inputTab;
2759 xmlPushInput(parser,input);
2760 (void) xmlSwitchEncoding(parser,xmlDetectCharEncoding(parser->input->cur,4));
2761 if (input->filename == (char *) NULL)
2762 input->filename=(char *) xmlStrdup(system_id);
2765 input->base=parser->input->cur;
2766 input->cur=parser->input->cur;
2768 xmlParseExternalSubset(parser,external_id,system_id);
2769 while (parser->inputNr > 1)
2770 (void) xmlPopInput(parser);
2771 xmlFreeInputStream(parser->input);
2772 xmlFree(parser->inputTab);
2773 parser->input=parser_context.input;
2774 parser->inputNr=parser_context.inputNr;
2775 parser->inputMax=parser_context.inputMax;
2776 parser->inputTab=parser_context.inputTab;
2779 #if defined(__cplusplus) || defined(c_plusplus)
2784 Static declarations.
2787 SVGDensityGeometry[] = "96.0x96.0";
2790 static Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
2793 filename[MagickPathExtent];
2812 message[MagickPathExtent];
2823 assert(image_info != (const ImageInfo *) NULL);
2824 assert(image_info->signature == MagickCoreSignature);
2825 assert(exception != (ExceptionInfo *) NULL);
2826 if (image_info->debug != MagickFalse)
2827 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2828 image_info->filename);
2829 assert(exception->signature == MagickCoreSignature);
2830 image=AcquireImage(image_info,exception);
2831 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2832 if (status == MagickFalse)
2834 image=DestroyImageList(image);
2835 return((Image *) NULL);
2837 if ((fabs(image->resolution.x) < MagickEpsilon) ||
2838 (fabs(image->resolution.y) < MagickEpsilon))
2846 flags=ParseGeometry(SVGDensityGeometry,&geometry_info);
2847 image->resolution.x=geometry_info.rho;
2848 image->resolution.y=geometry_info.sigma;
2849 if ((flags & SigmaValue) == 0)
2850 image->resolution.y=image->resolution.x;
2852 if (LocaleCompare(image_info->magick,"MSVG") != 0)
2857 delegate_info=GetDelegateInfo("svg:decode",(char *) NULL,exception);
2858 if (delegate_info != (const DelegateInfo *) NULL)
2861 background[MagickPathExtent],
2862 command[MagickPathExtent],
2864 input_filename[MagickPathExtent],
2865 opacity[MagickPathExtent],
2866 output_filename[MagickPathExtent],
2867 unique[MagickPathExtent];
2876 Our best hope of compliance with the SVG standard.
2878 status=AcquireUniqueSymbolicLink(image->filename,input_filename);
2879 (void) AcquireUniqueFilename(output_filename);
2880 (void) AcquireUniqueFilename(unique);
2881 density=AcquireString("");
2882 (void) FormatLocaleString(density,MagickPathExtent,"%.20g,%.20g",
2883 image->resolution.x,image->resolution.y);
2884 (void) FormatLocaleString(background,MagickPathExtent,
2885 "rgb(%.20g%%,%.20g%%,%.20g%%)",
2886 100.0*QuantumScale*image->background_color.red,
2887 100.0*QuantumScale*image->background_color.green,
2888 100.0*QuantumScale*image->background_color.blue);
2889 (void) FormatLocaleString(opacity,MagickPathExtent,"%.20g",
2890 QuantumScale*image->background_color.alpha);
2891 (void) FormatLocaleString(command,MagickPathExtent,
2892 GetDelegateCommands(delegate_info),input_filename,output_filename,
2893 density,background,opacity,unique);
2894 density=DestroyString(density);
2895 status=ExternalDelegateCommand(MagickFalse,image_info->verbose,
2896 command,(char *) NULL,exception);
2897 (void) RelinquishUniqueFileResource(unique);
2898 (void) RelinquishUniqueFileResource(input_filename);
2899 if ((status == 0) && (stat(output_filename,&attributes) == 0) &&
2900 (attributes.st_size > 0))
2908 read_info=CloneImageInfo(image_info);
2909 (void) CopyMagickString(read_info->filename,output_filename,
2911 svg_image=ReadImage(read_info,exception);
2912 read_info=DestroyImageInfo(read_info);
2913 (void) RelinquishUniqueFileResource(output_filename);
2914 if (svg_image != (Image *) NULL)
2916 image=DestroyImage(image);
2920 (void) RelinquishUniqueFileResource(output_filename);
2923 #if defined(MAGICKCORE_RSVG_DELEGATE)
2924 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2937 register unsigned char
2950 register const guchar
2972 svg_handle=rsvg_handle_new();
2973 if (svg_handle == (RsvgHandle *) NULL)
2974 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2975 rsvg_handle_set_base_uri(svg_handle,image_info->filename);
2976 if ((fabs(image->resolution.x) > MagickEpsilon) &&
2977 (fabs(image->resolution.y) > MagickEpsilon))
2978 rsvg_handle_set_dpi_x_y(svg_handle,image->resolution.x,
2979 image->resolution.y);
2980 while ((n=ReadBlob(image,MagickPathExtent-1,message)) != 0)
2983 error=(GError *) NULL;
2984 (void) rsvg_handle_write(svg_handle,message,n,&error);
2985 if (error != (GError *) NULL)
2986 g_error_free(error);
2988 error=(GError *) NULL;
2989 rsvg_handle_close(svg_handle,&error);
2990 if (error != (GError *) NULL)
2991 g_error_free(error);
2992 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2993 apply_density=MagickTrue;
2994 rsvg_handle_get_dimensions(svg_handle,&dimension_info);
2995 if ((image->resolution.x > 0.0) && (image->resolution.y > 0.0))
3001 We should not apply the density when the internal 'factor' is 'i'.
3002 This can be checked by using the trick below.
3004 rsvg_handle_set_dpi_x_y(svg_handle,image->resolution.x*256,
3005 image->resolution.y*256);
3006 rsvg_handle_get_dimensions(svg_handle,&dpi_dimension_info);
3007 if ((dpi_dimension_info.width != dimension_info.width) ||
3008 (dpi_dimension_info.height != dimension_info.height))
3009 apply_density=MagickFalse;
3010 rsvg_handle_set_dpi_x_y(svg_handle,image->resolution.x,
3011 image->resolution.y);
3013 if (image_info->size != (char *) NULL)
3015 (void) GetGeometry(image_info->size,(ssize_t *) NULL,
3016 (ssize_t *) NULL,&image->columns,&image->rows);
3017 if ((image->columns != 0) || (image->rows != 0))
3019 image->resolution.x=96.0*image->columns/dimension_info.width;
3020 image->resolution.y=96.0*image->rows/dimension_info.height;
3021 if (fabs(image->resolution.x) < MagickEpsilon)
3022 image->resolution.x=image->resolution.y;
3024 if (fabs(image->resolution.y) < MagickEpsilon)
3025 image->resolution.y=image->resolution.x;
3027 image->resolution.x=image->resolution.y=MagickMin(
3028 image->resolution.x,image->resolution.y);
3029 apply_density=MagickTrue;
3032 if (apply_density != MagickFalse)
3034 image->columns=image->resolution.x*dimension_info.width/96.0;
3035 image->rows=image->resolution.y*dimension_info.height/96.0;
3039 image->columns=dimension_info.width;
3040 image->rows=dimension_info.height;
3042 pixel_info=(MemoryInfo *) NULL;
3044 pixel_buffer=rsvg_handle_get_pixbuf(svg_handle);
3045 rsvg_handle_free(svg_handle);
3046 image->columns=gdk_pixbuf_get_width(pixel_buffer);
3047 image->rows=gdk_pixbuf_get_height(pixel_buffer);
3049 image->alpha_trait=BlendPixelTrait;
3050 status=SetImageExtent(image,image->columns,image->rows,exception);
3051 if (status == MagickFalse)
3053 #if !defined(MAGICKCORE_CAIRO_DELEGATE)
3054 g_object_unref(G_OBJECT(pixel_buffer));
3056 g_object_unref(svg_handle);
3057 ThrowReaderException(MissingDelegateError,
3058 "NoDecodeDelegateForThisImageFormat");
3060 if (image_info->ping == MagickFalse)
3062 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3066 stride=4*image->columns;
3067 #if defined(MAGICKCORE_PANGOCAIRO_DELEGATE)
3068 stride=(size_t) cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32,
3069 (int) image->columns);
3071 pixel_info=AcquireVirtualMemory(stride,image->rows*sizeof(*pixels));
3072 if (pixel_info == (MemoryInfo *) NULL)
3074 g_object_unref(svg_handle);
3075 ThrowReaderException(ResourceLimitError,
3076 "MemoryAllocationFailed");
3078 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
3080 (void) SetImageBackgroundColor(image,exception);
3081 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3082 cairo_surface=cairo_image_surface_create_for_data(pixels,
3083 CAIRO_FORMAT_ARGB32,(int) image->columns,(int) image->rows,(int)
3085 if (cairo_surface == (cairo_surface_t *) NULL)
3087 pixel_info=RelinquishVirtualMemory(pixel_info);
3088 g_object_unref(svg_handle);
3089 ThrowReaderException(ResourceLimitError,
3090 "MemoryAllocationFailed");
3092 cairo_image=cairo_create(cairo_surface);
3093 cairo_set_operator(cairo_image,CAIRO_OPERATOR_CLEAR);
3094 cairo_paint(cairo_image);
3095 cairo_set_operator(cairo_image,CAIRO_OPERATOR_OVER);
3096 if (apply_density != MagickFalse)
3097 cairo_scale(cairo_image,image->resolution.x/96.0,
3098 image->resolution.y/96.0);
3099 rsvg_handle_render_cairo(svg_handle,cairo_image);
3100 cairo_destroy(cairo_image);
3101 cairo_surface_destroy(cairo_surface);
3102 g_object_unref(svg_handle);
3105 p=gdk_pixbuf_get_pixels(pixel_buffer);
3107 GetPixelInfo(image,&fill_color);
3108 for (y=0; y < (ssize_t) image->rows; y++)
3110 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3111 if (q == (Quantum *) NULL)
3113 for (x=0; x < (ssize_t) image->columns; x++)
3115 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3116 fill_color.blue=ScaleCharToQuantum(*p++);
3117 fill_color.green=ScaleCharToQuantum(*p++);
3118 fill_color.red=ScaleCharToQuantum(*p++);
3120 fill_color.red=ScaleCharToQuantum(*p++);
3121 fill_color.green=ScaleCharToQuantum(*p++);
3122 fill_color.blue=ScaleCharToQuantum(*p++);
3124 fill_color.alpha=ScaleCharToQuantum(*p++);
3125 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3130 gamma=QuantumScale*fill_color.alpha;
3131 gamma=PerceptibleReciprocal(gamma);
3132 fill_color.blue*=gamma;
3133 fill_color.green*=gamma;
3134 fill_color.red*=gamma;
3137 CompositePixelOver(image,&fill_color,fill_color.alpha,q,(double)
3138 GetPixelAlpha(image,q),q);
3139 q+=GetPixelChannels(image);
3141 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3143 if (image->previous == (Image *) NULL)
3145 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
3147 if (status == MagickFalse)
3152 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3153 if (pixel_info != (MemoryInfo *) NULL)
3154 pixel_info=RelinquishVirtualMemory(pixel_info);
3156 g_object_unref(G_OBJECT(pixel_buffer));
3158 (void) CloseBlob(image);
3159 return(GetFirstImageInList(image));
3167 unique_file=AcquireUniqueFileResource(filename);
3168 if (unique_file != -1)
3169 file=fdopen(unique_file,"w");
3170 if ((unique_file == -1) || (file == (FILE *) NULL))
3172 (void) CopyMagickString(image->filename,filename,MagickPathExtent);
3173 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
3175 image=DestroyImageList(image);
3176 return((Image *) NULL);
3181 svg_info=AcquireSVGInfo();
3182 if (svg_info == (SVGInfo *) NULL)
3184 (void) fclose(file);
3185 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3187 svg_info->file=file;
3188 svg_info->exception=exception;
3189 svg_info->image=image;
3190 svg_info->image_info=image_info;
3191 svg_info->bounds.width=image->columns;
3192 svg_info->bounds.height=image->rows;
3193 if (image_info->size != (char *) NULL)
3194 (void) CloneString(&svg_info->size,image_info->size);
3195 if (image->debug != MagickFalse)
3196 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"begin SAX");
3197 (void) xmlSubstituteEntitiesDefault(1);
3198 (void) ResetMagickMemory(&sax_modules,0,sizeof(sax_modules));
3199 sax_modules.internalSubset=SVGInternalSubset;
3200 sax_modules.isStandalone=SVGIsStandalone;
3201 sax_modules.hasInternalSubset=SVGHasInternalSubset;
3202 sax_modules.hasExternalSubset=SVGHasExternalSubset;
3203 sax_modules.resolveEntity=SVGResolveEntity;
3204 sax_modules.getEntity=SVGGetEntity;
3205 sax_modules.entityDecl=SVGEntityDeclaration;
3206 sax_modules.notationDecl=SVGNotationDeclaration;
3207 sax_modules.attributeDecl=SVGAttributeDeclaration;
3208 sax_modules.elementDecl=SVGElementDeclaration;
3209 sax_modules.unparsedEntityDecl=SVGUnparsedEntityDeclaration;
3210 sax_modules.setDocumentLocator=SVGSetDocumentLocator;
3211 sax_modules.startDocument=SVGStartDocument;
3212 sax_modules.endDocument=SVGEndDocument;
3213 sax_modules.startElement=SVGStartElement;
3214 sax_modules.endElement=SVGEndElement;
3215 sax_modules.reference=SVGReference;
3216 sax_modules.characters=SVGCharacters;
3217 sax_modules.ignorableWhitespace=SVGIgnorableWhitespace;
3218 sax_modules.processingInstruction=SVGProcessingInstructions;
3219 sax_modules.comment=SVGComment;
3220 sax_modules.warning=SVGWarning;
3221 sax_modules.error=SVGError;
3222 sax_modules.fatalError=SVGError;
3223 sax_modules.getParameterEntity=SVGGetParameterEntity;
3224 sax_modules.cdataBlock=SVGCDataBlock;
3225 sax_modules.externalSubset=SVGExternalSubset;
3226 sax_handler=(&sax_modules);
3227 n=ReadBlob(image,MagickPathExtent-1,message);
3231 svg_info->parser=xmlCreatePushParserCtxt(sax_handler,svg_info,(char *)
3232 message,n,image->filename);
3233 while ((n=ReadBlob(image,MagickPathExtent-1,message)) != 0)
3236 status=xmlParseChunk(svg_info->parser,(char *) message,(int) n,0);
3241 (void) xmlParseChunk(svg_info->parser,(char *) message,0,1);
3242 SVGEndDocument(svg_info);
3243 xmlFreeParserCtxt(svg_info->parser);
3244 if (image->debug != MagickFalse)
3245 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"end SAX");
3246 (void) fclose(file);
3247 (void) CloseBlob(image);
3248 image->columns=svg_info->width;
3249 image->rows=svg_info->height;
3250 if (exception->severity >= ErrorException)
3252 svg_info=DestroySVGInfo(svg_info);
3253 (void) RelinquishUniqueFileResource(filename);
3254 image=DestroyImage(image);
3255 return((Image *) NULL);
3257 if (image_info->ping == MagickFalse)
3265 image=DestroyImage(image);
3266 image=(Image *) NULL;
3267 read_info=CloneImageInfo(image_info);
3268 SetImageInfoBlob(read_info,(void *) NULL,0);
3269 if (read_info->density != (char *) NULL)
3270 read_info->density=DestroyString(read_info->density);
3271 (void) FormatLocaleString(read_info->filename,MagickPathExtent,"mvg:%s",
3273 image=ReadImage(read_info,exception);
3274 read_info=DestroyImageInfo(read_info);
3275 if (image != (Image *) NULL)
3276 (void) CopyMagickString(image->filename,image_info->filename,
3280 Relinquish resources.
3282 if (image != (Image *) NULL)
3284 if (svg_info->title != (char *) NULL)
3285 (void) SetImageProperty(image,"svg:title",svg_info->title,exception);
3286 if (svg_info->comment != (char *) NULL)
3287 (void) SetImageProperty(image,"svg:comment",svg_info->comment,
3290 svg_info=DestroySVGInfo(svg_info);
3291 (void) RelinquishUniqueFileResource(filename);
3292 return(GetFirstImageInList(image));
3298 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3302 % R e g i s t e r S V G I m a g e %
3306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3308 % RegisterSVGImage() adds attributes for the SVG image format to
3309 % the list of supported formats. The attributes include the image format
3310 % tag, a method to read and/or write the format, whether the format
3311 % supports the saving of more than one frame to the same file or blob,
3312 % whether the format supports native in-memory I/O, and a brief
3313 % description of the format.
3315 % The format of the RegisterSVGImage method is:
3317 % size_t RegisterSVGImage(void)
3320 ModuleExport size_t RegisterSVGImage(void)
3323 version[MagickPathExtent];
3329 #if defined(LIBXML_DOTTED_VERSION)
3330 (void) CopyMagickString(version,"XML " LIBXML_DOTTED_VERSION,
3333 #if defined(MAGICKCORE_RSVG_DELEGATE)
3334 #if !GLIB_CHECK_VERSION(2,35,0)
3337 #if defined(MAGICKCORE_XML_DELEGATE)
3340 (void) FormatLocaleString(version,MagickPathExtent,"RSVG %d.%d.%d",
3341 LIBRSVG_MAJOR_VERSION,LIBRSVG_MINOR_VERSION,LIBRSVG_MICRO_VERSION);
3343 entry=AcquireMagickInfo("SVG","SVG","Scalable Vector Graphics");
3344 #if defined(MAGICKCORE_XML_DELEGATE)
3345 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3347 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3348 entry->flags^=CoderBlobSupportFlag;
3349 #if defined(MAGICKCORE_RSVG_DELEGATE)
3350 entry->flags^=CoderDecoderThreadSupportFlag;
3352 entry->mime_type=ConstantString("image/svg+xml");
3353 if (*version != '\0')
3354 entry->version=ConstantString(version);
3355 entry->magick=(IsImageFormatHandler *) IsSVG;
3356 (void) RegisterMagickInfo(entry);
3357 entry=AcquireMagickInfo("SVG","SVGZ","Compressed Scalable Vector Graphics");
3358 #if defined(MAGICKCORE_XML_DELEGATE)
3359 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3361 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3362 entry->flags^=CoderBlobSupportFlag;
3363 #if defined(MAGICKCORE_RSVG_DELEGATE)
3364 entry->flags^=CoderDecoderThreadSupportFlag;
3366 entry->mime_type=ConstantString("image/svg+xml");
3367 if (*version != '\0')
3368 entry->version=ConstantString(version);
3369 entry->magick=(IsImageFormatHandler *) IsSVG;
3370 (void) RegisterMagickInfo(entry);
3371 entry=AcquireMagickInfo("SVG","MSVG",
3372 "ImageMagick's own SVG internal renderer");
3373 #if defined(MAGICKCORE_XML_DELEGATE)
3374 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3376 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3377 entry->flags^=CoderBlobSupportFlag;
3378 #if defined(MAGICKCORE_RSVG_DELEGATE)
3379 entry->flags^=CoderDecoderThreadSupportFlag;
3381 entry->magick=(IsImageFormatHandler *) IsSVG;
3382 (void) RegisterMagickInfo(entry);
3383 return(MagickImageCoderSignature);
3388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3392 % U n r e g i s t e r S V G I m a g e %
3396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3398 % UnregisterSVGImage() removes format registrations made by the
3399 % SVG module from the list of supported formats.
3401 % The format of the UnregisterSVGImage method is:
3403 % UnregisterSVGImage(void)
3406 ModuleExport void UnregisterSVGImage(void)
3408 (void) UnregisterMagickInfo("SVGZ");
3409 (void) UnregisterMagickInfo("SVG");
3410 (void) UnregisterMagickInfo("MSVG");
3411 #if defined(MAGICKCORE_XML_DELEGATE)
3418 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3422 % W r i t e S V G I m a g e %
3426 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3428 % WriteSVGImage() writes a image in the SVG - XML based W3C standard
3431 % The format of the WriteSVGImage method is:
3433 % MagickBooleanType WriteSVGImage(const ImageInfo *image_info,
3434 % Image *image,ExceptionInfo *exception)
3436 % A description of each parameter follows.
3438 % o image_info: the image info.
3440 % o image: The image.
3442 % o exception: return any errors or warnings in this structure.
3446 static void AffineToTransform(Image *image,AffineMatrix *affine)
3449 transform[MagickPathExtent];
3451 if ((fabs(affine->tx) < MagickEpsilon) && (fabs(affine->ty) < MagickEpsilon))
3453 if ((fabs(affine->rx) < MagickEpsilon) &&
3454 (fabs(affine->ry) < MagickEpsilon))
3456 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3457 (fabs(affine->sy-1.0) < MagickEpsilon))
3459 (void) WriteBlobString(image,"\">\n");
3462 (void) FormatLocaleString(transform,MagickPathExtent,
3463 "\" transform=\"scale(%g,%g)\">\n",affine->sx,affine->sy);
3464 (void) WriteBlobString(image,transform);
3469 if ((fabs(affine->sx-affine->sy) < MagickEpsilon) &&
3470 (fabs(affine->rx+affine->ry) < MagickEpsilon) &&
3471 (fabs(affine->sx*affine->sx+affine->rx*affine->rx-1.0) <
3477 theta=(180.0/MagickPI)*atan2(affine->rx,affine->sx);
3478 (void) FormatLocaleString(transform,MagickPathExtent,
3479 "\" transform=\"rotate(%g)\">\n",theta);
3480 (void) WriteBlobString(image,transform);
3487 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3488 (fabs(affine->rx) < MagickEpsilon) &&
3489 (fabs(affine->ry) < MagickEpsilon) &&
3490 (fabs(affine->sy-1.0) < MagickEpsilon))
3492 (void) FormatLocaleString(transform,MagickPathExtent,
3493 "\" transform=\"translate(%g,%g)\">\n",affine->tx,affine->ty);
3494 (void) WriteBlobString(image,transform);
3498 (void) FormatLocaleString(transform,MagickPathExtent,
3499 "\" transform=\"matrix(%g %g %g %g %g %g)\">\n",
3500 affine->sx,affine->rx,affine->ry,affine->sy,affine->tx,affine->ty);
3501 (void) WriteBlobString(image,transform);
3504 static MagickBooleanType IsPoint(const char *point)
3512 value=strtol(point,&p,10);
3514 return(p != point ? MagickTrue : MagickFalse);
3517 static MagickBooleanType TraceSVGImage(Image *image,ExceptionInfo *exception)
3519 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
3524 at_fitting_opts_type
3536 register const Quantum
3550 Trace image and write as SVG.
3552 fitting_options=at_fitting_opts_new();
3553 output_options=at_output_opts_new();
3554 (void) SetImageGray(image,exception);
3555 type=GetImageType(image);
3557 if ((type == BilevelType) || (type == GrayscaleType))
3559 trace=at_bitmap_new(image->columns,image->rows,number_planes);
3561 for (y=0; y < (ssize_t) image->rows; y++)
3563 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3564 if (p == (const Quantum *) NULL)
3566 for (x=0; x < (ssize_t) image->columns; x++)
3568 trace->bitmap[i++]=GetPixelRed(image,p);
3569 if (number_planes == 3)
3571 trace->bitmap[i++]=GetPixelGreen(image,p);
3572 trace->bitmap[i++]=GetPixelBlue(image,p);
3574 p+=GetPixelChannels(image);
3577 splines=at_splines_new_full(trace,fitting_options,NULL,NULL,NULL,NULL,NULL,
3579 at_splines_write(at_output_get_handler_by_suffix((char *) "svg"),
3580 GetBlobFileHandle(image),image->filename,output_options,splines,NULL,
3585 at_splines_free(splines);
3586 at_bitmap_free(trace);
3587 at_output_opts_free(output_options);
3588 at_fitting_opts_free(fitting_options);
3594 message[MagickPathExtent];
3615 (void) WriteBlobString(image,
3616 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");
3617 (void) WriteBlobString(image,
3618 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"");
3619 (void) WriteBlobString(image,
3620 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
3621 (void) FormatLocaleString(message,MagickPathExtent,
3622 "<svg version=\"1.1\" id=\"Layer_1\" "
3623 "xmlns=\"http://www.w3.org/2000/svg\" "
3624 "xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\" "
3625 "width=\"%.20gpx\" height=\"%.20gpx\" viewBox=\"0 0 %.20g %.20g\" "
3626 "enable-background=\"new 0 0 %.20g %.20g\" xml:space=\"preserve\">",
3627 (double) image->columns,(double) image->rows,
3628 (double) image->columns,(double) image->rows,
3629 (double) image->columns,(double) image->rows);
3630 (void) WriteBlobString(image,message);
3631 clone_image=CloneImage(image,0,0,MagickTrue,exception);
3632 if (clone_image == (Image *) NULL)
3633 return(MagickFalse);
3634 image_info=AcquireImageInfo();
3635 (void) CopyMagickString(image_info->magick,"PNG",MagickPathExtent);
3637 blob=(unsigned char *) ImageToBlob(image_info,clone_image,&blob_length,
3639 clone_image=DestroyImage(clone_image);
3640 image_info=DestroyImageInfo(image_info);
3641 if (blob == (unsigned char *) NULL)
3642 return(MagickFalse);
3644 base64=Base64Encode(blob,blob_length,&encode_length);
3645 blob=(unsigned char *) RelinquishMagickMemory(blob);
3646 (void) FormatLocaleString(message,MagickPathExtent,
3647 " <image id=\"image%.20g\" width=\"%.20g\" height=\"%.20g\" "
3648 "x=\"%.20g\" y=\"%.20g\"\n xlink:href=\"data:image/png;base64,",
3649 (double) image->scene,(double) image->columns,(double) image->rows,
3650 (double) image->page.x,(double) image->page.y);
3651 (void) WriteBlobString(image,message);
3653 for (i=(ssize_t) encode_length; i > 0; i-=76)
3655 (void) FormatLocaleString(message,MagickPathExtent,"%.76s",p);
3656 (void) WriteBlobString(image,message);
3659 (void) WriteBlobString(image,"\n");
3661 base64=DestroyString(base64);
3662 (void) WriteBlobString(image,"\" />\n");
3663 (void) WriteBlobString(image,"</svg>\n");
3670 static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
3671 ExceptionInfo *exception)
3673 #define BezierQuantum 200
3679 keyword[MagickPathExtent],
3680 message[MagickPathExtent],
3681 name[MagickPathExtent],
3684 type[MagickPathExtent];
3725 Open output image file.
3727 assert(image_info != (const ImageInfo *) NULL);
3728 assert(image_info->signature == MagickCoreSignature);
3729 assert(image != (Image *) NULL);
3730 assert(image->signature == MagickCoreSignature);
3731 if (image->debug != MagickFalse)
3732 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3733 assert(exception != (ExceptionInfo *) NULL);
3734 assert(exception->signature == MagickCoreSignature);
3735 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
3736 if (status == MagickFalse)
3738 value=GetImageArtifact(image,"SVG");
3739 if (value != (char *) NULL)
3741 (void) WriteBlobString(image,value);
3742 (void) CloseBlob(image);
3745 value=GetImageArtifact(image,"MVG");
3746 if (value == (char *) NULL)
3747 return(TraceSVGImage(image,exception));
3751 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3752 (void) WriteBlobString(image,
3753 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3754 (void) WriteBlobString(image,
3755 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3756 (void) FormatLocaleString(message,MagickPathExtent,
3757 "<svg width=\"%.20g\" height=\"%.20g\">\n",(double) image->columns,(double)
3759 (void) WriteBlobString(image,message);
3761 Allocate primitive info memory.
3764 primitive_info=(PrimitiveInfo *) AcquireQuantumMemory(number_points,
3765 sizeof(*primitive_info));
3766 if (primitive_info == (PrimitiveInfo *) NULL)
3767 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3768 GetAffineMatrix(&affine);
3769 token=AcquireString(value);
3770 extent=strlen(token)+MagickPathExtent;
3774 for (q=(const char *) value; *q != '\0'; )
3777 Interpret graphic primitive.
3779 GetNextToken(q,&q,MagickPathExtent,keyword);
3780 if (*keyword == '\0')
3782 if (*keyword == '#')
3787 if (active != MagickFalse)
3789 AffineToTransform(image,&affine);
3792 (void) WriteBlobString(image,"<desc>");
3793 (void) WriteBlobString(image,keyword+1);
3794 for ( ; (*q != '\n') && (*q != '\0'); q++)
3797 case '<': (void) WriteBlobString(image,"<"); break;
3798 case '>': (void) WriteBlobString(image,">"); break;
3799 case '&': (void) WriteBlobString(image,"&"); break;
3800 default: (void) WriteBlobByte(image,*q); break;
3802 (void) WriteBlobString(image,"</desc>\n");
3805 primitive_type=UndefinedPrimitive;
3813 if (LocaleCompare("affine",keyword) == 0)
3815 GetNextToken(q,&q,extent,token);
3816 affine.sx=StringToDouble(token,&next_token);
3817 GetNextToken(q,&q,extent,token);
3819 GetNextToken(q,&q,extent,token);
3820 affine.rx=StringToDouble(token,&next_token);
3821 GetNextToken(q,&q,extent,token);
3823 GetNextToken(q,&q,extent,token);
3824 affine.ry=StringToDouble(token,&next_token);
3825 GetNextToken(q,&q,extent,token);
3827 GetNextToken(q,&q,extent,token);
3828 affine.sy=StringToDouble(token,&next_token);
3829 GetNextToken(q,&q,extent,token);
3831 GetNextToken(q,&q,extent,token);
3832 affine.tx=StringToDouble(token,&next_token);
3833 GetNextToken(q,&q,extent,token);
3835 GetNextToken(q,&q,extent,token);
3836 affine.ty=StringToDouble(token,&next_token);
3839 if (LocaleCompare("alpha",keyword) == 0)
3841 primitive_type=AlphaPrimitive;
3844 if (LocaleCompare("angle",keyword) == 0)
3846 GetNextToken(q,&q,extent,token);
3847 affine.rx=StringToDouble(token,&next_token);
3848 affine.ry=StringToDouble(token,&next_token);
3851 if (LocaleCompare("arc",keyword) == 0)
3853 primitive_type=ArcPrimitive;
3862 if (LocaleCompare("bezier",keyword) == 0)
3864 primitive_type=BezierPrimitive;
3873 if (LocaleCompare("clip-path",keyword) == 0)
3875 GetNextToken(q,&q,extent,token);
3876 (void) FormatLocaleString(message,MagickPathExtent,
3877 "clip-path:url(#%s);",token);
3878 (void) WriteBlobString(image,message);
3881 if (LocaleCompare("clip-rule",keyword) == 0)
3883 GetNextToken(q,&q,extent,token);
3884 (void) FormatLocaleString(message,MagickPathExtent,
3885 "clip-rule:%s;",token);
3886 (void) WriteBlobString(image,message);
3889 if (LocaleCompare("clip-units",keyword) == 0)
3891 GetNextToken(q,&q,extent,token);
3892 (void) FormatLocaleString(message,MagickPathExtent,
3893 "clipPathUnits=%s;",token);
3894 (void) WriteBlobString(image,message);
3897 if (LocaleCompare("circle",keyword) == 0)
3899 primitive_type=CirclePrimitive;
3902 if (LocaleCompare("color",keyword) == 0)
3904 primitive_type=ColorPrimitive;
3913 if (LocaleCompare("decorate",keyword) == 0)
3915 GetNextToken(q,&q,extent,token);
3916 (void) FormatLocaleString(message,MagickPathExtent,
3917 "text-decoration:%s;",token);
3918 (void) WriteBlobString(image,message);
3927 if (LocaleCompare("ellipse",keyword) == 0)
3929 primitive_type=EllipsePrimitive;
3938 if (LocaleCompare("fill",keyword) == 0)
3940 GetNextToken(q,&q,extent,token);
3941 (void) FormatLocaleString(message,MagickPathExtent,"fill:%s;",
3943 (void) WriteBlobString(image,message);
3946 if (LocaleCompare("fill-rule",keyword) == 0)
3948 GetNextToken(q,&q,extent,token);
3949 (void) FormatLocaleString(message,MagickPathExtent,
3950 "fill-rule:%s;",token);
3951 (void) WriteBlobString(image,message);
3954 if (LocaleCompare("fill-opacity",keyword) == 0)
3956 GetNextToken(q,&q,extent,token);
3957 (void) FormatLocaleString(message,MagickPathExtent,
3958 "fill-opacity:%s;",token);
3959 (void) WriteBlobString(image,message);
3962 if (LocaleCompare("font-family",keyword) == 0)
3964 GetNextToken(q,&q,extent,token);
3965 (void) FormatLocaleString(message,MagickPathExtent,
3966 "font-family:%s;",token);
3967 (void) WriteBlobString(image,message);
3970 if (LocaleCompare("font-stretch",keyword) == 0)
3972 GetNextToken(q,&q,extent,token);
3973 (void) FormatLocaleString(message,MagickPathExtent,
3974 "font-stretch:%s;",token);
3975 (void) WriteBlobString(image,message);
3978 if (LocaleCompare("font-style",keyword) == 0)
3980 GetNextToken(q,&q,extent,token);
3981 (void) FormatLocaleString(message,MagickPathExtent,
3982 "font-style:%s;",token);
3983 (void) WriteBlobString(image,message);
3986 if (LocaleCompare("font-size",keyword) == 0)
3988 GetNextToken(q,&q,extent,token);
3989 (void) FormatLocaleString(message,MagickPathExtent,
3990 "font-size:%s;",token);
3991 (void) WriteBlobString(image,message);
3994 if (LocaleCompare("font-weight",keyword) == 0)
3996 GetNextToken(q,&q,extent,token);
3997 (void) FormatLocaleString(message,MagickPathExtent,
3998 "font-weight:%s;",token);
3999 (void) WriteBlobString(image,message);
4008 if (LocaleCompare("gradient-units",keyword) == 0)
4010 GetNextToken(q,&q,extent,token);
4013 if (LocaleCompare("text-align",keyword) == 0)
4015 GetNextToken(q,&q,extent,token);
4016 (void) FormatLocaleString(message,MagickPathExtent,
4017 "text-align %s ",token);
4018 (void) WriteBlobString(image,message);
4021 if (LocaleCompare("text-anchor",keyword) == 0)
4023 GetNextToken(q,&q,extent,token);
4024 (void) FormatLocaleString(message,MagickPathExtent,
4025 "text-anchor %s ",token);
4026 (void) WriteBlobString(image,message);
4035 if (LocaleCompare("image",keyword) == 0)
4037 GetNextToken(q,&q,extent,token);
4038 primitive_type=ImagePrimitive;
4047 if (LocaleCompare("line",keyword) == 0)
4049 primitive_type=LinePrimitive;
4058 if (LocaleCompare("opacity",keyword) == 0)
4060 GetNextToken(q,&q,extent,token);
4061 (void) FormatLocaleString(message,MagickPathExtent,"opacity %s ",
4063 (void) WriteBlobString(image,message);
4072 if (LocaleCompare("path",keyword) == 0)
4074 primitive_type=PathPrimitive;
4077 if (LocaleCompare("point",keyword) == 0)
4079 primitive_type=PointPrimitive;
4082 if (LocaleCompare("polyline",keyword) == 0)
4084 primitive_type=PolylinePrimitive;
4087 if (LocaleCompare("polygon",keyword) == 0)
4089 primitive_type=PolygonPrimitive;
4092 if (LocaleCompare("pop",keyword) == 0)
4094 GetNextToken(q,&q,extent,token);
4095 if (LocaleCompare("clip-path",token) == 0)
4097 (void) WriteBlobString(image,"</clipPath>\n");
4100 if (LocaleCompare("defs",token) == 0)
4102 (void) WriteBlobString(image,"</defs>\n");
4105 if (LocaleCompare("gradient",token) == 0)
4107 (void) FormatLocaleString(message,MagickPathExtent,
4108 "</%sGradient>\n",type);
4109 (void) WriteBlobString(image,message);
4112 if (LocaleCompare("graphic-context",token) == 0)
4116 ThrowWriterException(DrawError,
4117 "UnbalancedGraphicContextPushPop");
4118 (void) WriteBlobString(image,"</g>\n");
4120 if (LocaleCompare("pattern",token) == 0)
4122 (void) WriteBlobString(image,"</pattern>\n");
4125 if (LocaleCompare("defs",token) == 0)
4126 (void) WriteBlobString(image,"</g>\n");
4129 if (LocaleCompare("push",keyword) == 0)
4131 GetNextToken(q,&q,extent,token);
4132 if (LocaleCompare("clip-path",token) == 0)
4134 GetNextToken(q,&q,extent,token);
4135 (void) FormatLocaleString(message,MagickPathExtent,
4136 "<clipPath id=\"%s\">\n",token);
4137 (void) WriteBlobString(image,message);
4140 if (LocaleCompare("defs",token) == 0)
4142 (void) WriteBlobString(image,"<defs>\n");
4145 if (LocaleCompare("gradient",token) == 0)
4147 GetNextToken(q,&q,extent,token);
4148 (void) CopyMagickString(name,token,MagickPathExtent);
4149 GetNextToken(q,&q,extent,token);
4150 (void) CopyMagickString(type,token,MagickPathExtent);
4151 GetNextToken(q,&q,extent,token);
4152 svg_info.segment.x1=StringToDouble(token,&next_token);
4153 svg_info.element.cx=StringToDouble(token,&next_token);
4154 GetNextToken(q,&q,extent,token);
4156 GetNextToken(q,&q,extent,token);
4157 svg_info.segment.y1=StringToDouble(token,&next_token);
4158 svg_info.element.cy=StringToDouble(token,&next_token);
4159 GetNextToken(q,&q,extent,token);
4161 GetNextToken(q,&q,extent,token);
4162 svg_info.segment.x2=StringToDouble(token,&next_token);
4163 svg_info.element.major=StringToDouble(token,
4165 GetNextToken(q,&q,extent,token);
4167 GetNextToken(q,&q,extent,token);
4168 svg_info.segment.y2=StringToDouble(token,&next_token);
4169 svg_info.element.minor=StringToDouble(token,
4171 (void) FormatLocaleString(message,MagickPathExtent,
4172 "<%sGradient id=\"%s\" x1=\"%g\" y1=\"%g\" x2=\"%g\" "
4173 "y2=\"%g\">\n",type,name,svg_info.segment.x1,
4174 svg_info.segment.y1,svg_info.segment.x2,svg_info.segment.y2);
4175 if (LocaleCompare(type,"radial") == 0)
4177 GetNextToken(q,&q,extent,token);
4179 GetNextToken(q,&q,extent,token);
4180 svg_info.element.angle=StringToDouble(token,
4182 (void) FormatLocaleString(message,MagickPathExtent,
4183 "<%sGradient id=\"%s\" cx=\"%g\" cy=\"%g\" r=\"%g\" "
4184 "fx=\"%g\" fy=\"%g\">\n",type,name,
4185 svg_info.element.cx,svg_info.element.cy,
4186 svg_info.element.angle,svg_info.element.major,
4187 svg_info.element.minor);
4189 (void) WriteBlobString(image,message);
4192 if (LocaleCompare("graphic-context",token) == 0)
4197 AffineToTransform(image,&affine);
4200 (void) WriteBlobString(image,"<g style=\"");
4203 if (LocaleCompare("pattern",token) == 0)
4205 GetNextToken(q,&q,extent,token);
4206 (void) CopyMagickString(name,token,MagickPathExtent);
4207 GetNextToken(q,&q,extent,token);
4208 svg_info.bounds.x=StringToDouble(token,&next_token);
4209 GetNextToken(q,&q,extent,token);
4211 GetNextToken(q,&q,extent,token);
4212 svg_info.bounds.y=StringToDouble(token,&next_token);
4213 GetNextToken(q,&q,extent,token);
4215 GetNextToken(q,&q,extent,token);
4216 svg_info.bounds.width=StringToDouble(token,
4218 GetNextToken(q,&q,extent,token);
4220 GetNextToken(q,&q,extent,token);
4221 svg_info.bounds.height=StringToDouble(token,(char **) NULL);
4222 (void) FormatLocaleString(message,MagickPathExtent,
4223 "<pattern id=\"%s\" x=\"%g\" y=\"%g\" width=\"%g\" "
4224 "height=\"%g\">\n",name,svg_info.bounds.x,svg_info.bounds.y,
4225 svg_info.bounds.width,svg_info.bounds.height);
4226 (void) WriteBlobString(image,message);
4237 if (LocaleCompare("rectangle",keyword) == 0)
4239 primitive_type=RectanglePrimitive;
4242 if (LocaleCompare("roundRectangle",keyword) == 0)
4244 primitive_type=RoundRectanglePrimitive;
4247 if (LocaleCompare("rotate",keyword) == 0)
4249 GetNextToken(q,&q,extent,token);
4250 (void) FormatLocaleString(message,MagickPathExtent,"rotate(%s) ",
4252 (void) WriteBlobString(image,message);
4261 if (LocaleCompare("scale",keyword) == 0)
4263 GetNextToken(q,&q,extent,token);
4264 affine.sx=StringToDouble(token,&next_token);
4265 GetNextToken(q,&q,extent,token);
4267 GetNextToken(q,&q,extent,token);
4268 affine.sy=StringToDouble(token,&next_token);
4271 if (LocaleCompare("skewX",keyword) == 0)
4273 GetNextToken(q,&q,extent,token);
4274 (void) FormatLocaleString(message,MagickPathExtent,"skewX(%s) ",
4276 (void) WriteBlobString(image,message);
4279 if (LocaleCompare("skewY",keyword) == 0)
4281 GetNextToken(q,&q,extent,token);
4282 (void) FormatLocaleString(message,MagickPathExtent,"skewY(%s) ",
4284 (void) WriteBlobString(image,message);
4287 if (LocaleCompare("stop-color",keyword) == 0)
4290 color[MagickPathExtent];
4292 GetNextToken(q,&q,extent,token);
4293 (void) CopyMagickString(color,token,MagickPathExtent);
4294 GetNextToken(q,&q,extent,token);
4295 (void) FormatLocaleString(message,MagickPathExtent,
4296 " <stop offset=\"%s\" stop-color=\"%s\" />\n",token,color);
4297 (void) WriteBlobString(image,message);
4300 if (LocaleCompare("stroke",keyword) == 0)
4302 GetNextToken(q,&q,extent,token);
4303 (void) FormatLocaleString(message,MagickPathExtent,"stroke:%s;",
4305 (void) WriteBlobString(image,message);
4308 if (LocaleCompare("stroke-antialias",keyword) == 0)
4310 GetNextToken(q,&q,extent,token);
4311 (void) FormatLocaleString(message,MagickPathExtent,
4312 "stroke-antialias:%s;",token);
4313 (void) WriteBlobString(image,message);
4316 if (LocaleCompare("stroke-dasharray",keyword) == 0)
4324 GetNextToken(p,&p,extent,token);
4325 for (k=0; IsPoint(token); k++)
4326 GetNextToken(p,&p,extent,token);
4327 (void) WriteBlobString(image,"stroke-dasharray:");
4328 for (j=0; j < k; j++)
4330 GetNextToken(q,&q,extent,token);
4331 (void) FormatLocaleString(message,MagickPathExtent,"%s ",
4333 (void) WriteBlobString(image,message);
4335 (void) WriteBlobString(image,";");
4338 GetNextToken(q,&q,extent,token);
4339 (void) FormatLocaleString(message,MagickPathExtent,
4340 "stroke-dasharray:%s;",token);
4341 (void) WriteBlobString(image,message);
4344 if (LocaleCompare("stroke-dashoffset",keyword) == 0)
4346 GetNextToken(q,&q,extent,token);
4347 (void) FormatLocaleString(message,MagickPathExtent,
4348 "stroke-dashoffset:%s;",token);
4349 (void) WriteBlobString(image,message);
4352 if (LocaleCompare("stroke-linecap",keyword) == 0)
4354 GetNextToken(q,&q,extent,token);
4355 (void) FormatLocaleString(message,MagickPathExtent,
4356 "stroke-linecap:%s;",token);
4357 (void) WriteBlobString(image,message);
4360 if (LocaleCompare("stroke-linejoin",keyword) == 0)
4362 GetNextToken(q,&q,extent,token);
4363 (void) FormatLocaleString(message,MagickPathExtent,
4364 "stroke-linejoin:%s;",token);
4365 (void) WriteBlobString(image,message);
4368 if (LocaleCompare("stroke-miterlimit",keyword) == 0)
4370 GetNextToken(q,&q,extent,token);
4371 (void) FormatLocaleString(message,MagickPathExtent,
4372 "stroke-miterlimit:%s;",token);
4373 (void) WriteBlobString(image,message);
4376 if (LocaleCompare("stroke-opacity",keyword) == 0)
4378 GetNextToken(q,&q,extent,token);
4379 (void) FormatLocaleString(message,MagickPathExtent,
4380 "stroke-opacity:%s;",token);
4381 (void) WriteBlobString(image,message);
4384 if (LocaleCompare("stroke-width",keyword) == 0)
4386 GetNextToken(q,&q,extent,token);
4387 (void) FormatLocaleString(message,MagickPathExtent,
4388 "stroke-width:%s;",token);
4389 (void) WriteBlobString(image,message);
4398 if (LocaleCompare("text",keyword) == 0)
4400 primitive_type=TextPrimitive;
4403 if (LocaleCompare("text-antialias",keyword) == 0)
4405 GetNextToken(q,&q,extent,token);
4406 (void) FormatLocaleString(message,MagickPathExtent,
4407 "text-antialias:%s;",token);
4408 (void) WriteBlobString(image,message);
4411 if (LocaleCompare("tspan",keyword) == 0)
4413 primitive_type=TextPrimitive;
4416 if (LocaleCompare("translate",keyword) == 0)
4418 GetNextToken(q,&q,extent,token);
4419 affine.tx=StringToDouble(token,&next_token);
4420 GetNextToken(q,&q,extent,token);
4422 GetNextToken(q,&q,extent,token);
4423 affine.ty=StringToDouble(token,&next_token);
4432 if (LocaleCompare("viewbox",keyword) == 0)
4434 GetNextToken(q,&q,extent,token);
4436 GetNextToken(q,&q,extent,token);
4437 GetNextToken(q,&q,extent,token);
4439 GetNextToken(q,&q,extent,token);
4440 GetNextToken(q,&q,extent,token);
4442 GetNextToken(q,&q,extent,token);
4443 GetNextToken(q,&q,extent,token);
4455 if (status == MagickFalse)
4457 if (primitive_type == UndefinedPrimitive)
4460 Parse the primitive attributes.
4464 for (x=0; *q != '\0'; x++)
4469 if (IsPoint(q) == MagickFalse)
4471 GetNextToken(q,&q,extent,token);
4472 point.x=StringToDouble(token,&next_token);
4473 GetNextToken(q,&q,extent,token);
4475 GetNextToken(q,&q,extent,token);
4476 point.y=StringToDouble(token,&next_token);
4477 GetNextToken(q,(const char **) NULL,extent,token);
4479 GetNextToken(q,&q,extent,token);
4480 primitive_info[i].primitive=primitive_type;
4481 primitive_info[i].point=point;
4482 primitive_info[i].coordinates=0;
4483 primitive_info[i].method=FloodfillMethod;
4485 if (i < (ssize_t) (number_points-6*BezierQuantum-360))
4487 number_points+=6*BezierQuantum+360;
4488 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4489 number_points,sizeof(*primitive_info));
4490 if (primitive_info == (PrimitiveInfo *) NULL)
4492 (void) ThrowMagickException(exception,GetMagickModule(),
4493 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
4497 primitive_info[j].primitive=primitive_type;
4498 primitive_info[j].coordinates=x;
4499 primitive_info[j].method=FloodfillMethod;
4500 primitive_info[j].text=(char *) NULL;
4503 AffineToTransform(image,&affine);
4507 switch (primitive_type)
4509 case PointPrimitive:
4512 if (primitive_info[j].coordinates != 1)
4521 if (primitive_info[j].coordinates != 2)
4526 (void) FormatLocaleString(message,MagickPathExtent,
4527 " <line x1=\"%g\" y1=\"%g\" x2=\"%g\" y2=\"%g\"/>\n",
4528 primitive_info[j].point.x,primitive_info[j].point.y,
4529 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4530 (void) WriteBlobString(image,message);
4533 case RectanglePrimitive:
4535 if (primitive_info[j].coordinates != 2)
4540 (void) FormatLocaleString(message,MagickPathExtent,
4541 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"/>\n",
4542 primitive_info[j].point.x,primitive_info[j].point.y,
4543 primitive_info[j+1].point.x-primitive_info[j].point.x,
4544 primitive_info[j+1].point.y-primitive_info[j].point.y);
4545 (void) WriteBlobString(image,message);
4548 case RoundRectanglePrimitive:
4550 if (primitive_info[j].coordinates != 3)
4555 (void) FormatLocaleString(message,MagickPathExtent,
4556 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" rx=\"%g\" "
4557 "ry=\"%g\"/>\n",primitive_info[j].point.x,
4558 primitive_info[j].point.y,primitive_info[j+1].point.x-
4559 primitive_info[j].point.x,primitive_info[j+1].point.y-
4560 primitive_info[j].point.y,primitive_info[j+2].point.x,
4561 primitive_info[j+2].point.y);
4562 (void) WriteBlobString(image,message);
4567 if (primitive_info[j].coordinates != 3)
4574 case EllipsePrimitive:
4576 if (primitive_info[j].coordinates != 3)
4581 (void) FormatLocaleString(message,MagickPathExtent,
4582 " <ellipse cx=\"%g\" cy=\"%g\" rx=\"%g\" ry=\"%g\"/>\n",
4583 primitive_info[j].point.x,primitive_info[j].point.y,
4584 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4585 (void) WriteBlobString(image,message);
4588 case CirclePrimitive:
4594 if (primitive_info[j].coordinates != 2)
4599 alpha=primitive_info[j+1].point.x-primitive_info[j].point.x;
4600 beta=primitive_info[j+1].point.y-primitive_info[j].point.y;
4601 (void) FormatLocaleString(message,MagickPathExtent,
4602 " <circle cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
4603 primitive_info[j].point.x,primitive_info[j].point.y,
4605 (void) WriteBlobString(image,message);
4608 case PolylinePrimitive:
4610 if (primitive_info[j].coordinates < 2)
4615 (void) CopyMagickString(message," <polyline points=\"",
4617 (void) WriteBlobString(image,message);
4618 length=strlen(message);
4621 (void) FormatLocaleString(message,MagickPathExtent,"%g,%g ",
4622 primitive_info[j].point.x,primitive_info[j].point.y);
4623 length+=strlen(message);
4626 (void) WriteBlobString(image,"\n ");
4627 length=strlen(message)+5;
4629 (void) WriteBlobString(image,message);
4631 (void) WriteBlobString(image,"\"/>\n");
4634 case PolygonPrimitive:
4636 if (primitive_info[j].coordinates < 3)
4641 primitive_info[i]=primitive_info[j];
4642 primitive_info[i].coordinates=0;
4643 primitive_info[j].coordinates++;
4645 (void) CopyMagickString(message," <polygon points=\"",MagickPathExtent);
4646 (void) WriteBlobString(image,message);
4647 length=strlen(message);
4650 (void) FormatLocaleString(message,MagickPathExtent,"%g,%g ",
4651 primitive_info[j].point.x,primitive_info[j].point.y);
4652 length+=strlen(message);
4655 (void) WriteBlobString(image,"\n ");
4656 length=strlen(message)+5;
4658 (void) WriteBlobString(image,message);
4660 (void) WriteBlobString(image,"\"/>\n");
4663 case BezierPrimitive:
4665 if (primitive_info[j].coordinates < 3)
4677 GetNextToken(q,&q,extent,token);
4678 number_attributes=1;
4679 for (p=token; *p != '\0'; p++)
4680 if (isalpha((int) *p))
4681 number_attributes++;
4682 if (i > (ssize_t) (number_points-6*BezierQuantum*number_attributes-1))
4684 number_points+=6*BezierQuantum*number_attributes;
4685 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4686 number_points,sizeof(*primitive_info));
4687 if (primitive_info == (PrimitiveInfo *) NULL)
4689 (void) ThrowMagickException(exception,GetMagickModule(),
4690 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4695 (void) WriteBlobString(image," <path d=\"");
4696 (void) WriteBlobString(image,token);
4697 (void) WriteBlobString(image,"\"/>\n");
4700 case AlphaPrimitive:
4701 case ColorPrimitive:
4703 if (primitive_info[j].coordinates != 1)
4708 GetNextToken(q,&q,extent,token);
4709 if (LocaleCompare("point",token) == 0)
4710 primitive_info[j].method=PointMethod;
4711 if (LocaleCompare("replace",token) == 0)
4712 primitive_info[j].method=ReplaceMethod;
4713 if (LocaleCompare("floodfill",token) == 0)
4714 primitive_info[j].method=FloodfillMethod;
4715 if (LocaleCompare("filltoborder",token) == 0)
4716 primitive_info[j].method=FillToBorderMethod;
4717 if (LocaleCompare("reset",token) == 0)
4718 primitive_info[j].method=ResetMethod;
4726 if (primitive_info[j].coordinates != 1)
4731 GetNextToken(q,&q,extent,token);
4732 (void) FormatLocaleString(message,MagickPathExtent,
4733 " <text x=\"%g\" y=\"%g\">",primitive_info[j].point.x,
4734 primitive_info[j].point.y);
4735 (void) WriteBlobString(image,message);
4736 for (p=token; *p != '\0'; p++)
4739 case '<': (void) WriteBlobString(image,"<"); break;
4740 case '>': (void) WriteBlobString(image,">"); break;
4741 case '&': (void) WriteBlobString(image,"&"); break;
4742 default: (void) WriteBlobByte(image,*p); break;
4744 (void) WriteBlobString(image,"</text>\n");
4747 case ImagePrimitive:
4749 if (primitive_info[j].coordinates != 2)
4754 GetNextToken(q,&q,extent,token);
4755 (void) FormatLocaleString(message,MagickPathExtent,
4756 " <image x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" "
4757 "xlink:href=\"%s\"/>\n",primitive_info[j].point.x,
4758 primitive_info[j].point.y,primitive_info[j+1].point.x,
4759 primitive_info[j+1].point.y,token);
4760 (void) WriteBlobString(image,message);
4764 if (primitive_info == (PrimitiveInfo *) NULL)
4766 primitive_info[i].primitive=UndefinedPrimitive;
4767 if (status == MagickFalse)
4770 (void) WriteBlobString(image,"</svg>\n");
4772 Relinquish resources.
4774 token=DestroyString(token);
4775 if (primitive_info != (PrimitiveInfo *) NULL)
4776 primitive_info=(PrimitiveInfo *) RelinquishMagickMemory(primitive_info);
4777 (void) CloseBlob(image);