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__) && !defined(__MINGW64__)
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 entry->mime_type=ConstantString("image/svg+xml");
3350 if (*version != '\0')
3351 entry->version=ConstantString(version);
3352 entry->magick=(IsImageFormatHandler *) IsSVG;
3353 (void) RegisterMagickInfo(entry);
3354 entry=AcquireMagickInfo("SVG","SVGZ","Compressed Scalable Vector Graphics");
3355 #if defined(MAGICKCORE_XML_DELEGATE)
3356 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3358 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3359 entry->flags^=CoderBlobSupportFlag;
3360 entry->mime_type=ConstantString("image/svg+xml");
3361 if (*version != '\0')
3362 entry->version=ConstantString(version);
3363 entry->magick=(IsImageFormatHandler *) IsSVG;
3364 (void) RegisterMagickInfo(entry);
3365 entry=AcquireMagickInfo("SVG","MSVG",
3366 "ImageMagick's own SVG internal renderer");
3367 #if defined(MAGICKCORE_XML_DELEGATE)
3368 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3370 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3371 entry->flags^=CoderBlobSupportFlag;
3372 entry->magick=(IsImageFormatHandler *) IsSVG;
3373 (void) RegisterMagickInfo(entry);
3374 return(MagickImageCoderSignature);
3379 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3383 % U n r e g i s t e r S V G I m a g e %
3387 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3389 % UnregisterSVGImage() removes format registrations made by the
3390 % SVG module from the list of supported formats.
3392 % The format of the UnregisterSVGImage method is:
3394 % UnregisterSVGImage(void)
3397 ModuleExport void UnregisterSVGImage(void)
3399 (void) UnregisterMagickInfo("SVGZ");
3400 (void) UnregisterMagickInfo("SVG");
3401 (void) UnregisterMagickInfo("MSVG");
3402 #if defined(MAGICKCORE_XML_DELEGATE)
3409 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3413 % W r i t e S V G I m a g e %
3417 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3419 % WriteSVGImage() writes a image in the SVG - XML based W3C standard
3422 % The format of the WriteSVGImage method is:
3424 % MagickBooleanType WriteSVGImage(const ImageInfo *image_info,
3425 % Image *image,ExceptionInfo *exception)
3427 % A description of each parameter follows.
3429 % o image_info: the image info.
3431 % o image: The image.
3433 % o exception: return any errors or warnings in this structure.
3437 static void AffineToTransform(Image *image,AffineMatrix *affine)
3440 transform[MagickPathExtent];
3442 if ((fabs(affine->tx) < MagickEpsilon) && (fabs(affine->ty) < MagickEpsilon))
3444 if ((fabs(affine->rx) < MagickEpsilon) &&
3445 (fabs(affine->ry) < MagickEpsilon))
3447 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3448 (fabs(affine->sy-1.0) < MagickEpsilon))
3450 (void) WriteBlobString(image,"\">\n");
3453 (void) FormatLocaleString(transform,MagickPathExtent,
3454 "\" transform=\"scale(%g,%g)\">\n",affine->sx,affine->sy);
3455 (void) WriteBlobString(image,transform);
3460 if ((fabs(affine->sx-affine->sy) < MagickEpsilon) &&
3461 (fabs(affine->rx+affine->ry) < MagickEpsilon) &&
3462 (fabs(affine->sx*affine->sx+affine->rx*affine->rx-1.0) <
3468 theta=(180.0/MagickPI)*atan2(affine->rx,affine->sx);
3469 (void) FormatLocaleString(transform,MagickPathExtent,
3470 "\" transform=\"rotate(%g)\">\n",theta);
3471 (void) WriteBlobString(image,transform);
3478 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3479 (fabs(affine->rx) < MagickEpsilon) &&
3480 (fabs(affine->ry) < MagickEpsilon) &&
3481 (fabs(affine->sy-1.0) < MagickEpsilon))
3483 (void) FormatLocaleString(transform,MagickPathExtent,
3484 "\" transform=\"translate(%g,%g)\">\n",affine->tx,affine->ty);
3485 (void) WriteBlobString(image,transform);
3489 (void) FormatLocaleString(transform,MagickPathExtent,
3490 "\" transform=\"matrix(%g %g %g %g %g %g)\">\n",
3491 affine->sx,affine->rx,affine->ry,affine->sy,affine->tx,affine->ty);
3492 (void) WriteBlobString(image,transform);
3495 static MagickBooleanType IsPoint(const char *point)
3503 value=strtol(point,&p,10);
3505 return(p != point ? MagickTrue : MagickFalse);
3508 static MagickBooleanType TraceSVGImage(Image *image,ExceptionInfo *exception)
3510 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
3515 at_fitting_opts_type
3527 register const Quantum
3541 Trace image and write as SVG.
3543 fitting_options=at_fitting_opts_new();
3544 output_options=at_output_opts_new();
3545 (void) SetImageGray(image,exception);
3546 type=GetImageType(image);
3548 if ((type == BilevelType) || (type == GrayscaleType))
3550 trace=at_bitmap_new(image->columns,image->rows,number_planes);
3552 for (y=0; y < (ssize_t) image->rows; y++)
3554 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3555 if (p == (const Quantum *) NULL)
3557 for (x=0; x < (ssize_t) image->columns; x++)
3559 trace->bitmap[i++]=GetPixelRed(image,p);
3560 if (number_planes == 3)
3562 trace->bitmap[i++]=GetPixelGreen(image,p);
3563 trace->bitmap[i++]=GetPixelBlue(image,p);
3565 p+=GetPixelChannels(image);
3568 splines=at_splines_new_full(trace,fitting_options,NULL,NULL,NULL,NULL,NULL,
3570 at_splines_write(at_output_get_handler_by_suffix((char *) "svg"),
3571 GetBlobFileHandle(image),image->filename,output_options,splines,NULL,
3576 at_splines_free(splines);
3577 at_bitmap_free(trace);
3578 at_output_opts_free(output_options);
3579 at_fitting_opts_free(fitting_options);
3585 message[MagickPathExtent];
3606 (void) WriteBlobString(image,
3607 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");
3608 (void) WriteBlobString(image,
3609 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"");
3610 (void) WriteBlobString(image,
3611 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
3612 (void) FormatLocaleString(message,MagickPathExtent,
3613 "<svg version=\"1.1\" id=\"Layer_1\" "
3614 "xmlns=\"http://www.w3.org/2000/svg\" "
3615 "xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\" "
3616 "width=\"%.20gpx\" height=\"%.20gpx\" viewBox=\"0 0 %.20g %.20g\" "
3617 "enable-background=\"new 0 0 %.20g %.20g\" xml:space=\"preserve\">",
3618 (double) image->columns,(double) image->rows,
3619 (double) image->columns,(double) image->rows,
3620 (double) image->columns,(double) image->rows);
3621 (void) WriteBlobString(image,message);
3622 clone_image=CloneImage(image,0,0,MagickTrue,exception);
3623 if (clone_image == (Image *) NULL)
3624 return(MagickFalse);
3625 image_info=AcquireImageInfo();
3626 (void) CopyMagickString(image_info->magick,"PNG",MagickPathExtent);
3628 blob=(unsigned char *) ImageToBlob(image_info,clone_image,&blob_length,
3630 clone_image=DestroyImage(clone_image);
3631 image_info=DestroyImageInfo(image_info);
3632 if (blob == (unsigned char *) NULL)
3633 return(MagickFalse);
3635 base64=Base64Encode(blob,blob_length,&encode_length);
3636 blob=(unsigned char *) RelinquishMagickMemory(blob);
3637 (void) FormatLocaleString(message,MagickPathExtent,
3638 " <image id=\"image%.20g\" width=\"%.20g\" height=\"%.20g\" "
3639 "x=\"%.20g\" y=\"%.20g\"\n xlink:href=\"data:image/png;base64,",
3640 (double) image->scene,(double) image->columns,(double) image->rows,
3641 (double) image->page.x,(double) image->page.y);
3642 (void) WriteBlobString(image,message);
3644 for (i=(ssize_t) encode_length; i > 0; i-=76)
3646 (void) FormatLocaleString(message,MagickPathExtent,"%.76s",p);
3647 (void) WriteBlobString(image,message);
3650 (void) WriteBlobString(image,"\n");
3652 base64=DestroyString(base64);
3653 (void) WriteBlobString(image,"\" />\n");
3654 (void) WriteBlobString(image,"</svg>\n");
3661 static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
3662 ExceptionInfo *exception)
3664 #define BezierQuantum 200
3670 keyword[MagickPathExtent],
3671 message[MagickPathExtent],
3672 name[MagickPathExtent],
3675 type[MagickPathExtent];
3716 Open output image file.
3718 assert(image_info != (const ImageInfo *) NULL);
3719 assert(image_info->signature == MagickCoreSignature);
3720 assert(image != (Image *) NULL);
3721 assert(image->signature == MagickCoreSignature);
3722 if (image->debug != MagickFalse)
3723 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3724 assert(exception != (ExceptionInfo *) NULL);
3725 assert(exception->signature == MagickCoreSignature);
3726 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
3727 if (status == MagickFalse)
3729 value=GetImageArtifact(image,"SVG");
3730 if (value != (char *) NULL)
3732 (void) WriteBlobString(image,value);
3733 (void) CloseBlob(image);
3736 value=GetImageArtifact(image,"MVG");
3737 if (value == (char *) NULL)
3738 return(TraceSVGImage(image,exception));
3742 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3743 (void) WriteBlobString(image,
3744 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3745 (void) WriteBlobString(image,
3746 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3747 (void) FormatLocaleString(message,MagickPathExtent,
3748 "<svg width=\"%.20g\" height=\"%.20g\">\n",(double) image->columns,(double)
3750 (void) WriteBlobString(image,message);
3752 Allocate primitive info memory.
3755 primitive_info=(PrimitiveInfo *) AcquireQuantumMemory(number_points,
3756 sizeof(*primitive_info));
3757 if (primitive_info == (PrimitiveInfo *) NULL)
3758 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3759 GetAffineMatrix(&affine);
3760 token=AcquireString(value);
3761 extent=strlen(token)+MagickPathExtent;
3765 for (q=(const char *) value; *q != '\0'; )
3768 Interpret graphic primitive.
3770 GetNextToken(q,&q,MagickPathExtent,keyword);
3771 if (*keyword == '\0')
3773 if (*keyword == '#')
3778 if (active != MagickFalse)
3780 AffineToTransform(image,&affine);
3783 (void) WriteBlobString(image,"<desc>");
3784 (void) WriteBlobString(image,keyword+1);
3785 for ( ; (*q != '\n') && (*q != '\0'); q++)
3788 case '<': (void) WriteBlobString(image,"<"); break;
3789 case '>': (void) WriteBlobString(image,">"); break;
3790 case '&': (void) WriteBlobString(image,"&"); break;
3791 default: (void) WriteBlobByte(image,*q); break;
3793 (void) WriteBlobString(image,"</desc>\n");
3796 primitive_type=UndefinedPrimitive;
3804 if (LocaleCompare("affine",keyword) == 0)
3806 GetNextToken(q,&q,extent,token);
3807 affine.sx=StringToDouble(token,&next_token);
3808 GetNextToken(q,&q,extent,token);
3810 GetNextToken(q,&q,extent,token);
3811 affine.rx=StringToDouble(token,&next_token);
3812 GetNextToken(q,&q,extent,token);
3814 GetNextToken(q,&q,extent,token);
3815 affine.ry=StringToDouble(token,&next_token);
3816 GetNextToken(q,&q,extent,token);
3818 GetNextToken(q,&q,extent,token);
3819 affine.sy=StringToDouble(token,&next_token);
3820 GetNextToken(q,&q,extent,token);
3822 GetNextToken(q,&q,extent,token);
3823 affine.tx=StringToDouble(token,&next_token);
3824 GetNextToken(q,&q,extent,token);
3826 GetNextToken(q,&q,extent,token);
3827 affine.ty=StringToDouble(token,&next_token);
3830 if (LocaleCompare("alpha",keyword) == 0)
3832 primitive_type=AlphaPrimitive;
3835 if (LocaleCompare("angle",keyword) == 0)
3837 GetNextToken(q,&q,extent,token);
3838 affine.rx=StringToDouble(token,&next_token);
3839 affine.ry=StringToDouble(token,&next_token);
3842 if (LocaleCompare("arc",keyword) == 0)
3844 primitive_type=ArcPrimitive;
3853 if (LocaleCompare("bezier",keyword) == 0)
3855 primitive_type=BezierPrimitive;
3864 if (LocaleCompare("clip-path",keyword) == 0)
3866 GetNextToken(q,&q,extent,token);
3867 (void) FormatLocaleString(message,MagickPathExtent,
3868 "clip-path:url(#%s);",token);
3869 (void) WriteBlobString(image,message);
3872 if (LocaleCompare("clip-rule",keyword) == 0)
3874 GetNextToken(q,&q,extent,token);
3875 (void) FormatLocaleString(message,MagickPathExtent,
3876 "clip-rule:%s;",token);
3877 (void) WriteBlobString(image,message);
3880 if (LocaleCompare("clip-units",keyword) == 0)
3882 GetNextToken(q,&q,extent,token);
3883 (void) FormatLocaleString(message,MagickPathExtent,
3884 "clipPathUnits=%s;",token);
3885 (void) WriteBlobString(image,message);
3888 if (LocaleCompare("circle",keyword) == 0)
3890 primitive_type=CirclePrimitive;
3893 if (LocaleCompare("color",keyword) == 0)
3895 primitive_type=ColorPrimitive;
3904 if (LocaleCompare("decorate",keyword) == 0)
3906 GetNextToken(q,&q,extent,token);
3907 (void) FormatLocaleString(message,MagickPathExtent,
3908 "text-decoration:%s;",token);
3909 (void) WriteBlobString(image,message);
3918 if (LocaleCompare("ellipse",keyword) == 0)
3920 primitive_type=EllipsePrimitive;
3929 if (LocaleCompare("fill",keyword) == 0)
3931 GetNextToken(q,&q,extent,token);
3932 (void) FormatLocaleString(message,MagickPathExtent,"fill:%s;",
3934 (void) WriteBlobString(image,message);
3937 if (LocaleCompare("fill-rule",keyword) == 0)
3939 GetNextToken(q,&q,extent,token);
3940 (void) FormatLocaleString(message,MagickPathExtent,
3941 "fill-rule:%s;",token);
3942 (void) WriteBlobString(image,message);
3945 if (LocaleCompare("fill-opacity",keyword) == 0)
3947 GetNextToken(q,&q,extent,token);
3948 (void) FormatLocaleString(message,MagickPathExtent,
3949 "fill-opacity:%s;",token);
3950 (void) WriteBlobString(image,message);
3953 if (LocaleCompare("font-family",keyword) == 0)
3955 GetNextToken(q,&q,extent,token);
3956 (void) FormatLocaleString(message,MagickPathExtent,
3957 "font-family:%s;",token);
3958 (void) WriteBlobString(image,message);
3961 if (LocaleCompare("font-stretch",keyword) == 0)
3963 GetNextToken(q,&q,extent,token);
3964 (void) FormatLocaleString(message,MagickPathExtent,
3965 "font-stretch:%s;",token);
3966 (void) WriteBlobString(image,message);
3969 if (LocaleCompare("font-style",keyword) == 0)
3971 GetNextToken(q,&q,extent,token);
3972 (void) FormatLocaleString(message,MagickPathExtent,
3973 "font-style:%s;",token);
3974 (void) WriteBlobString(image,message);
3977 if (LocaleCompare("font-size",keyword) == 0)
3979 GetNextToken(q,&q,extent,token);
3980 (void) FormatLocaleString(message,MagickPathExtent,
3981 "font-size:%s;",token);
3982 (void) WriteBlobString(image,message);
3985 if (LocaleCompare("font-weight",keyword) == 0)
3987 GetNextToken(q,&q,extent,token);
3988 (void) FormatLocaleString(message,MagickPathExtent,
3989 "font-weight:%s;",token);
3990 (void) WriteBlobString(image,message);
3999 if (LocaleCompare("gradient-units",keyword) == 0)
4001 GetNextToken(q,&q,extent,token);
4004 if (LocaleCompare("text-align",keyword) == 0)
4006 GetNextToken(q,&q,extent,token);
4007 (void) FormatLocaleString(message,MagickPathExtent,
4008 "text-align %s ",token);
4009 (void) WriteBlobString(image,message);
4012 if (LocaleCompare("text-anchor",keyword) == 0)
4014 GetNextToken(q,&q,extent,token);
4015 (void) FormatLocaleString(message,MagickPathExtent,
4016 "text-anchor %s ",token);
4017 (void) WriteBlobString(image,message);
4026 if (LocaleCompare("image",keyword) == 0)
4028 GetNextToken(q,&q,extent,token);
4029 primitive_type=ImagePrimitive;
4038 if (LocaleCompare("line",keyword) == 0)
4040 primitive_type=LinePrimitive;
4049 if (LocaleCompare("opacity",keyword) == 0)
4051 GetNextToken(q,&q,extent,token);
4052 (void) FormatLocaleString(message,MagickPathExtent,"opacity %s ",
4054 (void) WriteBlobString(image,message);
4063 if (LocaleCompare("path",keyword) == 0)
4065 primitive_type=PathPrimitive;
4068 if (LocaleCompare("point",keyword) == 0)
4070 primitive_type=PointPrimitive;
4073 if (LocaleCompare("polyline",keyword) == 0)
4075 primitive_type=PolylinePrimitive;
4078 if (LocaleCompare("polygon",keyword) == 0)
4080 primitive_type=PolygonPrimitive;
4083 if (LocaleCompare("pop",keyword) == 0)
4085 GetNextToken(q,&q,extent,token);
4086 if (LocaleCompare("clip-path",token) == 0)
4088 (void) WriteBlobString(image,"</clipPath>\n");
4091 if (LocaleCompare("defs",token) == 0)
4093 (void) WriteBlobString(image,"</defs>\n");
4096 if (LocaleCompare("gradient",token) == 0)
4098 (void) FormatLocaleString(message,MagickPathExtent,
4099 "</%sGradient>\n",type);
4100 (void) WriteBlobString(image,message);
4103 if (LocaleCompare("graphic-context",token) == 0)
4107 ThrowWriterException(DrawError,
4108 "UnbalancedGraphicContextPushPop");
4109 (void) WriteBlobString(image,"</g>\n");
4111 if (LocaleCompare("pattern",token) == 0)
4113 (void) WriteBlobString(image,"</pattern>\n");
4116 if (LocaleCompare("defs",token) == 0)
4117 (void) WriteBlobString(image,"</g>\n");
4120 if (LocaleCompare("push",keyword) == 0)
4122 GetNextToken(q,&q,extent,token);
4123 if (LocaleCompare("clip-path",token) == 0)
4125 GetNextToken(q,&q,extent,token);
4126 (void) FormatLocaleString(message,MagickPathExtent,
4127 "<clipPath id=\"%s\">\n",token);
4128 (void) WriteBlobString(image,message);
4131 if (LocaleCompare("defs",token) == 0)
4133 (void) WriteBlobString(image,"<defs>\n");
4136 if (LocaleCompare("gradient",token) == 0)
4138 GetNextToken(q,&q,extent,token);
4139 (void) CopyMagickString(name,token,MagickPathExtent);
4140 GetNextToken(q,&q,extent,token);
4141 (void) CopyMagickString(type,token,MagickPathExtent);
4142 GetNextToken(q,&q,extent,token);
4143 svg_info.segment.x1=StringToDouble(token,&next_token);
4144 svg_info.element.cx=StringToDouble(token,&next_token);
4145 GetNextToken(q,&q,extent,token);
4147 GetNextToken(q,&q,extent,token);
4148 svg_info.segment.y1=StringToDouble(token,&next_token);
4149 svg_info.element.cy=StringToDouble(token,&next_token);
4150 GetNextToken(q,&q,extent,token);
4152 GetNextToken(q,&q,extent,token);
4153 svg_info.segment.x2=StringToDouble(token,&next_token);
4154 svg_info.element.major=StringToDouble(token,
4156 GetNextToken(q,&q,extent,token);
4158 GetNextToken(q,&q,extent,token);
4159 svg_info.segment.y2=StringToDouble(token,&next_token);
4160 svg_info.element.minor=StringToDouble(token,
4162 (void) FormatLocaleString(message,MagickPathExtent,
4163 "<%sGradient id=\"%s\" x1=\"%g\" y1=\"%g\" x2=\"%g\" "
4164 "y2=\"%g\">\n",type,name,svg_info.segment.x1,
4165 svg_info.segment.y1,svg_info.segment.x2,svg_info.segment.y2);
4166 if (LocaleCompare(type,"radial") == 0)
4168 GetNextToken(q,&q,extent,token);
4170 GetNextToken(q,&q,extent,token);
4171 svg_info.element.angle=StringToDouble(token,
4173 (void) FormatLocaleString(message,MagickPathExtent,
4174 "<%sGradient id=\"%s\" cx=\"%g\" cy=\"%g\" r=\"%g\" "
4175 "fx=\"%g\" fy=\"%g\">\n",type,name,
4176 svg_info.element.cx,svg_info.element.cy,
4177 svg_info.element.angle,svg_info.element.major,
4178 svg_info.element.minor);
4180 (void) WriteBlobString(image,message);
4183 if (LocaleCompare("graphic-context",token) == 0)
4188 AffineToTransform(image,&affine);
4191 (void) WriteBlobString(image,"<g style=\"");
4194 if (LocaleCompare("pattern",token) == 0)
4196 GetNextToken(q,&q,extent,token);
4197 (void) CopyMagickString(name,token,MagickPathExtent);
4198 GetNextToken(q,&q,extent,token);
4199 svg_info.bounds.x=StringToDouble(token,&next_token);
4200 GetNextToken(q,&q,extent,token);
4202 GetNextToken(q,&q,extent,token);
4203 svg_info.bounds.y=StringToDouble(token,&next_token);
4204 GetNextToken(q,&q,extent,token);
4206 GetNextToken(q,&q,extent,token);
4207 svg_info.bounds.width=StringToDouble(token,
4209 GetNextToken(q,&q,extent,token);
4211 GetNextToken(q,&q,extent,token);
4212 svg_info.bounds.height=StringToDouble(token,(char **) NULL);
4213 (void) FormatLocaleString(message,MagickPathExtent,
4214 "<pattern id=\"%s\" x=\"%g\" y=\"%g\" width=\"%g\" "
4215 "height=\"%g\">\n",name,svg_info.bounds.x,svg_info.bounds.y,
4216 svg_info.bounds.width,svg_info.bounds.height);
4217 (void) WriteBlobString(image,message);
4228 if (LocaleCompare("rectangle",keyword) == 0)
4230 primitive_type=RectanglePrimitive;
4233 if (LocaleCompare("roundRectangle",keyword) == 0)
4235 primitive_type=RoundRectanglePrimitive;
4238 if (LocaleCompare("rotate",keyword) == 0)
4240 GetNextToken(q,&q,extent,token);
4241 (void) FormatLocaleString(message,MagickPathExtent,"rotate(%s) ",
4243 (void) WriteBlobString(image,message);
4252 if (LocaleCompare("scale",keyword) == 0)
4254 GetNextToken(q,&q,extent,token);
4255 affine.sx=StringToDouble(token,&next_token);
4256 GetNextToken(q,&q,extent,token);
4258 GetNextToken(q,&q,extent,token);
4259 affine.sy=StringToDouble(token,&next_token);
4262 if (LocaleCompare("skewX",keyword) == 0)
4264 GetNextToken(q,&q,extent,token);
4265 (void) FormatLocaleString(message,MagickPathExtent,"skewX(%s) ",
4267 (void) WriteBlobString(image,message);
4270 if (LocaleCompare("skewY",keyword) == 0)
4272 GetNextToken(q,&q,extent,token);
4273 (void) FormatLocaleString(message,MagickPathExtent,"skewY(%s) ",
4275 (void) WriteBlobString(image,message);
4278 if (LocaleCompare("stop-color",keyword) == 0)
4281 color[MagickPathExtent];
4283 GetNextToken(q,&q,extent,token);
4284 (void) CopyMagickString(color,token,MagickPathExtent);
4285 GetNextToken(q,&q,extent,token);
4286 (void) FormatLocaleString(message,MagickPathExtent,
4287 " <stop offset=\"%s\" stop-color=\"%s\" />\n",token,color);
4288 (void) WriteBlobString(image,message);
4291 if (LocaleCompare("stroke",keyword) == 0)
4293 GetNextToken(q,&q,extent,token);
4294 (void) FormatLocaleString(message,MagickPathExtent,"stroke:%s;",
4296 (void) WriteBlobString(image,message);
4299 if (LocaleCompare("stroke-antialias",keyword) == 0)
4301 GetNextToken(q,&q,extent,token);
4302 (void) FormatLocaleString(message,MagickPathExtent,
4303 "stroke-antialias:%s;",token);
4304 (void) WriteBlobString(image,message);
4307 if (LocaleCompare("stroke-dasharray",keyword) == 0)
4315 GetNextToken(p,&p,extent,token);
4316 for (k=0; IsPoint(token); k++)
4317 GetNextToken(p,&p,extent,token);
4318 (void) WriteBlobString(image,"stroke-dasharray:");
4319 for (j=0; j < k; j++)
4321 GetNextToken(q,&q,extent,token);
4322 (void) FormatLocaleString(message,MagickPathExtent,"%s ",
4324 (void) WriteBlobString(image,message);
4326 (void) WriteBlobString(image,";");
4329 GetNextToken(q,&q,extent,token);
4330 (void) FormatLocaleString(message,MagickPathExtent,
4331 "stroke-dasharray:%s;",token);
4332 (void) WriteBlobString(image,message);
4335 if (LocaleCompare("stroke-dashoffset",keyword) == 0)
4337 GetNextToken(q,&q,extent,token);
4338 (void) FormatLocaleString(message,MagickPathExtent,
4339 "stroke-dashoffset:%s;",token);
4340 (void) WriteBlobString(image,message);
4343 if (LocaleCompare("stroke-linecap",keyword) == 0)
4345 GetNextToken(q,&q,extent,token);
4346 (void) FormatLocaleString(message,MagickPathExtent,
4347 "stroke-linecap:%s;",token);
4348 (void) WriteBlobString(image,message);
4351 if (LocaleCompare("stroke-linejoin",keyword) == 0)
4353 GetNextToken(q,&q,extent,token);
4354 (void) FormatLocaleString(message,MagickPathExtent,
4355 "stroke-linejoin:%s;",token);
4356 (void) WriteBlobString(image,message);
4359 if (LocaleCompare("stroke-miterlimit",keyword) == 0)
4361 GetNextToken(q,&q,extent,token);
4362 (void) FormatLocaleString(message,MagickPathExtent,
4363 "stroke-miterlimit:%s;",token);
4364 (void) WriteBlobString(image,message);
4367 if (LocaleCompare("stroke-opacity",keyword) == 0)
4369 GetNextToken(q,&q,extent,token);
4370 (void) FormatLocaleString(message,MagickPathExtent,
4371 "stroke-opacity:%s;",token);
4372 (void) WriteBlobString(image,message);
4375 if (LocaleCompare("stroke-width",keyword) == 0)
4377 GetNextToken(q,&q,extent,token);
4378 (void) FormatLocaleString(message,MagickPathExtent,
4379 "stroke-width:%s;",token);
4380 (void) WriteBlobString(image,message);
4389 if (LocaleCompare("text",keyword) == 0)
4391 primitive_type=TextPrimitive;
4394 if (LocaleCompare("text-antialias",keyword) == 0)
4396 GetNextToken(q,&q,extent,token);
4397 (void) FormatLocaleString(message,MagickPathExtent,
4398 "text-antialias:%s;",token);
4399 (void) WriteBlobString(image,message);
4402 if (LocaleCompare("tspan",keyword) == 0)
4404 primitive_type=TextPrimitive;
4407 if (LocaleCompare("translate",keyword) == 0)
4409 GetNextToken(q,&q,extent,token);
4410 affine.tx=StringToDouble(token,&next_token);
4411 GetNextToken(q,&q,extent,token);
4413 GetNextToken(q,&q,extent,token);
4414 affine.ty=StringToDouble(token,&next_token);
4423 if (LocaleCompare("viewbox",keyword) == 0)
4425 GetNextToken(q,&q,extent,token);
4427 GetNextToken(q,&q,extent,token);
4428 GetNextToken(q,&q,extent,token);
4430 GetNextToken(q,&q,extent,token);
4431 GetNextToken(q,&q,extent,token);
4433 GetNextToken(q,&q,extent,token);
4434 GetNextToken(q,&q,extent,token);
4446 if (status == MagickFalse)
4448 if (primitive_type == UndefinedPrimitive)
4451 Parse the primitive attributes.
4455 for (x=0; *q != '\0'; x++)
4460 if (IsPoint(q) == MagickFalse)
4462 GetNextToken(q,&q,extent,token);
4463 point.x=StringToDouble(token,&next_token);
4464 GetNextToken(q,&q,extent,token);
4466 GetNextToken(q,&q,extent,token);
4467 point.y=StringToDouble(token,&next_token);
4468 GetNextToken(q,(const char **) NULL,extent,token);
4470 GetNextToken(q,&q,extent,token);
4471 primitive_info[i].primitive=primitive_type;
4472 primitive_info[i].point=point;
4473 primitive_info[i].coordinates=0;
4474 primitive_info[i].method=FloodfillMethod;
4476 if (i < (ssize_t) (number_points-6*BezierQuantum-360))
4478 number_points+=6*BezierQuantum+360;
4479 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4480 number_points,sizeof(*primitive_info));
4481 if (primitive_info == (PrimitiveInfo *) NULL)
4483 (void) ThrowMagickException(exception,GetMagickModule(),
4484 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
4488 primitive_info[j].primitive=primitive_type;
4489 primitive_info[j].coordinates=x;
4490 primitive_info[j].method=FloodfillMethod;
4491 primitive_info[j].text=(char *) NULL;
4494 AffineToTransform(image,&affine);
4498 switch (primitive_type)
4500 case PointPrimitive:
4503 if (primitive_info[j].coordinates != 1)
4512 if (primitive_info[j].coordinates != 2)
4517 (void) FormatLocaleString(message,MagickPathExtent,
4518 " <line x1=\"%g\" y1=\"%g\" x2=\"%g\" y2=\"%g\"/>\n",
4519 primitive_info[j].point.x,primitive_info[j].point.y,
4520 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4521 (void) WriteBlobString(image,message);
4524 case RectanglePrimitive:
4526 if (primitive_info[j].coordinates != 2)
4531 (void) FormatLocaleString(message,MagickPathExtent,
4532 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"/>\n",
4533 primitive_info[j].point.x,primitive_info[j].point.y,
4534 primitive_info[j+1].point.x-primitive_info[j].point.x,
4535 primitive_info[j+1].point.y-primitive_info[j].point.y);
4536 (void) WriteBlobString(image,message);
4539 case RoundRectanglePrimitive:
4541 if (primitive_info[j].coordinates != 3)
4546 (void) FormatLocaleString(message,MagickPathExtent,
4547 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" rx=\"%g\" "
4548 "ry=\"%g\"/>\n",primitive_info[j].point.x,
4549 primitive_info[j].point.y,primitive_info[j+1].point.x-
4550 primitive_info[j].point.x,primitive_info[j+1].point.y-
4551 primitive_info[j].point.y,primitive_info[j+2].point.x,
4552 primitive_info[j+2].point.y);
4553 (void) WriteBlobString(image,message);
4558 if (primitive_info[j].coordinates != 3)
4565 case EllipsePrimitive:
4567 if (primitive_info[j].coordinates != 3)
4572 (void) FormatLocaleString(message,MagickPathExtent,
4573 " <ellipse cx=\"%g\" cy=\"%g\" rx=\"%g\" ry=\"%g\"/>\n",
4574 primitive_info[j].point.x,primitive_info[j].point.y,
4575 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4576 (void) WriteBlobString(image,message);
4579 case CirclePrimitive:
4585 if (primitive_info[j].coordinates != 2)
4590 alpha=primitive_info[j+1].point.x-primitive_info[j].point.x;
4591 beta=primitive_info[j+1].point.y-primitive_info[j].point.y;
4592 (void) FormatLocaleString(message,MagickPathExtent,
4593 " <circle cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
4594 primitive_info[j].point.x,primitive_info[j].point.y,
4596 (void) WriteBlobString(image,message);
4599 case PolylinePrimitive:
4601 if (primitive_info[j].coordinates < 2)
4606 (void) CopyMagickString(message," <polyline points=\"",
4608 (void) WriteBlobString(image,message);
4609 length=strlen(message);
4612 (void) FormatLocaleString(message,MagickPathExtent,"%g,%g ",
4613 primitive_info[j].point.x,primitive_info[j].point.y);
4614 length+=strlen(message);
4617 (void) WriteBlobString(image,"\n ");
4618 length=strlen(message)+5;
4620 (void) WriteBlobString(image,message);
4622 (void) WriteBlobString(image,"\"/>\n");
4625 case PolygonPrimitive:
4627 if (primitive_info[j].coordinates < 3)
4632 primitive_info[i]=primitive_info[j];
4633 primitive_info[i].coordinates=0;
4634 primitive_info[j].coordinates++;
4636 (void) CopyMagickString(message," <polygon points=\"",MagickPathExtent);
4637 (void) WriteBlobString(image,message);
4638 length=strlen(message);
4641 (void) FormatLocaleString(message,MagickPathExtent,"%g,%g ",
4642 primitive_info[j].point.x,primitive_info[j].point.y);
4643 length+=strlen(message);
4646 (void) WriteBlobString(image,"\n ");
4647 length=strlen(message)+5;
4649 (void) WriteBlobString(image,message);
4651 (void) WriteBlobString(image,"\"/>\n");
4654 case BezierPrimitive:
4656 if (primitive_info[j].coordinates < 3)
4668 GetNextToken(q,&q,extent,token);
4669 number_attributes=1;
4670 for (p=token; *p != '\0'; p++)
4671 if (isalpha((int) *p))
4672 number_attributes++;
4673 if (i > (ssize_t) (number_points-6*BezierQuantum*number_attributes-1))
4675 number_points+=6*BezierQuantum*number_attributes;
4676 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4677 number_points,sizeof(*primitive_info));
4678 if (primitive_info == (PrimitiveInfo *) NULL)
4680 (void) ThrowMagickException(exception,GetMagickModule(),
4681 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4686 (void) WriteBlobString(image," <path d=\"");
4687 (void) WriteBlobString(image,token);
4688 (void) WriteBlobString(image,"\"/>\n");
4691 case AlphaPrimitive:
4692 case ColorPrimitive:
4694 if (primitive_info[j].coordinates != 1)
4699 GetNextToken(q,&q,extent,token);
4700 if (LocaleCompare("point",token) == 0)
4701 primitive_info[j].method=PointMethod;
4702 if (LocaleCompare("replace",token) == 0)
4703 primitive_info[j].method=ReplaceMethod;
4704 if (LocaleCompare("floodfill",token) == 0)
4705 primitive_info[j].method=FloodfillMethod;
4706 if (LocaleCompare("filltoborder",token) == 0)
4707 primitive_info[j].method=FillToBorderMethod;
4708 if (LocaleCompare("reset",token) == 0)
4709 primitive_info[j].method=ResetMethod;
4717 if (primitive_info[j].coordinates != 1)
4722 GetNextToken(q,&q,extent,token);
4723 (void) FormatLocaleString(message,MagickPathExtent,
4724 " <text x=\"%g\" y=\"%g\">",primitive_info[j].point.x,
4725 primitive_info[j].point.y);
4726 (void) WriteBlobString(image,message);
4727 for (p=token; *p != '\0'; p++)
4730 case '<': (void) WriteBlobString(image,"<"); break;
4731 case '>': (void) WriteBlobString(image,">"); break;
4732 case '&': (void) WriteBlobString(image,"&"); break;
4733 default: (void) WriteBlobByte(image,*p); break;
4735 (void) WriteBlobString(image,"</text>\n");
4738 case ImagePrimitive:
4740 if (primitive_info[j].coordinates != 2)
4745 GetNextToken(q,&q,extent,token);
4746 (void) FormatLocaleString(message,MagickPathExtent,
4747 " <image x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" "
4748 "xlink:href=\"%s\"/>\n",primitive_info[j].point.x,
4749 primitive_info[j].point.y,primitive_info[j+1].point.x,
4750 primitive_info[j+1].point.y,token);
4751 (void) WriteBlobString(image,message);
4755 if (primitive_info == (PrimitiveInfo *) NULL)
4757 primitive_info[i].primitive=UndefinedPrimitive;
4758 if (status == MagickFalse)
4761 (void) WriteBlobString(image,"</svg>\n");
4763 Relinquish resources.
4765 token=DestroyString(token);
4766 if (primitive_info != (PrimitiveInfo *) NULL)
4767 primitive_info=(PrimitiveInfo *) RelinquishMagickMemory(primitive_info);
4768 (void) CloseBlob(image);