2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Scalable Vector Graphics Format %
21 % Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization %
22 % dedicated to making software imaging solutions freely available. %
24 % You may not use this file except in compliance with the License. You may %
25 % obtain a copy of the License at %
27 % http://www.imagemagick.org/script/license.php %
29 % Unless required by applicable law or agreed to in writing, software %
30 % distributed under the License is distributed on an "AS IS" BASIS, %
31 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
32 % See the License for the specific language governing permissions and %
33 % limitations under the License. %
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/annotate.h"
45 #include "MagickCore/artifact.h"
46 #include "MagickCore/attribute.h"
47 #include "MagickCore/blob.h"
48 #include "MagickCore/blob-private.h"
49 #include "MagickCore/cache.h"
50 #include "MagickCore/constitute.h"
51 #include "MagickCore/composite-private.h"
52 #include "MagickCore/delegate.h"
53 #include "MagickCore/delegate-private.h"
54 #include "MagickCore/draw.h"
55 #include "MagickCore/exception.h"
56 #include "MagickCore/exception-private.h"
57 #include "MagickCore/gem.h"
58 #include "MagickCore/image.h"
59 #include "MagickCore/image-private.h"
60 #include "MagickCore/list.h"
61 #include "MagickCore/log.h"
62 #include "MagickCore/magick.h"
63 #include "MagickCore/memory_.h"
64 #include "MagickCore/module.h"
65 #include "MagickCore/monitor.h"
66 #include "MagickCore/monitor-private.h"
67 #include "MagickCore/quantum-private.h"
68 #include "MagickCore/pixel-accessor.h"
69 #include "MagickCore/property.h"
70 #include "MagickCore/resource_.h"
71 #include "MagickCore/static.h"
72 #include "MagickCore/string_.h"
73 #include "MagickCore/string-private.h"
74 #include "MagickCore/token.h"
75 #include "MagickCore/utility.h"
76 #if defined(MAGICKCORE_XML_DELEGATE)
77 # if defined(MAGICKCORE_WINDOWS_SUPPORT)
78 # if !defined(__MINGW32__) && !defined(__MINGW64__)
79 # include <win32config.h>
82 # include <libxml/parser.h>
83 # include <libxml/xmlmemory.h>
84 # include <libxml/parserInternals.h>
85 # include <libxml/xmlerror.h>
88 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
89 #include "autotrace/autotrace.h"
92 #if defined(MAGICKCORE_RSVG_DELEGATE)
93 #include "librsvg/rsvg.h"
94 #if !defined(LIBRSVG_CHECK_VERSION)
95 #include "librsvg/rsvg-cairo.h"
96 #include "librsvg/librsvg-features.h"
97 #elif !LIBRSVG_CHECK_VERSION(2,36,2)
98 #include "librsvg/rsvg-cairo.h"
99 #include "librsvg/librsvg-features.h"
104 Typedef declarations.
106 typedef struct _BoundingBox
115 typedef struct _ElementInfo
125 typedef struct _SVGInfo
179 #if defined(MAGICKCORE_XML_DELEGATE)
189 Forward declarations.
191 static MagickBooleanType
192 WriteSVGImage(const ImageInfo *,Image *,ExceptionInfo *);
195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
205 % IsSVG()() returns MagickTrue if the image format type, identified by the
206 % magick string, is SVG.
208 % The format of the IsSVG method is:
210 % MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
212 % A description of each parameter follows:
214 % o magick: compare image format pattern against these bytes.
216 % o length: Specifies the length of the magick string.
219 static MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
223 if (LocaleNCompare((const char *) magick,"?xml",4) == 0)
228 #if defined(MAGICKCORE_XML_DELEGATE)
230 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
234 % R e a d S V G I m a g e %
238 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
240 % ReadSVGImage() reads a Scalable Vector Gaphics file and returns it. It
241 % allocates the memory necessary for the new Image structure and returns a
242 % pointer to the new image.
244 % The format of the ReadSVGImage method is:
246 % Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
248 % A description of each parameter follows:
250 % o image_info: the image info.
252 % o exception: return any errors or warnings in this structure.
256 static SVGInfo *AcquireSVGInfo(void)
261 svg_info=(SVGInfo *) AcquireMagickMemory(sizeof(*svg_info));
262 if (svg_info == (SVGInfo *) NULL)
263 return((SVGInfo *) NULL);
264 (void) ResetMagickMemory(svg_info,0,sizeof(*svg_info));
265 svg_info->text=AcquireString("");
266 svg_info->scale=(double *) AcquireMagickMemory(sizeof(*svg_info->scale));
267 if (svg_info->scale == (double *) NULL)
268 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
269 GetAffineMatrix(&svg_info->affine);
270 svg_info->scale[0]=ExpandAffine(&svg_info->affine);
274 static SVGInfo *DestroySVGInfo(SVGInfo *svg_info)
276 if (svg_info->text != (char *) NULL)
277 svg_info->text=DestroyString(svg_info->text);
278 if (svg_info->scale != (double *) NULL)
279 svg_info->scale=(double *) RelinquishMagickMemory(svg_info->scale);
280 if (svg_info->title != (char *) NULL)
281 svg_info->title=DestroyString(svg_info->title);
282 if (svg_info->comment != (char *) NULL)
283 svg_info->comment=DestroyString(svg_info->comment);
284 return((SVGInfo *) RelinquishMagickMemory(svg_info));
287 static double GetUserSpaceCoordinateValue(const SVGInfo *svg_info,int type,
291 token[MagickPathExtent];
299 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",string);
300 assert(string != (const char *) NULL);
301 p=(const char *) string;
302 GetMagickToken(p,&p,token);
303 value=StringToDouble(token,(char **) NULL);
304 if (strchr(token,'%') != (char *) NULL)
312 if (svg_info->view_box.width == 0.0)
314 return(svg_info->view_box.width*value/100.0);
318 if (svg_info->view_box.height == 0.0)
320 return(svg_info->view_box.height*value/100.0);
322 alpha=value-svg_info->view_box.width;
323 beta=value-svg_info->view_box.height;
324 return(hypot(alpha,beta)/sqrt(2.0)/100.0);
326 GetMagickToken(p,&p,token);
327 if (LocaleNCompare(token,"cm",2) == 0)
328 return(DefaultResolution*svg_info->scale[0]/2.54*value);
329 if (LocaleNCompare(token,"em",2) == 0)
330 return(svg_info->pointsize*value);
331 if (LocaleNCompare(token,"ex",2) == 0)
332 return(svg_info->pointsize*value/2.0);
333 if (LocaleNCompare(token,"in",2) == 0)
334 return(DefaultResolution*svg_info->scale[0]*value);
335 if (LocaleNCompare(token,"mm",2) == 0)
336 return(DefaultResolution*svg_info->scale[0]/25.4*value);
337 if (LocaleNCompare(token,"pc",2) == 0)
338 return(DefaultResolution*svg_info->scale[0]/6.0*value);
339 if (LocaleNCompare(token,"pt",2) == 0)
340 return(1.25*svg_info->scale[0]*value);
341 if (LocaleNCompare(token,"px",2) == 0)
346 static void StripStyleTokens(char *message)
355 assert(message != (char *) NULL);
356 if (*message == '\0')
358 length=strlen(message);
360 while (isspace((int) ((unsigned char) *p)) != 0)
363 while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
365 (void) CopyMagickMemory(message,p,(size_t) (q-p+1));
367 StripString(message);
370 static char **GetStyleTokens(void *context,const char *style,int *number_tokens)
382 svg_info=(SVGInfo *) context;
385 if (style == (const char *) NULL)
386 return((char **) NULL);
387 text=AcquireString(style);
388 (void) SubstituteString(&text,":","\n");
389 (void) SubstituteString(&text,";","\n");
390 tokens=StringToList(text);
391 text=DestroyString(text);
392 for (i=0; tokens[i] != (char *) NULL; i++)
393 StripStyleTokens(tokens[i]);
398 static char **GetTransformTokens(void *context,const char *text,
414 svg_info=(SVGInfo *) context;
416 if (text == (const char *) NULL)
417 return((char **) NULL);
419 Determine the number of arguments.
421 for (p=text; *p != '\0'; p++)
426 tokens=(char **) AcquireQuantumMemory(*number_tokens+2UL,sizeof(*tokens));
427 if (tokens == (char **) NULL)
429 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
430 ResourceLimitError,"MemoryAllocationFailed","`%s'",text);
431 return((char **) NULL);
434 Convert string to an ASCII list.
438 for (q=p; *q != '\0'; q++)
440 if ((*q != '(') && (*q != ')') && (*q != '\0'))
442 tokens[i]=AcquireString(p);
443 (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
444 StripString(tokens[i++]);
447 tokens[i]=AcquireString(p);
448 (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
449 StripString(tokens[i++]);
450 tokens[i]=(char *) NULL;
454 #if defined(__cplusplus) || defined(c_plusplus)
458 static int SVGIsStandalone(void *context)
464 Is this document tagged standalone?
466 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGIsStandalone()");
467 svg_info=(SVGInfo *) context;
468 return(svg_info->document->standalone == 1);
471 static int SVGHasInternalSubset(void *context)
477 Does this document has an internal subset?
479 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
480 " SAX.SVGHasInternalSubset()");
481 svg_info=(SVGInfo *) context;
482 return(svg_info->document->intSubset != NULL);
485 static int SVGHasExternalSubset(void *context)
491 Does this document has an external subset?
493 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
494 " SAX.SVGHasExternalSubset()");
495 svg_info=(SVGInfo *) context;
496 return(svg_info->document->extSubset != NULL);
499 static void SVGInternalSubset(void *context,const xmlChar *name,
500 const xmlChar *external_id,const xmlChar *system_id)
506 Does this document has an internal subset?
508 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
509 " SAX.internalSubset(%s, %s, %s)",(const char *) name,
510 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
511 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
512 svg_info=(SVGInfo *) context;
513 (void) xmlCreateIntSubset(svg_info->document,name,external_id,system_id);
516 static xmlParserInputPtr SVGResolveEntity(void *context,
517 const xmlChar *public_id,const xmlChar *system_id)
526 Special entity resolver, better left to the parser, it has more
527 context than the application layer. The default behaviour is to
528 not resolve the entities, in that case the ENTITY_REF nodes are
529 built in the structure (and the parameter values).
531 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
532 " SAX.resolveEntity(%s, %s)",
533 (public_id != (const xmlChar *) NULL ? (const char *) public_id : "none"),
534 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
535 svg_info=(SVGInfo *) context;
536 stream=xmlLoadExternalEntity((const char *) system_id,(const char *)
537 public_id,svg_info->parser);
541 static xmlEntityPtr SVGGetEntity(void *context,const xmlChar *name)
547 Get an entity by name.
549 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGGetEntity(%s)",
551 svg_info=(SVGInfo *) context;
552 return(xmlGetDocEntity(svg_info->document,name));
555 static xmlEntityPtr SVGGetParameterEntity(void *context,const xmlChar *name)
561 Get a parameter entity by name.
563 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
564 " SAX.getParameterEntity(%s)",name);
565 svg_info=(SVGInfo *) context;
566 return(xmlGetParameterEntity(svg_info->document,name));
569 static void SVGEntityDeclaration(void *context,const xmlChar *name,int type,
570 const xmlChar *public_id,const xmlChar *system_id,xmlChar *content)
576 An entity definition has been parsed.
578 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
579 " SAX.entityDecl(%s, %d, %s, %s, %s)",name,type,
580 public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
581 system_id != (xmlChar *) NULL ? (const char *) system_id : "none",content);
582 svg_info=(SVGInfo *) context;
583 if (svg_info->parser->inSubset == 1)
584 (void) xmlAddDocEntity(svg_info->document,name,type,public_id,system_id,
587 if (svg_info->parser->inSubset == 2)
588 (void) xmlAddDtdEntity(svg_info->document,name,type,public_id,system_id,
592 static void SVGAttributeDeclaration(void *context,const xmlChar *element,
593 const xmlChar *name,int type,int value,const xmlChar *default_value,
594 xmlEnumerationPtr tree)
607 An attribute definition has been parsed.
609 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
610 " SAX.attributeDecl(%s, %s, %d, %d, %s, ...)",element,name,type,value,
612 svg_info=(SVGInfo *) context;
613 fullname=(xmlChar *) NULL;
614 prefix=(xmlChar *) NULL;
615 parser=svg_info->parser;
616 fullname=(xmlChar *) xmlSplitQName(parser,name,&prefix);
617 if (parser->inSubset == 1)
618 (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->intSubset,
619 element,fullname,prefix,(xmlAttributeType) type,
620 (xmlAttributeDefault) value,default_value,tree);
622 if (parser->inSubset == 2)
623 (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->extSubset,
624 element,fullname,prefix,(xmlAttributeType) type,
625 (xmlAttributeDefault) value,default_value,tree);
626 if (prefix != (xmlChar *) NULL)
628 if (fullname != (xmlChar *) NULL)
632 static void SVGElementDeclaration(void *context,const xmlChar *name,int type,
633 xmlElementContentPtr content)
642 An element definition has been parsed.
644 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
645 " SAX.elementDecl(%s, %d, ...)",name,type);
646 svg_info=(SVGInfo *) context;
647 parser=svg_info->parser;
648 if (parser->inSubset == 1)
649 (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->intSubset,
650 name,(xmlElementTypeVal) type,content);
652 if (parser->inSubset == 2)
653 (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->extSubset,
654 name,(xmlElementTypeVal) type,content);
657 static void SVGNotationDeclaration(void *context,const xmlChar *name,
658 const xmlChar *public_id,const xmlChar *system_id)
667 What to do when a notation declaration has been parsed.
669 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
670 " SAX.notationDecl(%s, %s, %s)",name,
671 public_id != (const xmlChar *) NULL ? (const char *) public_id : "none",
672 system_id != (const xmlChar *) NULL ? (const char *) system_id : "none");
673 svg_info=(SVGInfo *) context;
674 parser=svg_info->parser;
675 if (parser->inSubset == 1)
676 (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
677 name,public_id,system_id);
679 if (parser->inSubset == 2)
680 (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
681 name,public_id,system_id);
684 static void SVGUnparsedEntityDeclaration(void *context,const xmlChar *name,
685 const xmlChar *public_id,const xmlChar *system_id,const xmlChar *notation)
691 What to do when an unparsed entity declaration is parsed.
693 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
694 " SAX.unparsedEntityDecl(%s, %s, %s, %s)",name,
695 public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
696 system_id != (xmlChar *) NULL ? (const char *) system_id : "none",notation);
697 svg_info=(SVGInfo *) context;
698 (void) xmlAddDocEntity(svg_info->document,name,
699 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,public_id,system_id,notation);
703 static void SVGSetDocumentLocator(void *context,xmlSAXLocatorPtr location)
709 Receive the document locator at startup, actually xmlDefaultSAXLocator.
712 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
713 " SAX.setDocumentLocator()");
714 svg_info=(SVGInfo *) context;
718 static void SVGStartDocument(void *context)
727 Called when the document start being processed.
729 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startDocument()");
730 svg_info=(SVGInfo *) context;
731 parser=svg_info->parser;
732 svg_info->document=xmlNewDoc(parser->version);
733 if (svg_info->document == (xmlDocPtr) NULL)
735 if (parser->encoding == NULL)
736 svg_info->document->encoding=(const xmlChar *) NULL;
738 svg_info->document->encoding=xmlStrdup(parser->encoding);
739 svg_info->document->standalone=parser->standalone;
742 static void SVGEndDocument(void *context)
748 Called when the document end has been detected.
750 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.endDocument()");
751 svg_info=(SVGInfo *) context;
752 if (svg_info->offset != (char *) NULL)
753 svg_info->offset=DestroyString(svg_info->offset);
754 if (svg_info->stop_color != (char *) NULL)
755 svg_info->stop_color=DestroyString(svg_info->stop_color);
756 if (svg_info->scale != (double *) NULL)
757 svg_info->scale=(double *) RelinquishMagickMemory(svg_info->scale);
758 if (svg_info->text != (char *) NULL)
759 svg_info->text=DestroyString(svg_info->text);
760 if (svg_info->vertices != (char *) NULL)
761 svg_info->vertices=DestroyString(svg_info->vertices);
762 if (svg_info->url != (char *) NULL)
763 svg_info->url=DestroyString(svg_info->url);
764 #if defined(MAGICKCORE_XML_DELEGATE)
765 if (svg_info->document != (xmlDocPtr) NULL)
767 xmlFreeDoc(svg_info->document);
768 svg_info->document=(xmlDocPtr) NULL;
773 static void SVGStartElement(void *context,const xmlChar *name,
774 const xmlChar **attributes)
778 id[MagickPathExtent],
779 token[MagickPathExtent],
799 Called when an opening tag has been processed.
801 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startElement(%s",
803 svg_info=(SVGInfo *) context;
805 svg_info->scale=(double *) ResizeQuantumMemory(svg_info->scale,
806 svg_info->n+1UL,sizeof(*svg_info->scale));
807 if (svg_info->scale == (double *) NULL)
809 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
810 ResourceLimitError,"MemoryAllocationFailed","`%s'",name);
813 svg_info->scale[svg_info->n]=svg_info->scale[svg_info->n-1];
814 color=AcquireString("none");
815 units=AcquireString("userSpaceOnUse");
816 value=(const char *) NULL;
817 if (attributes != (const xmlChar **) NULL)
818 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
820 keyword=(const char *) attributes[i];
821 value=(const char *) attributes[i+1];
827 if (LocaleCompare(keyword,"cx") == 0)
829 svg_info->element.cx=
830 GetUserSpaceCoordinateValue(svg_info,1,value);
833 if (LocaleCompare(keyword,"cy") == 0)
835 svg_info->element.cy=
836 GetUserSpaceCoordinateValue(svg_info,-1,value);
844 if (LocaleCompare(keyword,"fx") == 0)
846 svg_info->element.major=
847 GetUserSpaceCoordinateValue(svg_info,1,value);
850 if (LocaleCompare(keyword,"fy") == 0)
852 svg_info->element.minor=
853 GetUserSpaceCoordinateValue(svg_info,-1,value);
861 if (LocaleCompare(keyword,"height") == 0)
863 svg_info->bounds.height=
864 GetUserSpaceCoordinateValue(svg_info,-1,value);
872 if (LocaleCompare(keyword,"id") == 0)
874 (void) CopyMagickString(id,value,MagickPathExtent);
882 if (LocaleCompare(keyword,"r") == 0)
884 svg_info->element.angle=
885 GetUserSpaceCoordinateValue(svg_info,0,value);
893 if (LocaleCompare(keyword,"width") == 0)
895 svg_info->bounds.width=
896 GetUserSpaceCoordinateValue(svg_info,1,value);
904 if (LocaleCompare(keyword,"x") == 0)
906 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value)-
910 if (LocaleCompare(keyword,"x1") == 0)
912 svg_info->segment.x1=GetUserSpaceCoordinateValue(svg_info,1,
916 if (LocaleCompare(keyword,"x2") == 0)
918 svg_info->segment.x2=GetUserSpaceCoordinateValue(svg_info,1,
927 if (LocaleCompare(keyword,"y") == 0)
929 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value)-
933 if (LocaleCompare(keyword,"y1") == 0)
935 svg_info->segment.y1=
936 GetUserSpaceCoordinateValue(svg_info,-1,value);
939 if (LocaleCompare(keyword,"y2") == 0)
941 svg_info->segment.y2=
942 GetUserSpaceCoordinateValue(svg_info,-1,value);
951 if (strchr((char *) name,':') != (char *) NULL)
956 for ( ; *name != ':'; name++) ;
964 if (LocaleCompare((const char *) name,"circle") == 0)
966 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
969 if (LocaleCompare((const char *) name,"clipPath") == 0)
971 (void) FormatLocaleFile(svg_info->file,"push clip-path '%s'\n",id);
979 if (LocaleCompare((const char *) name,"defs") == 0)
981 (void) FormatLocaleFile(svg_info->file,"push defs\n");
989 if (LocaleCompare((const char *) name,"ellipse") == 0)
991 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
999 if (LocaleCompare((const char *) name,"g") == 0)
1001 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1009 if (LocaleCompare((const char *) name,"image") == 0)
1011 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1019 if (LocaleCompare((const char *) name,"line") == 0)
1021 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1024 if (LocaleCompare((const char *) name,"linearGradient") == 0)
1026 (void) FormatLocaleFile(svg_info->file,
1027 "push gradient '%s' linear %g,%g %g,%g\n",id,
1028 svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
1029 svg_info->segment.y2);
1037 if (LocaleCompare((const char *) name,"path") == 0)
1039 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1042 if (LocaleCompare((const char *) name,"pattern") == 0)
1044 (void) FormatLocaleFile(svg_info->file,
1045 "push pattern '%s' %g,%g %g,%g\n",id,
1046 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.width,
1047 svg_info->bounds.height);
1050 if (LocaleCompare((const char *) name,"polygon") == 0)
1052 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1055 if (LocaleCompare((const char *) name,"polyline") == 0)
1057 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1065 if (LocaleCompare((const char *) name,"radialGradient") == 0)
1067 (void) FormatLocaleFile(svg_info->file,
1068 "push gradient '%s' radial %g,%g %g,%g %g\n",
1069 id,svg_info->element.cx,svg_info->element.cy,
1070 svg_info->element.major,svg_info->element.minor,
1071 svg_info->element.angle);
1074 if (LocaleCompare((const char *) name,"rect") == 0)
1076 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1084 if (LocaleCompare((const char *) name,"svg") == 0)
1086 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1094 if (LocaleCompare((const char *) name,"text") == 0)
1096 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1097 svg_info->bounds.x=0.0;
1098 svg_info->bounds.y=0.0;
1099 svg_info->bounds.width=0.0;
1100 svg_info->bounds.height=0.0;
1103 if (LocaleCompare((const char *) name,"tspan") == 0)
1105 if (*svg_info->text != '\0')
1116 text=EscapeString(svg_info->text,'\'');
1117 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
1118 svg_info->bounds.x-svg_info->center.x,svg_info->bounds.y-
1119 svg_info->center.y,text);
1120 text=DestroyString(text);
1121 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
1122 draw_info->pointsize=svg_info->pointsize;
1123 draw_info->text=AcquireString(svg_info->text);
1124 (void) ConcatenateString(&draw_info->text," ");
1125 (void) GetTypeMetrics(svg_info->image,draw_info,
1126 &metrics,svg_info->exception);
1127 svg_info->bounds.x+=metrics.width;
1128 draw_info=DestroyDrawInfo(draw_info);
1129 *svg_info->text='\0';
1131 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1139 if (attributes != (const xmlChar **) NULL)
1140 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
1142 keyword=(const char *) attributes[i];
1143 value=(const char *) attributes[i+1];
1144 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1145 " %s = %s",keyword,value);
1151 if (LocaleCompare(keyword,"angle") == 0)
1153 (void) FormatLocaleFile(svg_info->file,"angle %g\n",
1154 GetUserSpaceCoordinateValue(svg_info,0,value));
1162 if (LocaleCompare(keyword,"clip-path") == 0)
1164 (void) FormatLocaleFile(svg_info->file,"clip-path '%s'\n",value);
1167 if (LocaleCompare(keyword,"clip-rule") == 0)
1169 (void) FormatLocaleFile(svg_info->file,"clip-rule '%s'\n",value);
1172 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1174 (void) CloneString(&units,value);
1175 (void) FormatLocaleFile(svg_info->file,"clip-units '%s'\n",value);
1178 if (LocaleCompare(keyword,"color") == 0)
1180 (void) CloneString(&color,value);
1183 if (LocaleCompare(keyword,"cx") == 0)
1185 svg_info->element.cx=
1186 GetUserSpaceCoordinateValue(svg_info,1,value);
1189 if (LocaleCompare(keyword,"cy") == 0)
1191 svg_info->element.cy=
1192 GetUserSpaceCoordinateValue(svg_info,-1,value);
1200 if (LocaleCompare(keyword,"d") == 0)
1202 (void) CloneString(&svg_info->vertices,value);
1205 if (LocaleCompare(keyword,"dx") == 0)
1207 svg_info->bounds.x+=GetUserSpaceCoordinateValue(svg_info,1,value);
1210 if (LocaleCompare(keyword,"dy") == 0)
1212 svg_info->bounds.y+=
1213 GetUserSpaceCoordinateValue(svg_info,-1,value);
1221 if (LocaleCompare(keyword,"fill") == 0)
1223 if (LocaleCompare(value,"currentColor") == 0)
1225 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",color);
1228 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",value);
1231 if (LocaleCompare(keyword,"fillcolor") == 0)
1233 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",value);
1236 if (LocaleCompare(keyword,"fill-rule") == 0)
1238 (void) FormatLocaleFile(svg_info->file,"fill-rule '%s'\n",value);
1241 if (LocaleCompare(keyword,"fill-alpha") == 0)
1243 (void) FormatLocaleFile(svg_info->file,"fill-alpha '%s'\n",
1247 if (LocaleCompare(keyword,"font-family") == 0)
1249 (void) FormatLocaleFile(svg_info->file,"font-family '%s'\n",
1253 if (LocaleCompare(keyword,"font-stretch") == 0)
1255 (void) FormatLocaleFile(svg_info->file,"font-stretch '%s'\n",
1259 if (LocaleCompare(keyword,"font-style") == 0)
1261 (void) FormatLocaleFile(svg_info->file,"font-style '%s'\n",value);
1264 if (LocaleCompare(keyword,"font-size") == 0)
1266 svg_info->pointsize=GetUserSpaceCoordinateValue(svg_info,0,value);
1267 (void) FormatLocaleFile(svg_info->file,"font-size %g\n",
1268 svg_info->pointsize);
1271 if (LocaleCompare(keyword,"font-weight") == 0)
1273 (void) FormatLocaleFile(svg_info->file,"font-weight '%s'\n",
1282 if (LocaleCompare(keyword,"gradientTransform") == 0)
1289 GetAffineMatrix(&transform);
1290 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1291 tokens=GetTransformTokens(context,value,&number_tokens);
1292 for (j=0; j < (number_tokens-1); j+=2)
1294 keyword=(char *) tokens[j];
1295 if (keyword == (char *) NULL)
1297 value=(char *) tokens[j+1];
1298 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1299 " %s: %s",keyword,value);
1301 GetAffineMatrix(&affine);
1307 if (LocaleCompare(keyword,"matrix") == 0)
1309 p=(const char *) value;
1310 GetMagickToken(p,&p,token);
1311 affine.sx=StringToDouble(value,(char **) NULL);
1312 GetMagickToken(p,&p,token);
1314 GetMagickToken(p,&p,token);
1315 affine.rx=StringToDouble(token,(char **) NULL);
1316 GetMagickToken(p,&p,token);
1318 GetMagickToken(p,&p,token);
1319 affine.ry=StringToDouble(token,(char **) NULL);
1320 GetMagickToken(p,&p,token);
1322 GetMagickToken(p,&p,token);
1323 affine.sy=StringToDouble(token,(char **) NULL);
1324 GetMagickToken(p,&p,token);
1326 GetMagickToken(p,&p,token);
1327 affine.tx=StringToDouble(token,(char **) NULL);
1328 GetMagickToken(p,&p,token);
1330 GetMagickToken(p,&p,token);
1331 affine.ty=StringToDouble(token,(char **) NULL);
1339 if (LocaleCompare(keyword,"rotate") == 0)
1344 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1345 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1346 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1347 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1348 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1356 if (LocaleCompare(keyword,"scale") == 0)
1358 for (p=(const char *) value; *p != '\0'; p++)
1359 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1362 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1363 affine.sy=affine.sx;
1366 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1367 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
1370 if (LocaleCompare(keyword,"skewX") == 0)
1372 affine.sx=svg_info->affine.sx;
1373 affine.ry=tan(DegreesToRadians(fmod(
1374 GetUserSpaceCoordinateValue(svg_info,1,value),
1376 affine.sy=svg_info->affine.sy;
1379 if (LocaleCompare(keyword,"skewY") == 0)
1381 affine.sx=svg_info->affine.sx;
1382 affine.rx=tan(DegreesToRadians(fmod(
1383 GetUserSpaceCoordinateValue(svg_info,-1,value),
1385 affine.sy=svg_info->affine.sy;
1393 if (LocaleCompare(keyword,"translate") == 0)
1395 for (p=(const char *) value; *p != '\0'; p++)
1396 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1399 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
1400 affine.ty=affine.tx;
1403 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1411 transform.sx=affine.sx*current.sx+affine.ry*current.rx;
1412 transform.rx=affine.rx*current.sx+affine.sy*current.rx;
1413 transform.ry=affine.sx*current.ry+affine.ry*current.sy;
1414 transform.sy=affine.rx*current.ry+affine.sy*current.sy;
1415 transform.tx=affine.tx*current.sx+affine.ty*current.ry+
1417 transform.ty=affine.tx*current.rx+affine.ty*current.sy+
1420 (void) FormatLocaleFile(svg_info->file,
1421 "affine %g %g %g %g %g %g\n",transform.sx,
1422 transform.rx,transform.ry,transform.sy,transform.tx,
1424 for (j=0; tokens[j] != (char *) NULL; j++)
1425 tokens[j]=DestroyString(tokens[j]);
1426 tokens=(char **) RelinquishMagickMemory(tokens);
1429 if (LocaleCompare(keyword,"gradientUnits") == 0)
1431 (void) CloneString(&units,value);
1432 (void) FormatLocaleFile(svg_info->file,"gradient-units '%s'\n",
1441 if (LocaleCompare(keyword,"height") == 0)
1443 svg_info->bounds.height=
1444 GetUserSpaceCoordinateValue(svg_info,-1,value);
1447 if (LocaleCompare(keyword,"href") == 0)
1449 (void) CloneString(&svg_info->url,value);
1457 if (LocaleCompare(keyword,"major") == 0)
1459 svg_info->element.major=
1460 GetUserSpaceCoordinateValue(svg_info,1,value);
1463 if (LocaleCompare(keyword,"minor") == 0)
1465 svg_info->element.minor=
1466 GetUserSpaceCoordinateValue(svg_info,-1,value);
1474 if (LocaleCompare(keyword,"offset") == 0)
1476 (void) CloneString(&svg_info->offset,value);
1479 if (LocaleCompare(keyword,"opacity") == 0)
1481 (void) FormatLocaleFile(svg_info->file,"opacity '%s'\n",value);
1489 if (LocaleCompare(keyword,"path") == 0)
1491 (void) CloneString(&svg_info->url,value);
1494 if (LocaleCompare(keyword,"points") == 0)
1496 (void) CloneString(&svg_info->vertices,value);
1504 if (LocaleCompare(keyword,"r") == 0)
1506 svg_info->element.major=
1507 GetUserSpaceCoordinateValue(svg_info,1,value);
1508 svg_info->element.minor=
1509 GetUserSpaceCoordinateValue(svg_info,-1,value);
1512 if (LocaleCompare(keyword,"rotate") == 0)
1517 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1518 (void) FormatLocaleFile(svg_info->file,"translate %g,%g\n",
1519 svg_info->bounds.x,svg_info->bounds.y);
1520 svg_info->bounds.x=0;
1521 svg_info->bounds.y=0;
1522 (void) FormatLocaleFile(svg_info->file,"rotate %g\n",angle);
1525 if (LocaleCompare(keyword,"rx") == 0)
1527 if (LocaleCompare((const char *) name,"ellipse") == 0)
1528 svg_info->element.major=
1529 GetUserSpaceCoordinateValue(svg_info,1,value);
1532 GetUserSpaceCoordinateValue(svg_info,1,value);
1535 if (LocaleCompare(keyword,"ry") == 0)
1537 if (LocaleCompare((const char *) name,"ellipse") == 0)
1538 svg_info->element.minor=
1539 GetUserSpaceCoordinateValue(svg_info,-1,value);
1542 GetUserSpaceCoordinateValue(svg_info,-1,value);
1550 if (LocaleCompare(keyword,"stop-color") == 0)
1552 (void) CloneString(&svg_info->stop_color,value);
1555 if (LocaleCompare(keyword,"stroke") == 0)
1557 if (LocaleCompare(value,"currentColor") == 0)
1559 (void) FormatLocaleFile(svg_info->file,"stroke '%s'\n",color);
1562 (void) FormatLocaleFile(svg_info->file,"stroke '%s'\n",value);
1565 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1567 (void) FormatLocaleFile(svg_info->file,"stroke-antialias %d\n",
1568 LocaleCompare(value,"true") == 0);
1571 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1573 (void) FormatLocaleFile(svg_info->file,"stroke-dasharray %s\n",
1577 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1579 (void) FormatLocaleFile(svg_info->file,"stroke-dashoffset %s\n",
1583 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1585 (void) FormatLocaleFile(svg_info->file,"stroke-linecap '%s'\n",
1589 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1591 (void) FormatLocaleFile(svg_info->file,"stroke-linejoin '%s'\n",
1595 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1597 (void) FormatLocaleFile(svg_info->file,"stroke-miterlimit '%s'\n",
1601 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1603 (void) FormatLocaleFile(svg_info->file,"stroke-opacity '%s'\n",
1607 if (LocaleCompare(keyword,"stroke-width") == 0)
1609 (void) FormatLocaleFile(svg_info->file,"stroke-width %g\n",
1610 GetUserSpaceCoordinateValue(svg_info,1,value));
1613 if (LocaleCompare(keyword,"style") == 0)
1615 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1616 tokens=GetStyleTokens(context,value,&number_tokens);
1617 for (j=0; j < (number_tokens-1); j+=2)
1619 keyword=(char *) tokens[j];
1620 value=(char *) tokens[j+1];
1621 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1622 " %s: %s",keyword,value);
1628 if (LocaleCompare(keyword,"clip-path") == 0)
1630 (void) FormatLocaleFile(svg_info->file,
1631 "clip-path '%s'\n",value);
1634 if (LocaleCompare(keyword,"clip-rule") == 0)
1636 (void) FormatLocaleFile(svg_info->file,
1637 "clip-rule '%s'\n",value);
1640 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1642 (void) CloneString(&units,value);
1643 (void) FormatLocaleFile(svg_info->file,
1644 "clip-units '%s'\n",value);
1647 if (LocaleCompare(keyword,"color") == 0)
1649 (void) CloneString(&color,value);
1657 if (LocaleCompare(keyword,"fill") == 0)
1659 if (LocaleCompare(value,"currentColor") == 0)
1661 (void) FormatLocaleFile(svg_info->file,
1662 "fill '%s'\n",color);
1665 if (LocaleCompare(value,"#000000ff") == 0)
1666 (void) FormatLocaleFile(svg_info->file,
1667 "fill '#000000'\n");
1669 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",
1673 if (LocaleCompare(keyword,"fillcolor") == 0)
1675 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",
1679 if (LocaleCompare(keyword,"fill-rule") == 0)
1681 (void) FormatLocaleFile(svg_info->file,
1682 "fill-rule '%s'\n",value);
1685 if (LocaleCompare(keyword,"fill-alpha") == 0)
1687 (void) FormatLocaleFile(svg_info->file,
1688 "fill-alpha '%s'\n",value);
1691 if (LocaleCompare(keyword,"font-family") == 0)
1693 (void) FormatLocaleFile(svg_info->file,
1694 "font-family '%s'\n",value);
1697 if (LocaleCompare(keyword,"font-stretch") == 0)
1699 (void) FormatLocaleFile(svg_info->file,
1700 "font-stretch '%s'\n",value);
1703 if (LocaleCompare(keyword,"font-style") == 0)
1705 (void) FormatLocaleFile(svg_info->file,
1706 "font-style '%s'\n",value);
1709 if (LocaleCompare(keyword,"font-size") == 0)
1711 svg_info->pointsize=GetUserSpaceCoordinateValue(
1713 (void) FormatLocaleFile(svg_info->file,"font-size %g\n",
1714 svg_info->pointsize);
1717 if (LocaleCompare(keyword,"font-weight") == 0)
1719 (void) FormatLocaleFile(svg_info->file,
1720 "font-weight '%s'\n",value);
1728 if (LocaleCompare(keyword,"offset") == 0)
1730 (void) FormatLocaleFile(svg_info->file,"offset %g\n",
1731 GetUserSpaceCoordinateValue(svg_info,1,value));
1734 if (LocaleCompare(keyword,"opacity") == 0)
1736 (void) FormatLocaleFile(svg_info->file,
1737 "opacity '%s'\n",value);
1745 if (LocaleCompare(keyword,"stop-color") == 0)
1747 (void) CloneString(&svg_info->stop_color,value);
1750 if (LocaleCompare(keyword,"stroke") == 0)
1752 if (LocaleCompare(value,"currentColor") == 0)
1754 (void) FormatLocaleFile(svg_info->file,
1755 "stroke '%s'\n",color);
1758 if (LocaleCompare(value,"#000000ff") == 0)
1759 (void) FormatLocaleFile(svg_info->file,
1760 "fill '#000000'\n");
1762 (void) FormatLocaleFile(svg_info->file,
1763 "stroke '%s'\n",value);
1766 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1768 (void) FormatLocaleFile(svg_info->file,
1769 "stroke-antialias %d\n",
1770 LocaleCompare(value,"true") == 0);
1773 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1775 (void) FormatLocaleFile(svg_info->file,
1776 "stroke-dasharray %s\n",value);
1779 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1781 (void) FormatLocaleFile(svg_info->file,
1782 "stroke-dashoffset %s\n",
1786 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1788 (void) FormatLocaleFile(svg_info->file,
1789 "stroke-linecap '%s'\n",value);
1792 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1794 (void) FormatLocaleFile(svg_info->file,
1795 "stroke-linejoin '%s'\n",
1799 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1801 (void) FormatLocaleFile(svg_info->file,
1802 "stroke-miterlimit '%s'\n",
1806 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1808 (void) FormatLocaleFile(svg_info->file,
1809 "stroke-opacity '%s'\n",value);
1812 if (LocaleCompare(keyword,"stroke-width") == 0)
1814 (void) FormatLocaleFile(svg_info->file,
1815 "stroke-width %g\n",
1816 GetUserSpaceCoordinateValue(svg_info,1,value));
1824 if (LocaleCompare(keyword,"text-align") == 0)
1826 (void) FormatLocaleFile(svg_info->file,
1827 "text-align '%s'\n",value);
1830 if (LocaleCompare(keyword,"text-anchor") == 0)
1832 (void) FormatLocaleFile(svg_info->file,
1833 "text-anchor '%s'\n",value);
1836 if (LocaleCompare(keyword,"text-decoration") == 0)
1838 if (LocaleCompare(value,"underline") == 0)
1839 (void) FormatLocaleFile(svg_info->file,
1840 "decorate underline\n");
1841 if (LocaleCompare(value,"line-through") == 0)
1842 (void) FormatLocaleFile(svg_info->file,
1843 "decorate line-through\n");
1844 if (LocaleCompare(value,"overline") == 0)
1845 (void) FormatLocaleFile(svg_info->file,
1846 "decorate overline\n");
1849 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1851 (void) FormatLocaleFile(svg_info->file,
1852 "text-antialias %d\n",
1853 LocaleCompare(value,"true") == 0);
1862 for (j=0; tokens[j] != (char *) NULL; j++)
1863 tokens[j]=DestroyString(tokens[j]);
1864 tokens=(char **) RelinquishMagickMemory(tokens);
1872 if (LocaleCompare(keyword,"text-align") == 0)
1874 (void) FormatLocaleFile(svg_info->file,"text-align '%s'\n",
1878 if (LocaleCompare(keyword,"text-anchor") == 0)
1880 (void) FormatLocaleFile(svg_info->file,"text-anchor '%s'\n",
1884 if (LocaleCompare(keyword,"text-decoration") == 0)
1886 if (LocaleCompare(value,"underline") == 0)
1887 (void) FormatLocaleFile(svg_info->file,"decorate underline\n");
1888 if (LocaleCompare(value,"line-through") == 0)
1889 (void) FormatLocaleFile(svg_info->file,
1890 "decorate line-through\n");
1891 if (LocaleCompare(value,"overline") == 0)
1892 (void) FormatLocaleFile(svg_info->file,"decorate overline\n");
1895 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1897 (void) FormatLocaleFile(svg_info->file,"text-antialias %d\n",
1898 LocaleCompare(value,"true") == 0);
1901 if (LocaleCompare(keyword,"transform") == 0)
1908 GetAffineMatrix(&transform);
1909 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1910 tokens=GetTransformTokens(context,value,&number_tokens);
1911 for (j=0; j < (number_tokens-1); j+=2)
1913 keyword=(char *) tokens[j];
1914 value=(char *) tokens[j+1];
1915 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1916 " %s: %s",keyword,value);
1918 GetAffineMatrix(&affine);
1924 if (LocaleCompare(keyword,"matrix") == 0)
1926 p=(const char *) value;
1927 GetMagickToken(p,&p,token);
1928 affine.sx=StringToDouble(value,(char **) NULL);
1929 GetMagickToken(p,&p,token);
1931 GetMagickToken(p,&p,token);
1932 affine.rx=StringToDouble(token,(char **) NULL);
1933 GetMagickToken(p,&p,token);
1935 GetMagickToken(p,&p,token);
1936 affine.ry=StringToDouble(token,(char **) NULL);
1937 GetMagickToken(p,&p,token);
1939 GetMagickToken(p,&p,token);
1940 affine.sy=StringToDouble(token,(char **) NULL);
1941 GetMagickToken(p,&p,token);
1943 GetMagickToken(p,&p,token);
1944 affine.tx=StringToDouble(token,(char **) NULL);
1945 GetMagickToken(p,&p,token);
1947 GetMagickToken(p,&p,token);
1948 affine.ty=StringToDouble(token,(char **) NULL);
1956 if (LocaleCompare(keyword,"rotate") == 0)
1963 p=(const char *) value;
1964 GetMagickToken(p,&p,token);
1965 angle=StringToDouble(value,(char **) NULL);
1966 GetMagickToken(p,&p,token);
1968 GetMagickToken(p,&p,token);
1969 x=StringToDouble(token,(char **) NULL);
1970 GetMagickToken(p,&p,token);
1972 GetMagickToken(p,&p,token);
1973 y=StringToDouble(token,(char **) NULL);
1974 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1975 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1976 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1977 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1980 svg_info->center.x=x;
1981 svg_info->center.y=y;
1989 if (LocaleCompare(keyword,"scale") == 0)
1991 for (p=(const char *) value; *p != '\0'; p++)
1992 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1995 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1996 affine.sy=affine.sx;
1998 affine.sy=GetUserSpaceCoordinateValue(svg_info,-1,
2000 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
2003 if (LocaleCompare(keyword,"skewX") == 0)
2005 affine.sx=svg_info->affine.sx;
2006 affine.ry=tan(DegreesToRadians(fmod(
2007 GetUserSpaceCoordinateValue(svg_info,1,value),
2009 affine.sy=svg_info->affine.sy;
2012 if (LocaleCompare(keyword,"skewY") == 0)
2014 affine.sx=svg_info->affine.sx;
2015 affine.rx=tan(DegreesToRadians(fmod(
2016 GetUserSpaceCoordinateValue(svg_info,-1,value),
2018 affine.sy=svg_info->affine.sy;
2026 if (LocaleCompare(keyword,"translate") == 0)
2028 for (p=(const char *) value; *p != '\0'; p++)
2029 if ((isspace((int) ((unsigned char) *p)) != 0) ||
2032 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
2033 affine.ty=affine.tx;
2035 affine.ty=GetUserSpaceCoordinateValue(svg_info,-1,
2044 transform.sx=affine.sx*current.sx+affine.ry*current.rx;
2045 transform.rx=affine.rx*current.sx+affine.sy*current.rx;
2046 transform.ry=affine.sx*current.ry+affine.ry*current.sy;
2047 transform.sy=affine.rx*current.ry+affine.sy*current.sy;
2048 transform.tx=affine.tx*current.sx+affine.ty*current.ry+
2050 transform.ty=affine.tx*current.rx+affine.ty*current.sy+
2053 (void) FormatLocaleFile(svg_info->file,
2054 "affine %g %g %g %g %g %g\n",transform.sx,transform.rx,
2055 transform.ry,transform.sy,transform.tx,transform.ty);
2056 for (j=0; tokens[j] != (char *) NULL; j++)
2057 tokens[j]=DestroyString(tokens[j]);
2058 tokens=(char **) RelinquishMagickMemory(tokens);
2066 if (LocaleCompare(keyword,"verts") == 0)
2068 (void) CloneString(&svg_info->vertices,value);
2071 if (LocaleCompare(keyword,"viewBox") == 0)
2073 p=(const char *) value;
2074 GetMagickToken(p,&p,token);
2075 svg_info->view_box.x=StringToDouble(token,(char **) NULL);
2076 GetMagickToken(p,&p,token);
2078 GetMagickToken(p,&p,token);
2079 svg_info->view_box.y=StringToDouble(token,(char **) NULL);
2080 GetMagickToken(p,&p,token);
2082 GetMagickToken(p,&p,token);
2083 svg_info->view_box.width=StringToDouble(token,
2085 if (svg_info->bounds.width == 0)
2086 svg_info->bounds.width=svg_info->view_box.width;
2087 GetMagickToken(p,&p,token);
2089 GetMagickToken(p,&p,token);
2090 svg_info->view_box.height=StringToDouble(token,
2092 if (svg_info->bounds.height == 0)
2093 svg_info->bounds.height=svg_info->view_box.height;
2101 if (LocaleCompare(keyword,"width") == 0)
2103 svg_info->bounds.width=
2104 GetUserSpaceCoordinateValue(svg_info,1,value);
2112 if (LocaleCompare(keyword,"x") == 0)
2114 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value);
2117 if (LocaleCompare(keyword,"xlink:href") == 0)
2119 (void) CloneString(&svg_info->url,value);
2122 if (LocaleCompare(keyword,"x1") == 0)
2124 svg_info->segment.x1=
2125 GetUserSpaceCoordinateValue(svg_info,1,value);
2128 if (LocaleCompare(keyword,"x2") == 0)
2130 svg_info->segment.x2=
2131 GetUserSpaceCoordinateValue(svg_info,1,value);
2139 if (LocaleCompare(keyword,"y") == 0)
2141 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value);
2144 if (LocaleCompare(keyword,"y1") == 0)
2146 svg_info->segment.y1=
2147 GetUserSpaceCoordinateValue(svg_info,-1,value);
2150 if (LocaleCompare(keyword,"y2") == 0)
2152 svg_info->segment.y2=
2153 GetUserSpaceCoordinateValue(svg_info,-1,value);
2162 if (LocaleCompare((const char *) name,"svg") == 0)
2164 if (svg_info->document->encoding != (const xmlChar *) NULL)
2165 (void) FormatLocaleFile(svg_info->file,"encoding \"%s\"\n",
2166 (const char *) svg_info->document->encoding);
2167 if (attributes != (const xmlChar **) NULL)
2175 if ((svg_info->view_box.width == 0.0) ||
2176 (svg_info->view_box.height == 0.0))
2177 svg_info->view_box=svg_info->bounds;
2178 svg_info->width=(size_t) floor(svg_info->bounds.width+0.5);
2179 svg_info->height=(size_t) floor(svg_info->bounds.height+0.5);
2180 (void) FormatLocaleFile(svg_info->file,"viewbox 0 0 %.20g %.20g\n",
2181 (double) svg_info->width,(double) svg_info->height);
2182 sx=(double) svg_info->width/svg_info->view_box.width;
2183 sy=(double) svg_info->height/svg_info->view_box.height;
2184 tx=svg_info->view_box.x != 0.0 ? (double) -sx*svg_info->view_box.x :
2186 ty=svg_info->view_box.y != 0.0 ? (double) -sy*svg_info->view_box.y :
2188 (void) FormatLocaleFile(svg_info->file,"affine %g 0 0 %g %g %g\n",
2192 (void) LogMagickEvent(CoderEvent,GetMagickModule()," )");
2193 units=DestroyString(units);
2194 if (color != (char *) NULL)
2195 color=DestroyString(color);
2198 static void SVGEndElement(void *context,const xmlChar *name)
2204 Called when the end of an element has been detected.
2206 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2207 " SAX.endElement(%s)",name);
2208 svg_info=(SVGInfo *) context;
2209 if (strchr((char *) name,':') != (char *) NULL)
2212 Skip over namespace.
2214 for ( ; *name != ':'; name++) ;
2222 if (LocaleCompare((const char *) name,"circle") == 0)
2224 (void) FormatLocaleFile(svg_info->file,"circle %g,%g %g,%g\n",
2225 svg_info->element.cx,svg_info->element.cy,svg_info->element.cx,
2226 svg_info->element.cy+svg_info->element.minor);
2227 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2230 if (LocaleCompare((const char *) name,"clipPath") == 0)
2232 (void) FormatLocaleFile(svg_info->file,"pop clip-path\n");
2240 if (LocaleCompare((const char *) name,"defs") == 0)
2242 (void) FormatLocaleFile(svg_info->file,"pop defs\n");
2245 if (LocaleCompare((const char *) name,"desc") == 0)
2250 if (*svg_info->text == '\0')
2252 (void) fputc('#',svg_info->file);
2253 for (p=svg_info->text; *p != '\0'; p++)
2255 (void) fputc(*p,svg_info->file);
2257 (void) fputc('#',svg_info->file);
2259 (void) fputc('\n',svg_info->file);
2260 *svg_info->text='\0';
2268 if (LocaleCompare((const char *) name,"ellipse") == 0)
2273 angle=svg_info->element.angle;
2274 (void) FormatLocaleFile(svg_info->file,"ellipse %g,%g %g,%g 0,360\n",
2275 svg_info->element.cx,svg_info->element.cy,
2276 angle == 0.0 ? svg_info->element.major : svg_info->element.minor,
2277 angle == 0.0 ? svg_info->element.minor : svg_info->element.major);
2278 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2286 if (LocaleCompare((const char *) name,"g") == 0)
2288 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2296 if (LocaleCompare((const char *) name,"image") == 0)
2298 (void) FormatLocaleFile(svg_info->file,
2299 "image Over %g,%g %g,%g '%s'\n",svg_info->bounds.x,
2300 svg_info->bounds.y,svg_info->bounds.width,svg_info->bounds.height,
2302 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2310 if (LocaleCompare((const char *) name,"line") == 0)
2312 (void) FormatLocaleFile(svg_info->file,"line %g,%g %g,%g\n",
2313 svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
2314 svg_info->segment.y2);
2315 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2318 if (LocaleCompare((const char *) name,"linearGradient") == 0)
2320 (void) FormatLocaleFile(svg_info->file,"pop gradient\n");
2328 if (LocaleCompare((const char *) name,"pattern") == 0)
2330 (void) FormatLocaleFile(svg_info->file,"pop pattern\n");
2333 if (LocaleCompare((const char *) name,"path") == 0)
2335 (void) FormatLocaleFile(svg_info->file,"path '%s'\n",
2336 svg_info->vertices);
2337 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2340 if (LocaleCompare((const char *) name,"polygon") == 0)
2342 (void) FormatLocaleFile(svg_info->file,"polygon %s\n",
2343 svg_info->vertices);
2344 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2347 if (LocaleCompare((const char *) name,"polyline") == 0)
2349 (void) FormatLocaleFile(svg_info->file,"polyline %s\n",
2350 svg_info->vertices);
2351 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2359 if (LocaleCompare((const char *) name,"radialGradient") == 0)
2361 (void) FormatLocaleFile(svg_info->file,"pop gradient\n");
2364 if (LocaleCompare((const char *) name,"rect") == 0)
2366 if ((svg_info->radius.x == 0.0) && (svg_info->radius.y == 0.0))
2368 (void) FormatLocaleFile(svg_info->file,"rectangle %g,%g %g,%g\n",
2369 svg_info->bounds.x,svg_info->bounds.y,
2370 svg_info->bounds.x+svg_info->bounds.width,
2371 svg_info->bounds.y+svg_info->bounds.height);
2372 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2375 if (svg_info->radius.x == 0.0)
2376 svg_info->radius.x=svg_info->radius.y;
2377 if (svg_info->radius.y == 0.0)
2378 svg_info->radius.y=svg_info->radius.x;
2379 (void) FormatLocaleFile(svg_info->file,
2380 "roundRectangle %g,%g %g,%g %g,%g\n",
2381 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.x+
2382 svg_info->bounds.width,svg_info->bounds.y+svg_info->bounds.height,
2383 svg_info->radius.x,svg_info->radius.y);
2384 svg_info->radius.x=0.0;
2385 svg_info->radius.y=0.0;
2386 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2394 if (LocaleCompare((const char *) name,"stop") == 0)
2396 (void) FormatLocaleFile(svg_info->file,"stop-color '%s' %s\n",
2397 svg_info->stop_color,svg_info->offset);
2400 if (LocaleCompare((const char *) name,"svg") == 0)
2402 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2410 if (LocaleCompare((const char *) name,"text") == 0)
2412 if (*svg_info->text != '\0')
2417 text=EscapeString(svg_info->text,'\'');
2418 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
2419 svg_info->bounds.x,svg_info->bounds.y,text);
2420 text=DestroyString(text);
2421 *svg_info->text='\0';
2423 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2426 if (LocaleCompare((const char *) name,"tspan") == 0)
2428 if (*svg_info->text != '\0')
2439 text=EscapeString(svg_info->text,'\'');
2440 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
2441 svg_info->bounds.x,svg_info->bounds.y,text);
2442 text=DestroyString(text);
2443 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
2444 draw_info->pointsize=svg_info->pointsize;
2445 draw_info->text=AcquireString(svg_info->text);
2446 (void) ConcatenateString(&draw_info->text," ");
2447 (void) GetTypeMetrics(svg_info->image,draw_info,&metrics,
2448 svg_info->exception);
2449 svg_info->bounds.x+=metrics.width;
2450 draw_info=DestroyDrawInfo(draw_info);
2451 *svg_info->text='\0';
2453 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2456 if (LocaleCompare((const char *) name,"title") == 0)
2458 if (*svg_info->text == '\0')
2460 (void) CloneString(&svg_info->title,svg_info->text);
2461 *svg_info->text='\0';
2469 *svg_info->text='\0';
2470 (void) ResetMagickMemory(&svg_info->element,0,sizeof(svg_info->element));
2471 (void) ResetMagickMemory(&svg_info->segment,0,sizeof(svg_info->segment));
2475 static void SVGCharacters(void *context,const xmlChar *c,int length)
2490 Receiving some characters from the parser.
2492 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2493 " SAX.characters(%s,%.20g)",c,(double) length);
2494 svg_info=(SVGInfo *) context;
2495 text=(char *) AcquireQuantumMemory(length+1,sizeof(*text));
2496 if (text == (char *) NULL)
2499 for (i=0; i < (ssize_t) length; i++)
2503 if (svg_info->text == (char *) NULL)
2504 svg_info->text=text;
2507 (void) ConcatenateString(&svg_info->text,text);
2508 text=DestroyString(text);
2512 static void SVGReference(void *context,const xmlChar *name)
2521 Called when an entity reference is detected.
2523 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.reference(%s)",
2525 svg_info=(SVGInfo *) context;
2526 parser=svg_info->parser;
2527 if (parser == (xmlParserCtxtPtr) NULL)
2529 if (parser->node == (xmlNodePtr) NULL)
2532 (void) xmlAddChild(parser->node,xmlNewCharRef(svg_info->document,name));
2534 (void) xmlAddChild(parser->node,xmlNewReference(svg_info->document,name));
2537 static void SVGIgnorableWhitespace(void *context,const xmlChar *c,int length)
2543 Receiving some ignorable whitespaces from the parser.
2545 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2546 " SAX.ignorableWhitespace(%.30s, %d)",c,length);
2547 svg_info=(SVGInfo *) context;
2551 static void SVGProcessingInstructions(void *context,const xmlChar *target,
2552 const xmlChar *data)
2558 A processing instruction has been parsed.
2560 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2561 " SAX.processingInstruction(%s, %s)",target,data);
2562 svg_info=(SVGInfo *) context;
2566 static void SVGComment(void *context,const xmlChar *value)
2572 A comment has been parsed.
2574 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.comment(%s)",
2576 svg_info=(SVGInfo *) context;
2577 if (svg_info->comment != (char *) NULL)
2578 (void) ConcatenateString(&svg_info->comment,"\n");
2579 (void) ConcatenateString(&svg_info->comment,(const char *) value);
2582 static void SVGWarning(void *context,const char *format,...)
2586 reason[MagickPathExtent];
2595 Display and format a warning messages, gives file, line, position and
2598 va_start(operands,format);
2599 svg_info=(SVGInfo *) context;
2600 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.warning: ");
2601 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2602 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2603 (void) vsprintf(reason,format,operands);
2605 (void) vsnprintf(reason,MagickPathExtent,format,operands);
2607 message=GetExceptionMessage(errno);
2608 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
2609 DelegateWarning,reason,"`%s`",message);
2610 message=DestroyString(message);
2614 static void SVGError(void *context,const char *format,...)
2618 reason[MagickPathExtent];
2627 Display and format a error formats, gives file, line, position and
2630 va_start(operands,format);
2631 svg_info=(SVGInfo *) context;
2632 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.error: ");
2633 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2634 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2635 (void) vsprintf(reason,format,operands);
2637 (void) vsnprintf(reason,MagickPathExtent,format,operands);
2639 message=GetExceptionMessage(errno);
2640 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),CoderError,
2641 reason,"`%s`",message);
2642 message=DestroyString(message);
2646 static void SVGCDataBlock(void *context,const xmlChar *value,int length)
2658 Called when a pcdata block has been parsed.
2660 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.pcdata(%s, %d)",
2662 svg_info=(SVGInfo *) context;
2663 parser=svg_info->parser;
2664 child=xmlGetLastChild(parser->node);
2665 if ((child != (xmlNodePtr) NULL) && (child->type == XML_CDATA_SECTION_NODE))
2667 xmlTextConcat(child,value,length);
2670 (void) xmlAddChild(parser->node,xmlNewCDataBlock(parser->myDoc,value,length));
2673 static void SVGExternalSubset(void *context,const xmlChar *name,
2674 const xmlChar *external_id,const xmlChar *system_id)
2689 Does this document has an external subset?
2691 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2692 " SAX.externalSubset(%s, %s, %s)",name,
2693 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
2694 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
2695 svg_info=(SVGInfo *) context;
2696 parser=svg_info->parser;
2697 if (((external_id == NULL) && (system_id == NULL)) ||
2698 ((parser->validate == 0) || (parser->wellFormed == 0) ||
2699 (svg_info->document == 0)))
2701 input=SVGResolveEntity(context,external_id,system_id);
2704 (void) xmlNewDtd(svg_info->document,name,external_id,system_id);
2705 parser_context=(*parser);
2706 parser->inputTab=(xmlParserInputPtr *) xmlMalloc(5*sizeof(*parser->inputTab));
2707 if (parser->inputTab == (xmlParserInputPtr *) NULL)
2709 parser->errNo=XML_ERR_NO_MEMORY;
2710 parser->input=parser_context.input;
2711 parser->inputNr=parser_context.inputNr;
2712 parser->inputMax=parser_context.inputMax;
2713 parser->inputTab=parser_context.inputTab;
2719 xmlPushInput(parser,input);
2720 (void) xmlSwitchEncoding(parser,xmlDetectCharEncoding(parser->input->cur,4));
2721 if (input->filename == (char *) NULL)
2722 input->filename=(char *) xmlStrdup(system_id);
2725 input->base=parser->input->cur;
2726 input->cur=parser->input->cur;
2728 xmlParseExternalSubset(parser,external_id,system_id);
2729 while (parser->inputNr > 1)
2730 (void) xmlPopInput(parser);
2731 xmlFreeInputStream(parser->input);
2732 xmlFree(parser->inputTab);
2733 parser->input=parser_context.input;
2734 parser->inputNr=parser_context.inputNr;
2735 parser->inputMax=parser_context.inputMax;
2736 parser->inputTab=parser_context.inputTab;
2739 #if defined(__cplusplus) || defined(c_plusplus)
2744 Static declarations.
2747 SVGDensityGeometry[] = "90.0x90.0";
2750 static Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
2753 filename[MagickPathExtent];
2772 message[MagickPathExtent];
2783 assert(image_info != (const ImageInfo *) NULL);
2784 assert(image_info->signature == MagickCoreSignature);
2785 assert(exception != (ExceptionInfo *) NULL);
2786 if (image_info->debug != MagickFalse)
2787 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2788 image_info->filename);
2789 assert(exception->signature == MagickCoreSignature);
2790 image=AcquireImage(image_info,exception);
2791 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2792 if (status == MagickFalse)
2794 image=DestroyImageList(image);
2795 return((Image *) NULL);
2797 if ((image->resolution.x == 0.0) || (image->resolution.y == 0.0))
2805 flags=ParseGeometry(SVGDensityGeometry,&geometry_info);
2806 image->resolution.x=geometry_info.rho;
2807 image->resolution.y=geometry_info.sigma;
2808 if ((flags & SigmaValue) == 0)
2809 image->resolution.y=image->resolution.x;
2811 if (LocaleCompare(image_info->magick,"MSVG") != 0)
2816 delegate_info=GetDelegateInfo("svg:decode",(char *) NULL,exception);
2817 if (delegate_info != (const DelegateInfo *) NULL)
2820 background[MagickPathExtent],
2821 command[MagickPathExtent],
2823 input_filename[MagickPathExtent],
2824 opacity[MagickPathExtent],
2825 output_filename[MagickPathExtent],
2826 unique[MagickPathExtent];
2835 Our best hope of compliance with the SVG standard.
2837 status=AcquireUniqueSymbolicLink(image->filename,input_filename);
2838 (void) AcquireUniqueFilename(output_filename);
2839 (void) AcquireUniqueFilename(unique);
2840 density=AcquireString("");
2841 (void) FormatLocaleString(density,MagickPathExtent,"%.20g,%.20g",
2842 image->resolution.x,image->resolution.y);
2843 (void) FormatLocaleString(background,MagickPathExtent,
2844 "rgb(%.20g%%,%.20g%%,%.20g%%)",
2845 100.0*QuantumScale*image->background_color.red,
2846 100.0*QuantumScale*image->background_color.green,
2847 100.0*QuantumScale*image->background_color.blue);
2848 (void) FormatLocaleString(opacity,MagickPathExtent,"%.20g",
2849 QuantumScale*image->background_color.alpha);
2850 (void) FormatLocaleString(command,MagickPathExtent,GetDelegateCommands(
2851 delegate_info),input_filename,output_filename,density,background,
2853 density=DestroyString(density);
2854 status=ExternalDelegateCommand(MagickFalse,image_info->verbose,
2855 command,(char *) NULL,exception);
2856 (void) RelinquishUniqueFileResource(unique);
2857 (void) RelinquishUniqueFileResource(input_filename);
2858 if ((status == 0) && (stat(output_filename,&attributes) == 0) &&
2859 (attributes.st_size > 0))
2867 read_info=CloneImageInfo(image_info);
2868 (void) CopyMagickString(read_info->filename,output_filename,
2870 svg_image=ReadImage(read_info,exception);
2871 read_info=DestroyImageInfo(read_info);
2872 (void) RelinquishUniqueFileResource(output_filename);
2873 if (svg_image != (Image *) NULL)
2875 image=DestroyImage(image);
2879 (void) RelinquishUniqueFileResource(output_filename);
2882 #if defined(MAGICKCORE_RSVG_DELEGATE)
2883 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2893 register unsigned char
2906 register const guchar
2928 svg_handle=rsvg_handle_new();
2929 if (svg_handle == (RsvgHandle *) NULL)
2930 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2931 rsvg_handle_set_base_uri(svg_handle,image_info->filename);
2932 if ((image->resolution.x != 90.0) && (image->resolution.y != 90.0))
2933 rsvg_handle_set_dpi_x_y(svg_handle,image->resolution.x,
2934 image->resolution.y);
2935 while ((n=ReadBlob(image,MagickPathExtent,message)) != 0)
2937 error=(GError *) NULL;
2938 (void) rsvg_handle_write(svg_handle,message,n,&error);
2939 if (error != (GError *) NULL)
2940 g_error_free(error);
2942 error=(GError *) NULL;
2943 rsvg_handle_close(svg_handle,&error);
2944 if (error != (GError *) NULL)
2945 g_error_free(error);
2946 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2947 rsvg_handle_get_dimensions(svg_handle,&dimension_info);
2948 if ((image->columns != 0) || (image->rows != 0))
2950 image->resolution.x=90.0*image->columns/dimension_info.width;
2951 image->resolution.y=90.0*image->rows/dimension_info.height;
2952 if (image->resolution.x == 0)
2953 image->resolution.x=image->resolution.y;
2954 else if (image->resolution.y == 0)
2955 image->resolution.y=image->resolution.x;
2957 image->resolution.x=image->resolution.y=MagickMin(
2958 image->resolution.x,image->resolution.y);
2960 image->columns=image->resolution.x*dimension_info.width/90.0;
2961 image->rows=image->resolution.y*dimension_info.height/90.0;
2962 pixel_info=(MemoryInfo *) NULL;
2964 pixel_buffer=rsvg_handle_get_pixbuf(svg_handle);
2965 rsvg_handle_free(svg_handle);
2966 image->columns=gdk_pixbuf_get_width(pixel_buffer);
2967 image->rows=gdk_pixbuf_get_height(pixel_buffer);
2969 image->alpha_trait=BlendPixelTrait;
2970 SetImageProperty(image,"svg:base-uri",
2971 rsvg_handle_get_base_uri(svg_handle),exception);
2972 status=SetImageExtent(image,image->columns,image->rows,exception);
2973 if (status == MagickFalse)
2975 #if !defined(MAGICKCORE_CAIRO_DELEGATE)
2976 g_object_unref(G_OBJECT(pixel_buffer));
2978 g_object_unref(svg_handle);
2979 ThrowReaderException(MissingDelegateError,
2980 "NoDecodeDelegateForThisImageFormat");
2982 if (image_info->ping == MagickFalse)
2984 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2988 stride=4*image->columns;
2989 #if defined(MAGICKCORE_PANGOCAIRO_DELEGATE)
2990 stride=(size_t) cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32,
2991 (int) image->columns);
2993 pixel_info=AcquireVirtualMemory(stride,image->rows*sizeof(*pixels));
2994 if (pixel_info == (MemoryInfo *) NULL)
2996 g_object_unref(svg_handle);
2997 ThrowReaderException(ResourceLimitError,
2998 "MemoryAllocationFailed");
3000 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
3002 (void) SetImageBackgroundColor(image,exception);
3003 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3004 cairo_surface=cairo_image_surface_create_for_data(pixels,
3005 CAIRO_FORMAT_ARGB32,(int) image->columns,(int) image->rows,(int)
3007 if (cairo_surface == (cairo_surface_t *) NULL)
3009 pixel_info=RelinquishVirtualMemory(pixel_info);
3010 g_object_unref(svg_handle);
3011 ThrowReaderException(ResourceLimitError,
3012 "MemoryAllocationFailed");
3014 cairo_image=cairo_create(cairo_surface);
3015 cairo_set_operator(cairo_image,CAIRO_OPERATOR_CLEAR);
3016 cairo_paint(cairo_image);
3017 cairo_set_operator(cairo_image,CAIRO_OPERATOR_OVER);
3018 cairo_scale(cairo_image,image->resolution.x/90.0,
3019 image->resolution.y/90.0);
3020 rsvg_handle_render_cairo(svg_handle,cairo_image);
3021 cairo_destroy(cairo_image);
3022 cairo_surface_destroy(cairo_surface);
3023 g_object_unref(svg_handle);
3026 p=gdk_pixbuf_get_pixels(pixel_buffer);
3028 GetPixelInfo(image,&fill_color);
3029 for (y=0; y < (ssize_t) image->rows; y++)
3031 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3032 if (q == (Quantum *) NULL)
3034 for (x=0; x < (ssize_t) image->columns; x++)
3036 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3037 fill_color.blue=ScaleCharToQuantum(*p++);
3038 fill_color.green=ScaleCharToQuantum(*p++);
3039 fill_color.red=ScaleCharToQuantum(*p++);
3041 fill_color.red=ScaleCharToQuantum(*p++);
3042 fill_color.green=ScaleCharToQuantum(*p++);
3043 fill_color.blue=ScaleCharToQuantum(*p++);
3045 fill_color.alpha=ScaleCharToQuantum(*p++);
3046 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3051 gamma=QuantumScale*fill_color.alpha;
3052 gamma=PerceptibleReciprocal(gamma);
3053 fill_color.blue*=gamma;
3054 fill_color.green*=gamma;
3055 fill_color.red*=gamma;
3058 CompositePixelOver(image,&fill_color,fill_color.alpha,q,(double)
3059 GetPixelAlpha(image,q),q);
3060 q+=GetPixelChannels(image);
3062 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3064 if (image->previous == (Image *) NULL)
3066 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
3068 if (status == MagickFalse)
3073 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3074 if (pixel_info != (MemoryInfo *) NULL)
3075 pixel_info=RelinquishVirtualMemory(pixel_info);
3077 g_object_unref(G_OBJECT(pixel_buffer));
3079 (void) CloseBlob(image);
3080 return(GetFirstImageInList(image));
3088 unique_file=AcquireUniqueFileResource(filename);
3089 if (unique_file != -1)
3090 file=fdopen(unique_file,"w");
3091 if ((unique_file == -1) || (file == (FILE *) NULL))
3093 (void) CopyMagickString(image->filename,filename,MagickPathExtent);
3094 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
3096 image=DestroyImageList(image);
3097 return((Image *) NULL);
3102 svg_info=AcquireSVGInfo();
3103 if (svg_info == (SVGInfo *) NULL)
3105 (void) fclose(file);
3106 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3108 svg_info->file=file;
3109 svg_info->exception=exception;
3110 svg_info->image=image;
3111 svg_info->image_info=image_info;
3112 svg_info->bounds.width=image->columns;
3113 svg_info->bounds.height=image->rows;
3114 if (image_info->size != (char *) NULL)
3115 (void) CloneString(&svg_info->size,image_info->size);
3116 if (image->debug != MagickFalse)
3117 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"begin SAX");
3118 (void) xmlSubstituteEntitiesDefault(1);
3119 (void) ResetMagickMemory(&sax_modules,0,sizeof(sax_modules));
3120 sax_modules.internalSubset=SVGInternalSubset;
3121 sax_modules.isStandalone=SVGIsStandalone;
3122 sax_modules.hasInternalSubset=SVGHasInternalSubset;
3123 sax_modules.hasExternalSubset=SVGHasExternalSubset;
3124 sax_modules.resolveEntity=SVGResolveEntity;
3125 sax_modules.getEntity=SVGGetEntity;
3126 sax_modules.entityDecl=SVGEntityDeclaration;
3127 sax_modules.notationDecl=SVGNotationDeclaration;
3128 sax_modules.attributeDecl=SVGAttributeDeclaration;
3129 sax_modules.elementDecl=SVGElementDeclaration;
3130 sax_modules.unparsedEntityDecl=SVGUnparsedEntityDeclaration;
3131 sax_modules.setDocumentLocator=SVGSetDocumentLocator;
3132 sax_modules.startDocument=SVGStartDocument;
3133 sax_modules.endDocument=SVGEndDocument;
3134 sax_modules.startElement=SVGStartElement;
3135 sax_modules.endElement=SVGEndElement;
3136 sax_modules.reference=SVGReference;
3137 sax_modules.characters=SVGCharacters;
3138 sax_modules.ignorableWhitespace=SVGIgnorableWhitespace;
3139 sax_modules.processingInstruction=SVGProcessingInstructions;
3140 sax_modules.comment=SVGComment;
3141 sax_modules.warning=SVGWarning;
3142 sax_modules.error=SVGError;
3143 sax_modules.fatalError=SVGError;
3144 sax_modules.getParameterEntity=SVGGetParameterEntity;
3145 sax_modules.cdataBlock=SVGCDataBlock;
3146 sax_modules.externalSubset=SVGExternalSubset;
3147 sax_handler=(&sax_modules);
3148 n=ReadBlob(image,MagickPathExtent,message);
3151 svg_info->parser=xmlCreatePushParserCtxt(sax_handler,svg_info,(char *)
3152 message,n,image->filename);
3153 while ((n=ReadBlob(image,MagickPathExtent,message)) != 0)
3155 status=xmlParseChunk(svg_info->parser,(char *) message,(int) n,0);
3160 (void) xmlParseChunk(svg_info->parser,(char *) message,0,1);
3161 xmlFreeParserCtxt(svg_info->parser);
3162 if (image->debug != MagickFalse)
3163 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"end SAX");
3164 (void) fclose(file);
3165 (void) CloseBlob(image);
3166 image->columns=svg_info->width;
3167 image->rows=svg_info->height;
3168 if (exception->severity >= ErrorException)
3170 image=DestroyImage(image);
3171 return((Image *) NULL);
3173 if (image_info->ping == MagickFalse)
3181 image=DestroyImage(image);
3182 image=(Image *) NULL;
3183 read_info=CloneImageInfo(image_info);
3184 SetImageInfoBlob(read_info,(void *) NULL,0);
3185 if (read_info->density != (char *) NULL)
3186 read_info->density=DestroyString(read_info->density);
3187 (void) FormatLocaleString(read_info->filename,MagickPathExtent,"mvg:%s",
3189 image=ReadImage(read_info,exception);
3190 read_info=DestroyImageInfo(read_info);
3191 if (image != (Image *) NULL)
3192 (void) CopyMagickString(image->filename,image_info->filename,
3196 Relinquish resources.
3198 if (image != (Image *) NULL)
3200 if (svg_info->title != (char *) NULL)
3201 (void) SetImageProperty(image,"svg:title",svg_info->title,exception);
3202 if (svg_info->comment != (char *) NULL)
3203 (void) SetImageProperty(image,"svg:comment",svg_info->comment,
3206 svg_info=DestroySVGInfo(svg_info);
3207 (void) RelinquishUniqueFileResource(filename);
3208 return(GetFirstImageInList(image));
3213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3217 % R e g i s t e r S V G I m a g e %
3221 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3223 % RegisterSVGImage() adds attributes for the SVG image format to
3224 % the list of supported formats. The attributes include the image format
3225 % tag, a method to read and/or write the format, whether the format
3226 % supports the saving of more than one frame to the same file or blob,
3227 % whether the format supports native in-memory I/O, and a brief
3228 % description of the format.
3230 % The format of the RegisterSVGImage method is:
3232 % size_t RegisterSVGImage(void)
3235 ModuleExport size_t RegisterSVGImage(void)
3238 version[MagickPathExtent];
3244 #if defined(LIBXML_DOTTED_VERSION)
3245 (void) CopyMagickString(version,"XML " LIBXML_DOTTED_VERSION,MagickPathExtent);
3247 #if defined(MAGICKCORE_RSVG_DELEGATE)
3248 #if !GLIB_CHECK_VERSION(2,35,0)
3251 #if defined(MAGICKCORE_XML_DELEGATE)
3254 (void) FormatLocaleString(version,MagickPathExtent,"RSVG %d.%d.%d",
3255 LIBRSVG_MAJOR_VERSION,LIBRSVG_MINOR_VERSION,LIBRSVG_MICRO_VERSION);
3257 entry=AcquireMagickInfo("SVG","SVG","Scalable Vector Graphics");
3258 #if defined(MAGICKCORE_XML_DELEGATE)
3259 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3261 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3262 entry->flags^=CoderBlobSupportFlag;
3263 entry->mime_type=ConstantString("image/svg+xml");
3264 if (*version != '\0')
3265 entry->version=ConstantString(version);
3266 entry->magick=(IsImageFormatHandler *) IsSVG;
3267 (void) RegisterMagickInfo(entry);
3268 entry=AcquireMagickInfo("SVG","SVGZ","Compressed Scalable Vector Graphics");
3269 #if defined(MAGICKCORE_XML_DELEGATE)
3270 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3272 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3273 entry->flags^=CoderBlobSupportFlag;
3274 entry->mime_type=ConstantString("image/svg+xml");
3275 if (*version != '\0')
3276 entry->version=ConstantString(version);
3277 entry->magick=(IsImageFormatHandler *) IsSVG;
3278 (void) RegisterMagickInfo(entry);
3279 entry=AcquireMagickInfo("SVG","MSVG",
3280 "ImageMagick's own SVG internal renderer");
3281 #if defined(MAGICKCORE_XML_DELEGATE)
3282 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3284 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3285 entry->flags^=CoderBlobSupportFlag;
3286 entry->magick=(IsImageFormatHandler *) IsSVG;
3287 (void) RegisterMagickInfo(entry);
3288 return(MagickImageCoderSignature);
3292 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3296 % U n r e g i s t e r S V G I m a g e %
3300 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3302 % UnregisterSVGImage() removes format registrations made by the
3303 % SVG module from the list of supported formats.
3305 % The format of the UnregisterSVGImage method is:
3307 % UnregisterSVGImage(void)
3310 ModuleExport void UnregisterSVGImage(void)
3312 (void) UnregisterMagickInfo("SVGZ");
3313 (void) UnregisterMagickInfo("SVG");
3314 (void) UnregisterMagickInfo("MSVG");
3315 #if defined(MAGICKCORE_XML_DELEGATE)
3321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3325 % W r i t e S V G I m a g e %
3329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3331 % WriteSVGImage() writes a image in the SVG - XML based W3C standard
3334 % The format of the WriteSVGImage method is:
3336 % MagickBooleanType WriteSVGImage(const ImageInfo *image_info,
3337 % Image *image,ExceptionInfo *exception)
3339 % A description of each parameter follows.
3341 % o image_info: the image info.
3343 % o image: The image.
3345 % o exception: return any errors or warnings in this structure.
3349 static void AffineToTransform(Image *image,AffineMatrix *affine)
3352 transform[MagickPathExtent];
3354 if ((fabs(affine->tx) < MagickEpsilon) && (fabs(affine->ty) < MagickEpsilon))
3356 if ((fabs(affine->rx) < MagickEpsilon) &&
3357 (fabs(affine->ry) < MagickEpsilon))
3359 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3360 (fabs(affine->sy-1.0) < MagickEpsilon))
3362 (void) WriteBlobString(image,"\">\n");
3365 (void) FormatLocaleString(transform,MagickPathExtent,
3366 "\" transform=\"scale(%g,%g)\">\n",affine->sx,affine->sy);
3367 (void) WriteBlobString(image,transform);
3372 if ((fabs(affine->sx-affine->sy) < MagickEpsilon) &&
3373 (fabs(affine->rx+affine->ry) < MagickEpsilon) &&
3374 (fabs(affine->sx*affine->sx+affine->rx*affine->rx-1.0) <
3380 theta=(180.0/MagickPI)*atan2(affine->rx,affine->sx);
3381 (void) FormatLocaleString(transform,MagickPathExtent,
3382 "\" transform=\"rotate(%g)\">\n",theta);
3383 (void) WriteBlobString(image,transform);
3390 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3391 (fabs(affine->rx) < MagickEpsilon) &&
3392 (fabs(affine->ry) < MagickEpsilon) &&
3393 (fabs(affine->sy-1.0) < MagickEpsilon))
3395 (void) FormatLocaleString(transform,MagickPathExtent,
3396 "\" transform=\"translate(%g,%g)\">\n",affine->tx,affine->ty);
3397 (void) WriteBlobString(image,transform);
3401 (void) FormatLocaleString(transform,MagickPathExtent,
3402 "\" transform=\"matrix(%g %g %g %g %g %g)\">\n",
3403 affine->sx,affine->rx,affine->ry,affine->sy,affine->tx,affine->ty);
3404 (void) WriteBlobString(image,transform);
3407 static MagickBooleanType IsPoint(const char *point)
3415 value=strtol(point,&p,10);
3417 return(p != point ? MagickTrue : MagickFalse);
3420 static MagickBooleanType TraceSVGImage(Image *image,ExceptionInfo *exception)
3422 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
3427 at_fitting_opts_type
3439 register const PixelPacket
3453 Trace image and write as SVG.
3455 fitting_options=at_fitting_opts_new();
3456 output_options=at_output_opts_new();
3457 (void) SetImageGray(image,exception);
3458 type=GetImageType(image);
3460 if ((type == BilevelType) || (type == GrayscaleType))
3462 trace=at_bitmap_new(image->columns,image->rows,number_planes);
3464 for (y=0; y < (ssize_t) image->rows; y++)
3466 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3467 if (p == (const PixelPacket *) NULL)
3469 for (x=0; x < (ssize_t) image->columns; x++)
3471 trace->bitmap[i++]=GetPixelRed(image,p);
3472 if (number_planes == 3)
3474 trace->bitmap[i++]=GetPixelGreen(image,p);
3475 trace->bitmap[i++]=GetPixelBlue(image,p);
3477 p+=GetPixelChannels(image);
3480 splines=at_splines_new_full(trace,fitting_options,NULL,NULL,NULL,NULL,NULL,
3482 at_splines_write(at_output_get_handler_by_suffix((char *) "svg"),
3483 GetBlobFileHandle(image),image->filename,output_options,splines,NULL,
3488 at_splines_free(splines);
3489 at_bitmap_free(trace);
3490 at_output_opts_free(output_options);
3491 at_fitting_opts_free(fitting_options);
3497 message[MagickPathExtent];
3518 (void) WriteBlobString(image,
3519 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");
3520 (void) WriteBlobString(image,
3521 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"");
3522 (void) WriteBlobString(image,
3523 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
3524 (void) FormatLocaleString(message,MagickPathExtent,
3525 "<svg version=\"1.1\" id=\"Layer_1\" "
3526 "xmlns=\"http://www.w3.org/2000/svg\" "
3527 "xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\" "
3528 "width=\"%.20gpx\" height=\"%.20gpx\" viewBox=\"0 0 %.20g %.20g\" "
3529 "enable-background=\"new 0 0 %.20g %.20g\" xml:space=\"preserve\">",
3530 (double) image->columns,(double) image->rows,
3531 (double) image->columns,(double) image->rows,
3532 (double) image->columns,(double) image->rows);
3533 (void) WriteBlobString(image,message);
3534 clone_image=CloneImage(image,0,0,MagickTrue,exception);
3535 if (clone_image == (Image *) NULL)
3536 return(MagickFalse);
3537 image_info=AcquireImageInfo();
3538 (void) CopyMagickString(image_info->magick,"PNG",MagickPathExtent);
3540 blob=(unsigned char *) ImageToBlob(image_info,clone_image,&blob_length,
3542 clone_image=DestroyImage(clone_image);
3543 image_info=DestroyImageInfo(image_info);
3544 if (blob == (unsigned char *) NULL)
3545 return(MagickFalse);
3547 base64=Base64Encode(blob,blob_length,&encode_length);
3548 blob=(unsigned char *) RelinquishMagickMemory(blob);
3549 (void) FormatLocaleString(message,MagickPathExtent,
3550 " <image id=\"image%.20g\" width=\"%.20g\" height=\"%.20g\" "
3551 "x=\"%.20g\" y=\"%.20g\"\n xlink:href=\"data:image/png;base64,",
3552 (double) image->scene,(double) image->columns,(double) image->rows,
3553 (double) image->page.x,(double) image->page.y);
3554 (void) WriteBlobString(image,message);
3556 for (i=(ssize_t) encode_length; i > 0; i-=76)
3558 (void) FormatLocaleString(message,MagickPathExtent,"%.76s",p);
3559 (void) WriteBlobString(image,message);
3562 (void) WriteBlobString(image,"\n");
3564 base64=DestroyString(base64);
3565 (void) WriteBlobString(image,"\" />\n");
3566 (void) WriteBlobString(image,"</svg>\n");
3573 static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
3574 ExceptionInfo *exception)
3576 #define BezierQuantum 200
3582 keyword[MagickPathExtent],
3583 message[MagickPathExtent],
3584 name[MagickPathExtent],
3586 type[MagickPathExtent];
3628 Open output image file.
3630 assert(image_info != (const ImageInfo *) NULL);
3631 assert(image_info->signature == MagickCoreSignature);
3632 assert(image != (Image *) NULL);
3633 assert(image->signature == MagickCoreSignature);
3634 if (image->debug != MagickFalse)
3635 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3636 assert(exception != (ExceptionInfo *) NULL);
3637 assert(exception->signature == MagickCoreSignature);
3638 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
3639 if (status == MagickFalse)
3641 value=GetImageArtifact(image,"SVG");
3642 if (value != (char *) NULL)
3644 (void) WriteBlobString(image,value);
3645 (void) CloseBlob(image);
3648 value=GetImageArtifact(image,"MVG");
3649 if (value == (char *) NULL)
3650 return(TraceSVGImage(image,exception));
3654 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3655 (void) WriteBlobString(image,
3656 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3657 (void) WriteBlobString(image,
3658 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3659 (void) FormatLocaleString(message,MagickPathExtent,
3660 "<svg width=\"%.20g\" height=\"%.20g\">\n",(double) image->columns,(double)
3662 (void) WriteBlobString(image,message);
3664 Allocate primitive info memory.
3667 primitive_info=(PrimitiveInfo *) AcquireQuantumMemory(number_points,
3668 sizeof(*primitive_info));
3669 if (primitive_info == (PrimitiveInfo *) NULL)
3670 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3671 GetAffineMatrix(&affine);
3672 token=AcquireString(value);
3676 for (q=(const char *) value; *q != '\0'; )
3679 Interpret graphic primitive.
3681 GetMagickToken(q,&q,keyword);
3682 if (*keyword == '\0')
3684 if (*keyword == '#')
3689 if (active != MagickFalse)
3691 AffineToTransform(image,&affine);
3694 (void) WriteBlobString(image,"<desc>");
3695 (void) WriteBlobString(image,keyword+1);
3696 for ( ; (*q != '\n') && (*q != '\0'); q++)
3699 case '<': (void) WriteBlobString(image,"<"); break;
3700 case '>': (void) WriteBlobString(image,">"); break;
3701 case '&': (void) WriteBlobString(image,"&"); break;
3702 default: (void) WriteBlobByte(image,*q); break;
3704 (void) WriteBlobString(image,"</desc>\n");
3707 primitive_type=UndefinedPrimitive;
3715 if (LocaleCompare("affine",keyword) == 0)
3717 GetMagickToken(q,&q,token);
3718 affine.sx=StringToDouble(token,(char **) NULL);
3719 GetMagickToken(q,&q,token);
3721 GetMagickToken(q,&q,token);
3722 affine.rx=StringToDouble(token,(char **) NULL);
3723 GetMagickToken(q,&q,token);
3725 GetMagickToken(q,&q,token);
3726 affine.ry=StringToDouble(token,(char **) NULL);
3727 GetMagickToken(q,&q,token);
3729 GetMagickToken(q,&q,token);
3730 affine.sy=StringToDouble(token,(char **) NULL);
3731 GetMagickToken(q,&q,token);
3733 GetMagickToken(q,&q,token);
3734 affine.tx=StringToDouble(token,(char **) NULL);
3735 GetMagickToken(q,&q,token);
3737 GetMagickToken(q,&q,token);
3738 affine.ty=StringToDouble(token,(char **) NULL);
3741 if (LocaleCompare("alpha",keyword) == 0)
3743 primitive_type=AlphaPrimitive;
3746 if (LocaleCompare("angle",keyword) == 0)
3748 GetMagickToken(q,&q,token);
3749 affine.rx=StringToDouble(token,(char **) NULL);
3750 affine.ry=StringToDouble(token,(char **) NULL);
3753 if (LocaleCompare("arc",keyword) == 0)
3755 primitive_type=ArcPrimitive;
3764 if (LocaleCompare("bezier",keyword) == 0)
3766 primitive_type=BezierPrimitive;
3775 if (LocaleCompare("clip-path",keyword) == 0)
3777 GetMagickToken(q,&q,token);
3778 (void) FormatLocaleString(message,MagickPathExtent,
3779 "clip-path:url(#%s);",token);
3780 (void) WriteBlobString(image,message);
3783 if (LocaleCompare("clip-rule",keyword) == 0)
3785 GetMagickToken(q,&q,token);
3786 (void) FormatLocaleString(message,MagickPathExtent,
3787 "clip-rule:%s;",token);
3788 (void) WriteBlobString(image,message);
3791 if (LocaleCompare("clip-units",keyword) == 0)
3793 GetMagickToken(q,&q,token);
3794 (void) FormatLocaleString(message,MagickPathExtent,
3795 "clipPathUnits=%s;",token);
3796 (void) WriteBlobString(image,message);
3799 if (LocaleCompare("circle",keyword) == 0)
3801 primitive_type=CirclePrimitive;
3804 if (LocaleCompare("color",keyword) == 0)
3806 primitive_type=ColorPrimitive;
3815 if (LocaleCompare("decorate",keyword) == 0)
3817 GetMagickToken(q,&q,token);
3818 (void) FormatLocaleString(message,MagickPathExtent,
3819 "text-decoration:%s;",token);
3820 (void) WriteBlobString(image,message);
3829 if (LocaleCompare("ellipse",keyword) == 0)
3831 primitive_type=EllipsePrimitive;
3840 if (LocaleCompare("fill",keyword) == 0)
3842 GetMagickToken(q,&q,token);
3843 (void) FormatLocaleString(message,MagickPathExtent,"fill:%s;",
3845 (void) WriteBlobString(image,message);
3848 if (LocaleCompare("fill-rule",keyword) == 0)
3850 GetMagickToken(q,&q,token);
3851 (void) FormatLocaleString(message,MagickPathExtent,
3852 "fill-rule:%s;",token);
3853 (void) WriteBlobString(image,message);
3856 if (LocaleCompare("fill-alpha",keyword) == 0)
3858 GetMagickToken(q,&q,token);
3859 (void) FormatLocaleString(message,MagickPathExtent,
3860 "fill-alpha:%s;",token);
3861 (void) WriteBlobString(image,message);
3864 if (LocaleCompare("font-family",keyword) == 0)
3866 GetMagickToken(q,&q,token);
3867 (void) FormatLocaleString(message,MagickPathExtent,
3868 "font-family:%s;",token);
3869 (void) WriteBlobString(image,message);
3872 if (LocaleCompare("font-stretch",keyword) == 0)
3874 GetMagickToken(q,&q,token);
3875 (void) FormatLocaleString(message,MagickPathExtent,
3876 "font-stretch:%s;",token);
3877 (void) WriteBlobString(image,message);
3880 if (LocaleCompare("font-style",keyword) == 0)
3882 GetMagickToken(q,&q,token);
3883 (void) FormatLocaleString(message,MagickPathExtent,
3884 "font-style:%s;",token);
3885 (void) WriteBlobString(image,message);
3888 if (LocaleCompare("font-size",keyword) == 0)
3890 GetMagickToken(q,&q,token);
3891 (void) FormatLocaleString(message,MagickPathExtent,
3892 "font-size:%s;",token);
3893 (void) WriteBlobString(image,message);
3896 if (LocaleCompare("font-weight",keyword) == 0)
3898 GetMagickToken(q,&q,token);
3899 (void) FormatLocaleString(message,MagickPathExtent,
3900 "font-weight:%s;",token);
3901 (void) WriteBlobString(image,message);
3910 if (LocaleCompare("gradient-units",keyword) == 0)
3912 GetMagickToken(q,&q,token);
3915 if (LocaleCompare("text-align",keyword) == 0)
3917 GetMagickToken(q,&q,token);
3918 (void) FormatLocaleString(message,MagickPathExtent,
3919 "text-align %s ",token);
3920 (void) WriteBlobString(image,message);
3923 if (LocaleCompare("text-anchor",keyword) == 0)
3925 GetMagickToken(q,&q,token);
3926 (void) FormatLocaleString(message,MagickPathExtent,
3927 "text-anchor %s ",token);
3928 (void) WriteBlobString(image,message);
3937 if (LocaleCompare("image",keyword) == 0)
3939 GetMagickToken(q,&q,token);
3940 primitive_type=ImagePrimitive;
3949 if (LocaleCompare("line",keyword) == 0)
3951 primitive_type=LinePrimitive;
3960 if (LocaleCompare("opacity",keyword) == 0)
3962 GetMagickToken(q,&q,token);
3963 (void) FormatLocaleString(message,MagickPathExtent,"opacity %s ",
3965 (void) WriteBlobString(image,message);
3974 if (LocaleCompare("path",keyword) == 0)
3976 primitive_type=PathPrimitive;
3979 if (LocaleCompare("point",keyword) == 0)
3981 primitive_type=PointPrimitive;
3984 if (LocaleCompare("polyline",keyword) == 0)
3986 primitive_type=PolylinePrimitive;
3989 if (LocaleCompare("polygon",keyword) == 0)
3991 primitive_type=PolygonPrimitive;
3994 if (LocaleCompare("pop",keyword) == 0)
3996 GetMagickToken(q,&q,token);
3997 if (LocaleCompare("clip-path",token) == 0)
3999 (void) WriteBlobString(image,"</clipPath>\n");
4002 if (LocaleCompare("defs",token) == 0)
4004 (void) WriteBlobString(image,"</defs>\n");
4007 if (LocaleCompare("gradient",token) == 0)
4009 (void) FormatLocaleString(message,MagickPathExtent,
4010 "</%sGradient>\n",type);
4011 (void) WriteBlobString(image,message);
4014 if (LocaleCompare("graphic-context",token) == 0)
4018 ThrowWriterException(DrawError,
4019 "UnbalancedGraphicContextPushPop");
4020 (void) WriteBlobString(image,"</g>\n");
4022 if (LocaleCompare("pattern",token) == 0)
4024 (void) WriteBlobString(image,"</pattern>\n");
4027 if (LocaleCompare("defs",token) == 0)
4028 (void) WriteBlobString(image,"</g>\n");
4031 if (LocaleCompare("push",keyword) == 0)
4033 GetMagickToken(q,&q,token);
4034 if (LocaleCompare("clip-path",token) == 0)
4036 GetMagickToken(q,&q,token);
4037 (void) FormatLocaleString(message,MagickPathExtent,
4038 "<clipPath id=\"%s\">\n",token);
4039 (void) WriteBlobString(image,message);
4042 if (LocaleCompare("defs",token) == 0)
4044 (void) WriteBlobString(image,"<defs>\n");
4047 if (LocaleCompare("gradient",token) == 0)
4049 GetMagickToken(q,&q,token);
4050 (void) CopyMagickString(name,token,MagickPathExtent);
4051 GetMagickToken(q,&q,token);
4052 (void) CopyMagickString(type,token,MagickPathExtent);
4053 GetMagickToken(q,&q,token);
4054 svg_info.segment.x1=StringToDouble(token,(char **) NULL);
4055 svg_info.element.cx=StringToDouble(token,(char **) NULL);
4056 GetMagickToken(q,&q,token);
4058 GetMagickToken(q,&q,token);
4059 svg_info.segment.y1=StringToDouble(token,(char **) NULL);
4060 svg_info.element.cy=StringToDouble(token,(char **) NULL);
4061 GetMagickToken(q,&q,token);
4063 GetMagickToken(q,&q,token);
4064 svg_info.segment.x2=StringToDouble(token,(char **) NULL);
4065 svg_info.element.major=StringToDouble(token,
4067 GetMagickToken(q,&q,token);
4069 GetMagickToken(q,&q,token);
4070 svg_info.segment.y2=StringToDouble(token,(char **) NULL);
4071 svg_info.element.minor=StringToDouble(token,
4073 (void) FormatLocaleString(message,MagickPathExtent,
4074 "<%sGradient id=\"%s\" x1=\"%g\" y1=\"%g\" x2=\"%g\" "
4075 "y2=\"%g\">\n",type,name,svg_info.segment.x1,
4076 svg_info.segment.y1,svg_info.segment.x2,svg_info.segment.y2);
4077 if (LocaleCompare(type,"radial") == 0)
4079 GetMagickToken(q,&q,token);
4081 GetMagickToken(q,&q,token);
4082 svg_info.element.angle=StringToDouble(token,
4084 (void) FormatLocaleString(message,MagickPathExtent,
4085 "<%sGradient id=\"%s\" cx=\"%g\" cy=\"%g\" r=\"%g\" "
4086 "fx=\"%g\" fy=\"%g\">\n",type,name,
4087 svg_info.element.cx,svg_info.element.cy,
4088 svg_info.element.angle,svg_info.element.major,
4089 svg_info.element.minor);
4091 (void) WriteBlobString(image,message);
4094 if (LocaleCompare("graphic-context",token) == 0)
4099 AffineToTransform(image,&affine);
4102 (void) WriteBlobString(image,"<g style=\"");
4105 if (LocaleCompare("pattern",token) == 0)
4107 GetMagickToken(q,&q,token);
4108 (void) CopyMagickString(name,token,MagickPathExtent);
4109 GetMagickToken(q,&q,token);
4110 svg_info.bounds.x=StringToDouble(token,(char **) NULL);
4111 GetMagickToken(q,&q,token);
4113 GetMagickToken(q,&q,token);
4114 svg_info.bounds.y=StringToDouble(token,(char **) NULL);
4115 GetMagickToken(q,&q,token);
4117 GetMagickToken(q,&q,token);
4118 svg_info.bounds.width=StringToDouble(token,
4120 GetMagickToken(q,&q,token);
4122 GetMagickToken(q,&q,token);
4123 svg_info.bounds.height=StringToDouble(token,
4125 (void) FormatLocaleString(message,MagickPathExtent,
4126 "<pattern id=\"%s\" x=\"%g\" y=\"%g\" width=\"%g\" "
4127 "height=\"%g\">\n",name,svg_info.bounds.x,
4128 svg_info.bounds.y,svg_info.bounds.width,
4129 svg_info.bounds.height);
4130 (void) WriteBlobString(image,message);
4141 if (LocaleCompare("rectangle",keyword) == 0)
4143 primitive_type=RectanglePrimitive;
4146 if (LocaleCompare("roundRectangle",keyword) == 0)
4148 primitive_type=RoundRectanglePrimitive;
4151 if (LocaleCompare("rotate",keyword) == 0)
4153 GetMagickToken(q,&q,token);
4154 (void) FormatLocaleString(message,MagickPathExtent,"rotate(%s) ",
4156 (void) WriteBlobString(image,message);
4165 if (LocaleCompare("scale",keyword) == 0)
4167 GetMagickToken(q,&q,token);
4168 affine.sx=StringToDouble(token,(char **) NULL);
4169 GetMagickToken(q,&q,token);
4171 GetMagickToken(q,&q,token);
4172 affine.sy=StringToDouble(token,(char **) NULL);
4175 if (LocaleCompare("skewX",keyword) == 0)
4177 GetMagickToken(q,&q,token);
4178 (void) FormatLocaleString(message,MagickPathExtent,"skewX(%s) ",
4180 (void) WriteBlobString(image,message);
4183 if (LocaleCompare("skewY",keyword) == 0)
4185 GetMagickToken(q,&q,token);
4186 (void) FormatLocaleString(message,MagickPathExtent,"skewY(%s) ",
4188 (void) WriteBlobString(image,message);
4191 if (LocaleCompare("stop-color",keyword) == 0)
4194 color[MagickPathExtent];
4196 GetMagickToken(q,&q,token);
4197 (void) CopyMagickString(color,token,MagickPathExtent);
4198 GetMagickToken(q,&q,token);
4199 (void) FormatLocaleString(message,MagickPathExtent,
4200 " <stop offset=\"%s\" stop-color=\"%s\" />\n",token,color);
4201 (void) WriteBlobString(image,message);
4204 if (LocaleCompare("stroke",keyword) == 0)
4206 GetMagickToken(q,&q,token);
4207 (void) FormatLocaleString(message,MagickPathExtent,"stroke:%s;",
4209 (void) WriteBlobString(image,message);
4212 if (LocaleCompare("stroke-antialias",keyword) == 0)
4214 GetMagickToken(q,&q,token);
4215 (void) FormatLocaleString(message,MagickPathExtent,
4216 "stroke-antialias:%s;",token);
4217 (void) WriteBlobString(image,message);
4220 if (LocaleCompare("stroke-dasharray",keyword) == 0)
4228 GetMagickToken(p,&p,token);
4229 for (k=0; IsPoint(token); k++)
4230 GetMagickToken(p,&p,token);
4231 (void) WriteBlobString(image,"stroke-dasharray:");
4232 for (j=0; j < k; j++)
4234 GetMagickToken(q,&q,token);
4235 (void) FormatLocaleString(message,MagickPathExtent,"%s ",
4237 (void) WriteBlobString(image,message);
4239 (void) WriteBlobString(image,";");
4242 GetMagickToken(q,&q,token);
4243 (void) FormatLocaleString(message,MagickPathExtent,
4244 "stroke-dasharray:%s;",token);
4245 (void) WriteBlobString(image,message);
4248 if (LocaleCompare("stroke-dashoffset",keyword) == 0)
4250 GetMagickToken(q,&q,token);
4251 (void) FormatLocaleString(message,MagickPathExtent,
4252 "stroke-dashoffset:%s;",token);
4253 (void) WriteBlobString(image,message);
4256 if (LocaleCompare("stroke-linecap",keyword) == 0)
4258 GetMagickToken(q,&q,token);
4259 (void) FormatLocaleString(message,MagickPathExtent,
4260 "stroke-linecap:%s;",token);
4261 (void) WriteBlobString(image,message);
4264 if (LocaleCompare("stroke-linejoin",keyword) == 0)
4266 GetMagickToken(q,&q,token);
4267 (void) FormatLocaleString(message,MagickPathExtent,
4268 "stroke-linejoin:%s;",token);
4269 (void) WriteBlobString(image,message);
4272 if (LocaleCompare("stroke-miterlimit",keyword) == 0)
4274 GetMagickToken(q,&q,token);
4275 (void) FormatLocaleString(message,MagickPathExtent,
4276 "stroke-miterlimit:%s;",token);
4277 (void) WriteBlobString(image,message);
4280 if (LocaleCompare("stroke-opacity",keyword) == 0)
4282 GetMagickToken(q,&q,token);
4283 (void) FormatLocaleString(message,MagickPathExtent,
4284 "stroke-opacity:%s;",token);
4285 (void) WriteBlobString(image,message);
4288 if (LocaleCompare("stroke-width",keyword) == 0)
4290 GetMagickToken(q,&q,token);
4291 (void) FormatLocaleString(message,MagickPathExtent,
4292 "stroke-width:%s;",token);
4293 (void) WriteBlobString(image,message);
4302 if (LocaleCompare("text",keyword) == 0)
4304 primitive_type=TextPrimitive;
4307 if (LocaleCompare("text-antialias",keyword) == 0)
4309 GetMagickToken(q,&q,token);
4310 (void) FormatLocaleString(message,MagickPathExtent,
4311 "text-antialias:%s;",token);
4312 (void) WriteBlobString(image,message);
4315 if (LocaleCompare("tspan",keyword) == 0)
4317 primitive_type=TextPrimitive;
4320 if (LocaleCompare("translate",keyword) == 0)
4322 GetMagickToken(q,&q,token);
4323 affine.tx=StringToDouble(token,(char **) NULL);
4324 GetMagickToken(q,&q,token);
4326 GetMagickToken(q,&q,token);
4327 affine.ty=StringToDouble(token,(char **) NULL);
4336 if (LocaleCompare("viewbox",keyword) == 0)
4338 GetMagickToken(q,&q,token);
4340 GetMagickToken(q,&q,token);
4341 GetMagickToken(q,&q,token);
4343 GetMagickToken(q,&q,token);
4344 GetMagickToken(q,&q,token);
4346 GetMagickToken(q,&q,token);
4347 GetMagickToken(q,&q,token);
4359 if (status == MagickFalse)
4361 if (primitive_type == UndefinedPrimitive)
4364 Parse the primitive attributes.
4368 for (x=0; *q != '\0'; x++)
4373 if (IsPoint(q) == MagickFalse)
4375 GetMagickToken(q,&q,token);
4376 point.x=StringToDouble(token,(char **) NULL);
4377 GetMagickToken(q,&q,token);
4379 GetMagickToken(q,&q,token);
4380 point.y=StringToDouble(token,(char **) NULL);
4381 GetMagickToken(q,(const char **) NULL,token);
4383 GetMagickToken(q,&q,token);
4384 primitive_info[i].primitive=primitive_type;
4385 primitive_info[i].point=point;
4386 primitive_info[i].coordinates=0;
4387 primitive_info[i].method=FloodfillMethod;
4389 if (i < (ssize_t) (number_points-6*BezierQuantum-360))
4391 number_points+=6*BezierQuantum+360;
4392 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4393 number_points,sizeof(*primitive_info));
4394 if (primitive_info == (PrimitiveInfo *) NULL)
4396 (void) ThrowMagickException(exception,GetMagickModule(),
4397 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
4401 primitive_info[j].primitive=primitive_type;
4402 primitive_info[j].coordinates=x;
4403 primitive_info[j].method=FloodfillMethod;
4404 primitive_info[j].text=(char *) NULL;
4407 AffineToTransform(image,&affine);
4411 switch (primitive_type)
4413 case PointPrimitive:
4416 if (primitive_info[j].coordinates != 1)
4425 if (primitive_info[j].coordinates != 2)
4430 (void) FormatLocaleString(message,MagickPathExtent,
4431 " <line x1=\"%g\" y1=\"%g\" x2=\"%g\" y2=\"%g\"/>\n",
4432 primitive_info[j].point.x,primitive_info[j].point.y,
4433 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4434 (void) WriteBlobString(image,message);
4437 case RectanglePrimitive:
4439 if (primitive_info[j].coordinates != 2)
4444 (void) FormatLocaleString(message,MagickPathExtent,
4445 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"/>\n",
4446 primitive_info[j].point.x,primitive_info[j].point.y,
4447 primitive_info[j+1].point.x-primitive_info[j].point.x,
4448 primitive_info[j+1].point.y-primitive_info[j].point.y);
4449 (void) WriteBlobString(image,message);
4452 case RoundRectanglePrimitive:
4454 if (primitive_info[j].coordinates != 3)
4459 (void) FormatLocaleString(message,MagickPathExtent,
4460 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" rx=\"%g\" "
4461 "ry=\"%g\"/>\n",primitive_info[j].point.x,
4462 primitive_info[j].point.y,primitive_info[j+1].point.x-
4463 primitive_info[j].point.x,primitive_info[j+1].point.y-
4464 primitive_info[j].point.y,primitive_info[j+2].point.x,
4465 primitive_info[j+2].point.y);
4466 (void) WriteBlobString(image,message);
4471 if (primitive_info[j].coordinates != 3)
4478 case EllipsePrimitive:
4480 if (primitive_info[j].coordinates != 3)
4485 (void) FormatLocaleString(message,MagickPathExtent,
4486 " <ellipse cx=\"%g\" cy=\"%g\" rx=\"%g\" ry=\"%g\"/>\n",
4487 primitive_info[j].point.x,primitive_info[j].point.y,
4488 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4489 (void) WriteBlobString(image,message);
4492 case CirclePrimitive:
4498 if (primitive_info[j].coordinates != 2)
4503 alpha=primitive_info[j+1].point.x-primitive_info[j].point.x;
4504 beta=primitive_info[j+1].point.y-primitive_info[j].point.y;
4505 (void) FormatLocaleString(message,MagickPathExtent,
4506 " <circle cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
4507 primitive_info[j].point.x,primitive_info[j].point.y,
4509 (void) WriteBlobString(image,message);
4512 case PolylinePrimitive:
4514 if (primitive_info[j].coordinates < 2)
4519 (void) CopyMagickString(message," <polyline points=\"",MagickPathExtent);
4520 (void) WriteBlobString(image,message);
4521 length=strlen(message);
4524 (void) FormatLocaleString(message,MagickPathExtent,"%g,%g ",
4525 primitive_info[j].point.x,primitive_info[j].point.y);
4526 length+=strlen(message);
4529 (void) WriteBlobString(image,"\n ");
4530 length=strlen(message)+5;
4532 (void) WriteBlobString(image,message);
4534 (void) WriteBlobString(image,"\"/>\n");
4537 case PolygonPrimitive:
4539 if (primitive_info[j].coordinates < 3)
4544 primitive_info[i]=primitive_info[j];
4545 primitive_info[i].coordinates=0;
4546 primitive_info[j].coordinates++;
4548 (void) CopyMagickString(message," <polygon points=\"",MagickPathExtent);
4549 (void) WriteBlobString(image,message);
4550 length=strlen(message);
4553 (void) FormatLocaleString(message,MagickPathExtent,"%g,%g ",
4554 primitive_info[j].point.x,primitive_info[j].point.y);
4555 length+=strlen(message);
4558 (void) WriteBlobString(image,"\n ");
4559 length=strlen(message)+5;
4561 (void) WriteBlobString(image,message);
4563 (void) WriteBlobString(image,"\"/>\n");
4566 case BezierPrimitive:
4568 if (primitive_info[j].coordinates < 3)
4580 GetMagickToken(q,&q,token);
4581 number_attributes=1;
4582 for (p=token; *p != '\0'; p++)
4583 if (isalpha((int) *p))
4584 number_attributes++;
4585 if (i > (ssize_t) (number_points-6*BezierQuantum*number_attributes-1))
4587 number_points+=6*BezierQuantum*number_attributes;
4588 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4589 number_points,sizeof(*primitive_info));
4590 if (primitive_info == (PrimitiveInfo *) NULL)
4592 (void) ThrowMagickException(exception,GetMagickModule(),
4593 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4598 (void) WriteBlobString(image," <path d=\"");
4599 (void) WriteBlobString(image,token);
4600 (void) WriteBlobString(image,"\"/>\n");
4603 case AlphaPrimitive:
4604 case ColorPrimitive:
4606 if (primitive_info[j].coordinates != 1)
4611 GetMagickToken(q,&q,token);
4612 if (LocaleCompare("point",token) == 0)
4613 primitive_info[j].method=PointMethod;
4614 if (LocaleCompare("replace",token) == 0)
4615 primitive_info[j].method=ReplaceMethod;
4616 if (LocaleCompare("floodfill",token) == 0)
4617 primitive_info[j].method=FloodfillMethod;
4618 if (LocaleCompare("filltoborder",token) == 0)
4619 primitive_info[j].method=FillToBorderMethod;
4620 if (LocaleCompare("reset",token) == 0)
4621 primitive_info[j].method=ResetMethod;
4629 if (primitive_info[j].coordinates != 1)
4634 GetMagickToken(q,&q,token);
4635 (void) FormatLocaleString(message,MagickPathExtent,
4636 " <text x=\"%g\" y=\"%g\">",primitive_info[j].point.x,
4637 primitive_info[j].point.y);
4638 (void) WriteBlobString(image,message);
4639 for (p=token; *p != '\0'; p++)
4642 case '<': (void) WriteBlobString(image,"<"); break;
4643 case '>': (void) WriteBlobString(image,">"); break;
4644 case '&': (void) WriteBlobString(image,"&"); break;
4645 default: (void) WriteBlobByte(image,*p); break;
4647 (void) WriteBlobString(image,"</text>\n");
4650 case ImagePrimitive:
4652 if (primitive_info[j].coordinates != 2)
4657 GetMagickToken(q,&q,token);
4658 (void) FormatLocaleString(message,MagickPathExtent,
4659 " <image x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" "
4660 "xlink:href=\"%s\"/>\n",primitive_info[j].point.x,
4661 primitive_info[j].point.y,primitive_info[j+1].point.x,
4662 primitive_info[j+1].point.y,token);
4663 (void) WriteBlobString(image,message);
4667 if (primitive_info == (PrimitiveInfo *) NULL)
4669 primitive_info[i].primitive=UndefinedPrimitive;
4670 if (status == MagickFalse)
4673 (void) WriteBlobString(image,"</svg>\n");
4675 Relinquish resources.
4677 token=DestroyString(token);
4678 if (primitive_info != (PrimitiveInfo *) NULL)
4679 primitive_info=(PrimitiveInfo *) RelinquishMagickMemory(primitive_info);
4680 (void) CloseBlob(image);