2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Scalable Vector Graphics Format %
21 % Copyright 1999-2018 ImageMagick Studio LLC, a non-profit organization %
22 % dedicated to making software imaging solutions freely available. %
24 % You may not use this file except in compliance with the License. You may %
25 % obtain a copy of the License at %
27 % https://www.imagemagick.org/script/license.php %
29 % Unless required by applicable law or agreed to in writing, software %
30 % distributed under the License is distributed on an "AS IS" BASIS, %
31 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
32 % See the License for the specific language governing permissions and %
33 % limitations under the License. %
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
44 #include "MagickCore/studio.h"
45 #include "MagickCore/annotate.h"
46 #include "MagickCore/artifact.h"
47 #include "MagickCore/attribute.h"
48 #include "MagickCore/blob.h"
49 #include "MagickCore/blob-private.h"
50 #include "MagickCore/cache.h"
51 #include "MagickCore/constitute.h"
52 #include "MagickCore/composite-private.h"
53 #include "MagickCore/delegate.h"
54 #include "MagickCore/delegate-private.h"
55 #include "MagickCore/draw.h"
56 #include "MagickCore/exception.h"
57 #include "MagickCore/exception-private.h"
58 #include "MagickCore/gem.h"
59 #include "MagickCore/image.h"
60 #include "MagickCore/image-private.h"
61 #include "MagickCore/list.h"
62 #include "MagickCore/log.h"
63 #include "MagickCore/magick.h"
64 #include "MagickCore/memory_.h"
65 #include "MagickCore/memory-private.h"
66 #include "MagickCore/module.h"
67 #include "MagickCore/monitor.h"
68 #include "MagickCore/monitor-private.h"
69 #include "MagickCore/quantum-private.h"
70 #include "MagickCore/pixel-accessor.h"
71 #include "MagickCore/property.h"
72 #include "MagickCore/resource_.h"
73 #include "MagickCore/static.h"
74 #include "MagickCore/string_.h"
75 #include "MagickCore/string-private.h"
76 #include "MagickCore/token.h"
77 #include "MagickCore/utility.h"
78 #if defined(MAGICKCORE_XML_DELEGATE)
79 # if defined(MAGICKCORE_WINDOWS_SUPPORT)
80 # if !defined(__MINGW32__)
81 # include <win32config.h>
84 # include <libxml/parser.h>
85 # include <libxml/xmlmemory.h>
86 # include <libxml/parserInternals.h>
87 # include <libxml/xmlerror.h>
90 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
91 #include "autotrace/autotrace.h"
94 #if defined(MAGICKCORE_RSVG_DELEGATE)
95 #include "librsvg/rsvg.h"
96 #if !defined(LIBRSVG_CHECK_VERSION)
97 #include "librsvg/rsvg-cairo.h"
98 #include "librsvg/librsvg-features.h"
99 #elif !LIBRSVG_CHECK_VERSION(2,36,2)
100 #include "librsvg/rsvg-cairo.h"
101 #include "librsvg/librsvg-features.h"
107 Typedef declarations.
109 typedef struct _BoundingBox
118 typedef struct _ElementInfo
128 typedef struct _SVGInfo
182 #if defined(MAGICKCORE_XML_DELEGATE)
193 Forward declarations.
195 static MagickBooleanType
196 WriteSVGImage(const ImageInfo *,Image *,ExceptionInfo *);
200 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
208 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
210 % IsSVG()() returns MagickTrue if the image format type, identified by the
211 % magick string, is SVG.
213 % The format of the IsSVG method is:
215 % MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
217 % A description of each parameter follows:
219 % o magick: compare image format pattern against these bytes.
221 % o length: Specifies the length of the magick string.
224 static MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
228 if (LocaleNCompare((const char *) magick,"?xml",4) == 0)
233 #if defined(MAGICKCORE_XML_DELEGATE)
235 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
239 % R e a d S V G I m a g e %
243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
245 % ReadSVGImage() reads a Scalable Vector Gaphics file and returns it. It
246 % allocates the memory necessary for the new Image structure and returns a
247 % pointer to the new image.
249 % The format of the ReadSVGImage method is:
251 % Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
253 % A description of each parameter follows:
255 % o image_info: the image info.
257 % o exception: return any errors or warnings in this structure.
261 static SVGInfo *AcquireSVGInfo(void)
266 svg_info=(SVGInfo *) AcquireMagickMemory(sizeof(*svg_info));
267 if (svg_info == (SVGInfo *) NULL)
268 return((SVGInfo *) NULL);
269 (void) ResetMagickMemory(svg_info,0,sizeof(*svg_info));
270 svg_info->text=AcquireString("");
271 svg_info->scale=(double *) AcquireCriticalMemory(sizeof(*svg_info->scale));
272 GetAffineMatrix(&svg_info->affine);
273 svg_info->scale[0]=ExpandAffine(&svg_info->affine);
277 static SVGInfo *DestroySVGInfo(SVGInfo *svg_info)
279 if (svg_info->text != (char *) NULL)
280 svg_info->text=DestroyString(svg_info->text);
281 if (svg_info->scale != (double *) NULL)
282 svg_info->scale=(double *) RelinquishMagickMemory(svg_info->scale);
283 if (svg_info->title != (char *) NULL)
284 svg_info->title=DestroyString(svg_info->title);
285 if (svg_info->comment != (char *) NULL)
286 svg_info->comment=DestroyString(svg_info->comment);
287 return((SVGInfo *) RelinquishMagickMemory(svg_info));
290 static double GetUserSpaceCoordinateValue(const SVGInfo *svg_info,int type,
295 token[MagickPathExtent];
303 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",string);
304 assert(string != (const char *) NULL);
305 p=(const char *) string;
306 GetNextToken(p,&p,MagickPathExtent,token);
307 value=StringToDouble(token,&next_token);
308 if (strchr(token,'%') != (char *) NULL)
316 if (svg_info->view_box.width == 0.0)
318 return(svg_info->view_box.width*value/100.0);
322 if (svg_info->view_box.height == 0.0)
324 return(svg_info->view_box.height*value/100.0);
326 alpha=value-svg_info->view_box.width;
327 beta=value-svg_info->view_box.height;
328 return(hypot(alpha,beta)/sqrt(2.0)/100.0);
330 GetNextToken(p,&p,MagickPathExtent,token);
331 if (LocaleNCompare(token,"cm",2) == 0)
332 return(96.0*svg_info->scale[0]/2.54*value);
333 if (LocaleNCompare(token,"em",2) == 0)
334 return(svg_info->pointsize*value);
335 if (LocaleNCompare(token,"ex",2) == 0)
336 return(svg_info->pointsize*value/2.0);
337 if (LocaleNCompare(token,"in",2) == 0)
338 return(96.0*svg_info->scale[0]*value);
339 if (LocaleNCompare(token,"mm",2) == 0)
340 return(96.0*svg_info->scale[0]/25.4*value);
341 if (LocaleNCompare(token,"pc",2) == 0)
342 return(96.0*svg_info->scale[0]/6.0*value);
343 if (LocaleNCompare(token,"pt",2) == 0)
344 return(1.25*svg_info->scale[0]*value);
345 if (LocaleNCompare(token,"px",2) == 0)
350 static void StripStyleTokens(char *message)
359 assert(message != (char *) NULL);
360 if (*message == '\0')
362 length=strlen(message);
364 while (isspace((int) ((unsigned char) *p)) != 0)
367 while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
369 (void) CopyMagickMemory(message,p,(size_t) (q-p+1));
371 StripString(message);
374 static char **GetStyleTokens(void *context,const char *style,
375 size_t *number_tokens)
387 svg_info=(SVGInfo *) context;
390 if (style == (const char *) NULL)
391 return((char **) NULL);
392 text=AcquireString(style);
393 (void) SubstituteString(&text,":","\n");
394 (void) SubstituteString(&text,";","\n");
395 tokens=StringToList(text);
396 text=DestroyString(text);
397 for (i=0; tokens[i] != (char *) NULL; i++)
398 StripStyleTokens(tokens[i]);
399 *number_tokens=(size_t) i;
403 static char **GetTransformTokens(void *context,const char *text,
404 size_t *number_tokens)
422 svg_info=(SVGInfo *) context;
424 if (text == (const char *) NULL)
425 return((char **) NULL);
427 tokens=(char **) AcquireQuantumMemory(extent+2UL,sizeof(*tokens));
428 if (tokens == (char **) NULL)
430 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
431 ResourceLimitError,"MemoryAllocationFailed","`%s'",text);
432 return((char **) NULL);
435 Convert string to an ASCII list.
439 for (q=p; *q != '\0'; q++)
441 if ((*q != '(') && (*q != ')') && (*q != '\0'))
443 if (i == (ssize_t) extent)
446 tokens=(char **) ResizeQuantumMemory(tokens,extent+2,sizeof(*tokens));
447 if (tokens == (char **) NULL)
449 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
450 ResourceLimitError,"MemoryAllocationFailed","`%s'",text);
451 return((char **) NULL);
454 tokens[i]=AcquireString(p);
455 (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
456 StripString(tokens[i]);
460 tokens[i]=AcquireString(p);
461 (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
462 StripString(tokens[i++]);
463 tokens[i]=(char *) NULL;
464 *number_tokens=(size_t) i;
468 #if defined(__cplusplus) || defined(c_plusplus)
472 static int SVGIsStandalone(void *context)
478 Is this document tagged standalone?
480 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGIsStandalone()");
481 svg_info=(SVGInfo *) context;
482 return(svg_info->document->standalone == 1);
485 static int SVGHasInternalSubset(void *context)
491 Does this document has an internal subset?
493 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
494 " SAX.SVGHasInternalSubset()");
495 svg_info=(SVGInfo *) context;
496 return(svg_info->document->intSubset != NULL);
499 static int SVGHasExternalSubset(void *context)
505 Does this document has an external subset?
507 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
508 " SAX.SVGHasExternalSubset()");
509 svg_info=(SVGInfo *) context;
510 return(svg_info->document->extSubset != NULL);
513 static void SVGInternalSubset(void *context,const xmlChar *name,
514 const xmlChar *external_id,const xmlChar *system_id)
520 Does this document has an internal subset?
522 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
523 " SAX.internalSubset(%s, %s, %s)",(const char *) name,
524 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
525 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
526 svg_info=(SVGInfo *) context;
527 (void) xmlCreateIntSubset(svg_info->document,name,external_id,system_id);
530 static xmlParserInputPtr SVGResolveEntity(void *context,
531 const xmlChar *public_id,const xmlChar *system_id)
540 Special entity resolver, better left to the parser, it has more
541 context than the application layer. The default behaviour is to
542 not resolve the entities, in that case the ENTITY_REF nodes are
543 built in the structure (and the parameter values).
545 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
546 " SAX.resolveEntity(%s, %s)",
547 (public_id != (const xmlChar *) NULL ? (const char *) public_id : "none"),
548 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
549 svg_info=(SVGInfo *) context;
550 stream=xmlLoadExternalEntity((const char *) system_id,(const char *)
551 public_id,svg_info->parser);
555 static xmlEntityPtr SVGGetEntity(void *context,const xmlChar *name)
561 Get an entity by name.
563 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGGetEntity(%s)",
565 svg_info=(SVGInfo *) context;
566 return(xmlGetDocEntity(svg_info->document,name));
569 static xmlEntityPtr SVGGetParameterEntity(void *context,const xmlChar *name)
575 Get a parameter entity by name.
577 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
578 " SAX.getParameterEntity(%s)",name);
579 svg_info=(SVGInfo *) context;
580 return(xmlGetParameterEntity(svg_info->document,name));
583 static void SVGEntityDeclaration(void *context,const xmlChar *name,int type,
584 const xmlChar *public_id,const xmlChar *system_id,xmlChar *content)
590 An entity definition has been parsed.
592 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
593 " SAX.entityDecl(%s, %d, %s, %s, %s)",name,type,
594 public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
595 system_id != (xmlChar *) NULL ? (const char *) system_id : "none",content);
596 svg_info=(SVGInfo *) context;
597 if (svg_info->parser->inSubset == 1)
598 (void) xmlAddDocEntity(svg_info->document,name,type,public_id,system_id,
601 if (svg_info->parser->inSubset == 2)
602 (void) xmlAddDtdEntity(svg_info->document,name,type,public_id,system_id,
606 static void SVGAttributeDeclaration(void *context,const xmlChar *element,
607 const xmlChar *name,int type,int value,const xmlChar *default_value,
608 xmlEnumerationPtr tree)
621 An attribute definition has been parsed.
623 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
624 " SAX.attributeDecl(%s, %s, %d, %d, %s, ...)",element,name,type,value,
626 svg_info=(SVGInfo *) context;
627 fullname=(xmlChar *) NULL;
628 prefix=(xmlChar *) NULL;
629 parser=svg_info->parser;
630 fullname=(xmlChar *) xmlSplitQName(parser,name,&prefix);
631 if (parser->inSubset == 1)
632 (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->intSubset,
633 element,fullname,prefix,(xmlAttributeType) type,
634 (xmlAttributeDefault) value,default_value,tree);
636 if (parser->inSubset == 2)
637 (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->extSubset,
638 element,fullname,prefix,(xmlAttributeType) type,
639 (xmlAttributeDefault) value,default_value,tree);
640 if (prefix != (xmlChar *) NULL)
642 if (fullname != (xmlChar *) NULL)
646 static void SVGElementDeclaration(void *context,const xmlChar *name,int type,
647 xmlElementContentPtr content)
656 An element definition has been parsed.
658 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
659 " SAX.elementDecl(%s, %d, ...)",name,type);
660 svg_info=(SVGInfo *) context;
661 parser=svg_info->parser;
662 if (parser->inSubset == 1)
663 (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->intSubset,
664 name,(xmlElementTypeVal) type,content);
666 if (parser->inSubset == 2)
667 (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->extSubset,
668 name,(xmlElementTypeVal) type,content);
671 static void SVGNotationDeclaration(void *context,const xmlChar *name,
672 const xmlChar *public_id,const xmlChar *system_id)
681 What to do when a notation declaration has been parsed.
683 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
684 " SAX.notationDecl(%s, %s, %s)",name,
685 public_id != (const xmlChar *) NULL ? (const char *) public_id : "none",
686 system_id != (const xmlChar *) NULL ? (const char *) system_id : "none");
687 svg_info=(SVGInfo *) context;
688 parser=svg_info->parser;
689 if (parser->inSubset == 1)
690 (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
691 name,public_id,system_id);
693 if (parser->inSubset == 2)
694 (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
695 name,public_id,system_id);
698 static void SVGUnparsedEntityDeclaration(void *context,const xmlChar *name,
699 const xmlChar *public_id,const xmlChar *system_id,const xmlChar *notation)
705 What to do when an unparsed entity declaration is parsed.
707 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
708 " SAX.unparsedEntityDecl(%s, %s, %s, %s)",name,
709 public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
710 system_id != (xmlChar *) NULL ? (const char *) system_id : "none",notation);
711 svg_info=(SVGInfo *) context;
712 (void) xmlAddDocEntity(svg_info->document,name,
713 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,public_id,system_id,notation);
717 static void SVGSetDocumentLocator(void *context,xmlSAXLocatorPtr location)
723 Receive the document locator at startup, actually xmlDefaultSAXLocator.
726 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
727 " SAX.setDocumentLocator()");
728 svg_info=(SVGInfo *) context;
732 static void SVGStartDocument(void *context)
741 Called when the document start being processed.
743 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startDocument()");
744 svg_info=(SVGInfo *) context;
745 parser=svg_info->parser;
746 svg_info->document=xmlNewDoc(parser->version);
747 if (svg_info->document == (xmlDocPtr) NULL)
749 if (parser->encoding == NULL)
750 svg_info->document->encoding=(const xmlChar *) NULL;
752 svg_info->document->encoding=xmlStrdup(parser->encoding);
753 svg_info->document->standalone=parser->standalone;
756 static void SVGEndDocument(void *context)
762 Called when the document end has been detected.
764 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.endDocument()");
765 svg_info=(SVGInfo *) context;
766 if (svg_info->offset != (char *) NULL)
767 svg_info->offset=DestroyString(svg_info->offset);
768 if (svg_info->stop_color != (char *) NULL)
769 svg_info->stop_color=DestroyString(svg_info->stop_color);
770 if (svg_info->scale != (double *) NULL)
771 svg_info->scale=(double *) RelinquishMagickMemory(svg_info->scale);
772 if (svg_info->text != (char *) NULL)
773 svg_info->text=DestroyString(svg_info->text);
774 if (svg_info->vertices != (char *) NULL)
775 svg_info->vertices=DestroyString(svg_info->vertices);
776 if (svg_info->url != (char *) NULL)
777 svg_info->url=DestroyString(svg_info->url);
778 #if defined(MAGICKCORE_XML_DELEGATE)
779 if (svg_info->document != (xmlDocPtr) NULL)
781 xmlFreeDoc(svg_info->document);
782 svg_info->document=(xmlDocPtr) NULL;
787 static void SVGStartElement(void *context,const xmlChar *name,
788 const xmlChar **attributes)
792 id[MagickPathExtent],
794 token[MagickPathExtent],
814 Called when an opening tag has been processed.
816 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startElement(%s",
818 svg_info=(SVGInfo *) context;
820 svg_info->scale=(double *) ResizeQuantumMemory(svg_info->scale,
821 svg_info->n+1UL,sizeof(*svg_info->scale));
822 if (svg_info->scale == (double *) NULL)
824 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
825 ResourceLimitError,"MemoryAllocationFailed","`%s'",name);
828 svg_info->scale[svg_info->n]=svg_info->scale[svg_info->n-1];
829 color=AcquireString("none");
830 units=AcquireString("userSpaceOnUse");
833 value=(const char *) NULL;
834 if (attributes != (const xmlChar **) NULL)
835 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
837 keyword=(const char *) attributes[i];
838 value=(const char *) attributes[i+1];
844 if (LocaleCompare(keyword,"cx") == 0)
846 svg_info->element.cx=
847 GetUserSpaceCoordinateValue(svg_info,1,value);
850 if (LocaleCompare(keyword,"cy") == 0)
852 svg_info->element.cy=
853 GetUserSpaceCoordinateValue(svg_info,-1,value);
861 if (LocaleCompare(keyword,"fx") == 0)
863 svg_info->element.major=
864 GetUserSpaceCoordinateValue(svg_info,1,value);
867 if (LocaleCompare(keyword,"fy") == 0)
869 svg_info->element.minor=
870 GetUserSpaceCoordinateValue(svg_info,-1,value);
878 if (LocaleCompare(keyword,"height") == 0)
880 svg_info->bounds.height=
881 GetUserSpaceCoordinateValue(svg_info,-1,value);
889 if (LocaleCompare(keyword,"id") == 0)
891 (void) CopyMagickString(id,value,MagickPathExtent);
899 if (LocaleCompare(keyword,"r") == 0)
901 svg_info->element.angle=
902 GetUserSpaceCoordinateValue(svg_info,0,value);
910 if (LocaleCompare(keyword,"width") == 0)
912 svg_info->bounds.width=
913 GetUserSpaceCoordinateValue(svg_info,1,value);
921 if (LocaleCompare(keyword,"x") == 0)
923 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value)-
927 if (LocaleCompare(keyword,"x1") == 0)
929 svg_info->segment.x1=GetUserSpaceCoordinateValue(svg_info,1,
933 if (LocaleCompare(keyword,"x2") == 0)
935 svg_info->segment.x2=GetUserSpaceCoordinateValue(svg_info,1,
944 if (LocaleCompare(keyword,"y") == 0)
946 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value)-
950 if (LocaleCompare(keyword,"y1") == 0)
952 svg_info->segment.y1=
953 GetUserSpaceCoordinateValue(svg_info,-1,value);
956 if (LocaleCompare(keyword,"y2") == 0)
958 svg_info->segment.y2=
959 GetUserSpaceCoordinateValue(svg_info,-1,value);
968 if (strchr((char *) name,':') != (char *) NULL)
973 for ( ; *name != ':'; name++) ;
981 if (LocaleCompare((const char *) name,"circle") == 0)
983 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
986 if (LocaleCompare((const char *) name,"clipPath") == 0)
988 (void) FormatLocaleFile(svg_info->file,"push clip-path '%s'\n",id);
996 if (LocaleCompare((const char *) name,"defs") == 0)
998 (void) FormatLocaleFile(svg_info->file,"push defs\n");
1006 if (LocaleCompare((const char *) name,"ellipse") == 0)
1008 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1016 if (LocaleCompare((const char *) name,"g") == 0)
1018 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1026 if (LocaleCompare((const char *) name,"image") == 0)
1028 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1036 if (LocaleCompare((const char *) name,"line") == 0)
1038 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1041 if (LocaleCompare((const char *) name,"linearGradient") == 0)
1043 (void) FormatLocaleFile(svg_info->file,
1044 "push gradient '%s' linear %g,%g %g,%g\n",id,
1045 svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
1046 svg_info->segment.y2);
1054 if (LocaleCompare((const char *) name,"path") == 0)
1056 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1059 if (LocaleCompare((const char *) name,"pattern") == 0)
1061 (void) FormatLocaleFile(svg_info->file,
1062 "push pattern '%s' %g,%g %g,%g\n",id,
1063 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.width,
1064 svg_info->bounds.height);
1067 if (LocaleCompare((const char *) name,"polygon") == 0)
1069 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1072 if (LocaleCompare((const char *) name,"polyline") == 0)
1074 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1082 if (LocaleCompare((const char *) name,"radialGradient") == 0)
1084 (void) FormatLocaleFile(svg_info->file,
1085 "push gradient '%s' radial %g,%g %g,%g %g\n",
1086 id,svg_info->element.cx,svg_info->element.cy,
1087 svg_info->element.major,svg_info->element.minor,
1088 svg_info->element.angle);
1091 if (LocaleCompare((const char *) name,"rect") == 0)
1093 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1101 if (LocaleCompare((const char *) name,"svg") == 0)
1103 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1111 if (LocaleCompare((const char *) name,"text") == 0)
1113 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1114 svg_info->bounds.x=0.0;
1115 svg_info->bounds.y=0.0;
1116 svg_info->bounds.width=0.0;
1117 svg_info->bounds.height=0.0;
1120 if (LocaleCompare((const char *) name,"tspan") == 0)
1122 if (*svg_info->text != '\0')
1133 text=EscapeString(svg_info->text,'\'');
1134 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
1135 svg_info->bounds.x-svg_info->center.x,svg_info->bounds.y-
1136 svg_info->center.y,text);
1137 text=DestroyString(text);
1138 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
1139 draw_info->pointsize=svg_info->pointsize;
1140 draw_info->text=AcquireString(svg_info->text);
1141 (void) ConcatenateString(&draw_info->text," ");
1142 (void) GetTypeMetrics(svg_info->image,draw_info,
1143 &metrics,svg_info->exception);
1144 svg_info->bounds.x+=metrics.width;
1145 draw_info=DestroyDrawInfo(draw_info);
1146 *svg_info->text='\0';
1148 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1156 if (attributes != (const xmlChar **) NULL)
1157 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
1159 keyword=(const char *) attributes[i];
1160 value=(const char *) attributes[i+1];
1161 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1162 " %s = %s",keyword,value);
1168 if (LocaleCompare(keyword,"angle") == 0)
1170 (void) FormatLocaleFile(svg_info->file,"angle %g\n",
1171 GetUserSpaceCoordinateValue(svg_info,0,value));
1179 if (LocaleCompare(keyword,"clip-path") == 0)
1181 (void) FormatLocaleFile(svg_info->file,"clip-path '%s'\n",value);
1184 if (LocaleCompare(keyword,"clip-rule") == 0)
1186 (void) FormatLocaleFile(svg_info->file,"clip-rule '%s'\n",value);
1189 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1191 (void) CloneString(&units,value);
1192 (void) FormatLocaleFile(svg_info->file,"clip-units '%s'\n",value);
1195 if (LocaleCompare(keyword,"color") == 0)
1197 (void) CloneString(&color,value);
1200 if (LocaleCompare(keyword,"cx") == 0)
1202 svg_info->element.cx=
1203 GetUserSpaceCoordinateValue(svg_info,1,value);
1206 if (LocaleCompare(keyword,"cy") == 0)
1208 svg_info->element.cy=
1209 GetUserSpaceCoordinateValue(svg_info,-1,value);
1217 if (LocaleCompare(keyword,"d") == 0)
1219 (void) CloneString(&svg_info->vertices,value);
1222 if (LocaleCompare(keyword,"dx") == 0)
1224 svg_info->bounds.x+=GetUserSpaceCoordinateValue(svg_info,1,value);
1227 if (LocaleCompare(keyword,"dy") == 0)
1229 svg_info->bounds.y+=
1230 GetUserSpaceCoordinateValue(svg_info,-1,value);
1238 if (LocaleCompare(keyword,"fill") == 0)
1240 if (LocaleCompare(value,"currentColor") == 0)
1242 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",color);
1245 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",value);
1248 if (LocaleCompare(keyword,"fillcolor") == 0)
1250 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",value);
1253 if (LocaleCompare(keyword,"fill-rule") == 0)
1255 (void) FormatLocaleFile(svg_info->file,"fill-rule '%s'\n",value);
1258 if (LocaleCompare(keyword,"fill-opacity") == 0)
1260 (void) FormatLocaleFile(svg_info->file,"fill-opacity '%s'\n",
1264 if (LocaleCompare(keyword,"font-family") == 0)
1266 (void) FormatLocaleFile(svg_info->file,"font-family '%s'\n",
1270 if (LocaleCompare(keyword,"font-stretch") == 0)
1272 (void) FormatLocaleFile(svg_info->file,"font-stretch '%s'\n",
1276 if (LocaleCompare(keyword,"font-style") == 0)
1278 (void) FormatLocaleFile(svg_info->file,"font-style '%s'\n",value);
1281 if (LocaleCompare(keyword,"font-size") == 0)
1283 if (LocaleCompare(value,"xx-small") == 0)
1284 svg_info->pointsize=6.144;
1285 else if (LocaleCompare(value,"x-small") == 0)
1286 svg_info->pointsize=7.68;
1287 else if (LocaleCompare(value,"small") == 0)
1288 svg_info->pointsize=9.6;
1289 else if (LocaleCompare(value,"medium") == 0)
1290 svg_info->pointsize=12.0;
1291 else if (LocaleCompare(value,"large") == 0)
1292 svg_info->pointsize=14.4;
1293 else if (LocaleCompare(value,"x-large") == 0)
1294 svg_info->pointsize=17.28;
1295 else if (LocaleCompare(value,"xx-large") == 0)
1296 svg_info->pointsize=20.736;
1298 svg_info->pointsize=GetUserSpaceCoordinateValue(svg_info,0,
1300 (void) FormatLocaleFile(svg_info->file,"font-size %g\n",
1301 svg_info->pointsize);
1304 if (LocaleCompare(keyword,"font-weight") == 0)
1306 (void) FormatLocaleFile(svg_info->file,"font-weight '%s'\n",
1315 if (LocaleCompare(keyword,"gradientTransform") == 0)
1322 GetAffineMatrix(&transform);
1323 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1324 tokens=GetTransformTokens(context,value,&number_tokens);
1325 if (tokens == (char **) NULL)
1327 for (j=0; j < (ssize_t) (number_tokens-1); j+=2)
1329 keyword=(char *) tokens[j];
1330 if (keyword == (char *) NULL)
1332 value=(char *) tokens[j+1];
1333 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1334 " %s: %s",keyword,value);
1336 GetAffineMatrix(&affine);
1342 if (LocaleCompare(keyword,"matrix") == 0)
1344 p=(const char *) value;
1345 GetNextToken(p,&p,MagickPathExtent,token);
1346 affine.sx=StringToDouble(value,(char **) NULL);
1347 GetNextToken(p,&p,MagickPathExtent,token);
1349 GetNextToken(p,&p,MagickPathExtent,token);
1350 affine.rx=StringToDouble(token,&next_token);
1351 GetNextToken(p,&p,MagickPathExtent,token);
1353 GetNextToken(p,&p,MagickPathExtent,token);
1354 affine.ry=StringToDouble(token,&next_token);
1355 GetNextToken(p,&p,MagickPathExtent,token);
1357 GetNextToken(p,&p,MagickPathExtent,token);
1358 affine.sy=StringToDouble(token,&next_token);
1359 GetNextToken(p,&p,MagickPathExtent,token);
1361 GetNextToken(p,&p,MagickPathExtent,token);
1362 affine.tx=StringToDouble(token,&next_token);
1363 GetNextToken(p,&p,MagickPathExtent,token);
1365 GetNextToken(p,&p,MagickPathExtent,token);
1366 affine.ty=StringToDouble(token,&next_token);
1374 if (LocaleCompare(keyword,"rotate") == 0)
1379 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1380 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1381 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1382 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1383 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1391 if (LocaleCompare(keyword,"scale") == 0)
1393 for (p=(const char *) value; *p != '\0'; p++)
1394 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1397 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1398 affine.sy=affine.sx;
1401 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1402 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
1405 if (LocaleCompare(keyword,"skewX") == 0)
1407 affine.sx=svg_info->affine.sx;
1408 affine.ry=tan(DegreesToRadians(fmod(
1409 GetUserSpaceCoordinateValue(svg_info,1,value),
1411 affine.sy=svg_info->affine.sy;
1414 if (LocaleCompare(keyword,"skewY") == 0)
1416 affine.sx=svg_info->affine.sx;
1417 affine.rx=tan(DegreesToRadians(fmod(
1418 GetUserSpaceCoordinateValue(svg_info,-1,value),
1420 affine.sy=svg_info->affine.sy;
1428 if (LocaleCompare(keyword,"translate") == 0)
1430 for (p=(const char *) value; *p != '\0'; p++)
1431 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1434 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
1435 affine.ty=affine.tx;
1438 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1446 transform.sx=affine.sx*current.sx+affine.ry*current.rx;
1447 transform.rx=affine.rx*current.sx+affine.sy*current.rx;
1448 transform.ry=affine.sx*current.ry+affine.ry*current.sy;
1449 transform.sy=affine.rx*current.ry+affine.sy*current.sy;
1450 transform.tx=affine.tx*current.sx+affine.ty*current.ry+
1452 transform.ty=affine.tx*current.rx+affine.ty*current.sy+
1455 (void) FormatLocaleFile(svg_info->file,
1456 "affine %g %g %g %g %g %g\n",transform.sx,
1457 transform.rx,transform.ry,transform.sy,transform.tx,
1459 for (j=0; tokens[j] != (char *) NULL; j++)
1460 tokens[j]=DestroyString(tokens[j]);
1461 tokens=(char **) RelinquishMagickMemory(tokens);
1464 if (LocaleCompare(keyword,"gradientUnits") == 0)
1466 (void) CloneString(&units,value);
1467 (void) FormatLocaleFile(svg_info->file,"gradient-units '%s'\n",
1476 if (LocaleCompare(keyword,"height") == 0)
1478 svg_info->bounds.height=
1479 GetUserSpaceCoordinateValue(svg_info,-1,value);
1482 if (LocaleCompare(keyword,"href") == 0)
1484 (void) CloneString(&svg_info->url,value);
1492 if (LocaleCompare(keyword,"major") == 0)
1494 svg_info->element.major=
1495 GetUserSpaceCoordinateValue(svg_info,1,value);
1498 if (LocaleCompare(keyword,"minor") == 0)
1500 svg_info->element.minor=
1501 GetUserSpaceCoordinateValue(svg_info,-1,value);
1509 if (LocaleCompare(keyword,"offset") == 0)
1511 (void) CloneString(&svg_info->offset,value);
1514 if (LocaleCompare(keyword,"opacity") == 0)
1516 (void) FormatLocaleFile(svg_info->file,"opacity '%s'\n",value);
1524 if (LocaleCompare(keyword,"path") == 0)
1526 (void) CloneString(&svg_info->url,value);
1529 if (LocaleCompare(keyword,"points") == 0)
1531 (void) CloneString(&svg_info->vertices,value);
1539 if (LocaleCompare(keyword,"r") == 0)
1541 svg_info->element.major=
1542 GetUserSpaceCoordinateValue(svg_info,1,value);
1543 svg_info->element.minor=
1544 GetUserSpaceCoordinateValue(svg_info,-1,value);
1547 if (LocaleCompare(keyword,"rotate") == 0)
1552 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1553 (void) FormatLocaleFile(svg_info->file,"translate %g,%g\n",
1554 svg_info->bounds.x,svg_info->bounds.y);
1555 svg_info->bounds.x=0;
1556 svg_info->bounds.y=0;
1557 (void) FormatLocaleFile(svg_info->file,"rotate %g\n",angle);
1560 if (LocaleCompare(keyword,"rx") == 0)
1562 if (LocaleCompare((const char *) name,"ellipse") == 0)
1563 svg_info->element.major=
1564 GetUserSpaceCoordinateValue(svg_info,1,value);
1567 GetUserSpaceCoordinateValue(svg_info,1,value);
1570 if (LocaleCompare(keyword,"ry") == 0)
1572 if (LocaleCompare((const char *) name,"ellipse") == 0)
1573 svg_info->element.minor=
1574 GetUserSpaceCoordinateValue(svg_info,-1,value);
1577 GetUserSpaceCoordinateValue(svg_info,-1,value);
1585 if (LocaleCompare(keyword,"stop-color") == 0)
1587 (void) CloneString(&svg_info->stop_color,value);
1590 if (LocaleCompare(keyword,"stroke") == 0)
1592 if (LocaleCompare(value,"currentColor") == 0)
1594 (void) FormatLocaleFile(svg_info->file,"stroke '%s'\n",color);
1597 (void) FormatLocaleFile(svg_info->file,"stroke '%s'\n",value);
1600 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1602 (void) FormatLocaleFile(svg_info->file,"stroke-antialias %d\n",
1603 LocaleCompare(value,"true") == 0);
1606 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1608 (void) FormatLocaleFile(svg_info->file,"stroke-dasharray %s\n",
1612 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1614 (void) FormatLocaleFile(svg_info->file,"stroke-dashoffset %g\n",
1615 GetUserSpaceCoordinateValue(svg_info,1,value));
1618 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1620 (void) FormatLocaleFile(svg_info->file,"stroke-linecap '%s'\n",
1624 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1626 (void) FormatLocaleFile(svg_info->file,"stroke-linejoin '%s'\n",
1630 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1632 (void) FormatLocaleFile(svg_info->file,"stroke-miterlimit '%s'\n",
1636 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1638 (void) FormatLocaleFile(svg_info->file,"stroke-opacity '%s'\n",
1642 if (LocaleCompare(keyword,"stroke-width") == 0)
1644 (void) FormatLocaleFile(svg_info->file,"stroke-width %g\n",
1645 GetUserSpaceCoordinateValue(svg_info,1,value));
1648 if (LocaleCompare(keyword,"style") == 0)
1650 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1651 tokens=GetStyleTokens(context,value,&number_tokens);
1652 for (j=0; j < (ssize_t) (number_tokens-1); j+=2)
1654 keyword=(char *) tokens[j];
1655 value=(char *) tokens[j+1];
1656 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1657 " %s: %s",keyword,value);
1663 if (LocaleCompare(keyword,"clip-path") == 0)
1665 (void) FormatLocaleFile(svg_info->file,
1666 "clip-path '%s'\n",value);
1669 if (LocaleCompare(keyword,"clip-rule") == 0)
1671 (void) FormatLocaleFile(svg_info->file,
1672 "clip-rule '%s'\n",value);
1675 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1677 (void) CloneString(&units,value);
1678 (void) FormatLocaleFile(svg_info->file,
1679 "clip-units '%s'\n",value);
1682 if (LocaleCompare(keyword,"color") == 0)
1684 (void) CloneString(&color,value);
1692 if (LocaleCompare(keyword,"fill") == 0)
1694 if (LocaleCompare(value,"currentColor") == 0)
1696 (void) FormatLocaleFile(svg_info->file,
1697 "fill '%s'\n",color);
1700 if (LocaleCompare(value,"#000000ff") == 0)
1701 (void) FormatLocaleFile(svg_info->file,
1702 "fill '#000000'\n");
1704 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",
1708 if (LocaleCompare(keyword,"fillcolor") == 0)
1710 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",
1714 if (LocaleCompare(keyword,"fill-rule") == 0)
1716 (void) FormatLocaleFile(svg_info->file,
1717 "fill-rule '%s'\n",value);
1720 if (LocaleCompare(keyword,"fill-opacity") == 0)
1722 (void) FormatLocaleFile(svg_info->file,
1723 "fill-opacity '%s'\n",value);
1726 if (LocaleCompare(keyword,"font-family") == 0)
1728 (void) FormatLocaleFile(svg_info->file,
1729 "font-family '%s'\n",value);
1732 if (LocaleCompare(keyword,"font-stretch") == 0)
1734 (void) FormatLocaleFile(svg_info->file,
1735 "font-stretch '%s'\n",value);
1738 if (LocaleCompare(keyword,"font-style") == 0)
1740 (void) FormatLocaleFile(svg_info->file,
1741 "font-style '%s'\n",value);
1744 if (LocaleCompare(keyword,"font-size") == 0)
1746 svg_info->pointsize=GetUserSpaceCoordinateValue(
1748 (void) FormatLocaleFile(svg_info->file,"font-size %g\n",
1749 svg_info->pointsize);
1752 if (LocaleCompare(keyword,"font-weight") == 0)
1754 (void) FormatLocaleFile(svg_info->file,
1755 "font-weight '%s'\n",value);
1763 if (LocaleCompare(keyword,"offset") == 0)
1765 (void) FormatLocaleFile(svg_info->file,"offset %g\n",
1766 GetUserSpaceCoordinateValue(svg_info,1,value));
1769 if (LocaleCompare(keyword,"opacity") == 0)
1771 (void) FormatLocaleFile(svg_info->file,
1772 "opacity '%s'\n",value);
1780 if (LocaleCompare(keyword,"stop-color") == 0)
1782 (void) CloneString(&svg_info->stop_color,value);
1785 if (LocaleCompare(keyword,"stroke") == 0)
1787 if (LocaleCompare(value,"currentColor") == 0)
1789 (void) FormatLocaleFile(svg_info->file,
1790 "stroke '%s'\n",color);
1793 if (LocaleCompare(value,"#000000ff") == 0)
1794 (void) FormatLocaleFile(svg_info->file,
1795 "fill '#000000'\n");
1797 (void) FormatLocaleFile(svg_info->file,
1798 "stroke '%s'\n",value);
1801 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1803 (void) FormatLocaleFile(svg_info->file,
1804 "stroke-antialias %d\n",
1805 LocaleCompare(value,"true") == 0);
1808 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1810 (void) FormatLocaleFile(svg_info->file,
1811 "stroke-dasharray %s\n",value);
1814 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1816 (void) FormatLocaleFile(svg_info->file,
1817 "stroke-dashoffset %g\n",
1818 GetUserSpaceCoordinateValue(svg_info,1,value));
1821 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1823 (void) FormatLocaleFile(svg_info->file,
1824 "stroke-linecap '%s'\n",value);
1827 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1829 (void) FormatLocaleFile(svg_info->file,
1830 "stroke-linejoin '%s'\n",value);
1833 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1835 (void) FormatLocaleFile(svg_info->file,
1836 "stroke-miterlimit '%s'\n",value);
1839 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1841 (void) FormatLocaleFile(svg_info->file,
1842 "stroke-opacity '%s'\n",value);
1845 if (LocaleCompare(keyword,"stroke-width") == 0)
1847 (void) FormatLocaleFile(svg_info->file,
1848 "stroke-width %g\n",
1849 GetUserSpaceCoordinateValue(svg_info,1,value));
1857 if (LocaleCompare(keyword,"text-align") == 0)
1859 (void) FormatLocaleFile(svg_info->file,
1860 "text-align '%s'\n",value);
1863 if (LocaleCompare(keyword,"text-anchor") == 0)
1865 (void) FormatLocaleFile(svg_info->file,
1866 "text-anchor '%s'\n",value);
1869 if (LocaleCompare(keyword,"text-decoration") == 0)
1871 if (LocaleCompare(value,"underline") == 0)
1872 (void) FormatLocaleFile(svg_info->file,
1873 "decorate underline\n");
1874 if (LocaleCompare(value,"line-through") == 0)
1875 (void) FormatLocaleFile(svg_info->file,
1876 "decorate line-through\n");
1877 if (LocaleCompare(value,"overline") == 0)
1878 (void) FormatLocaleFile(svg_info->file,
1879 "decorate overline\n");
1882 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1884 (void) FormatLocaleFile(svg_info->file,
1885 "text-antialias %d\n",
1886 LocaleCompare(value,"true") == 0);
1895 for (j=0; tokens[j] != (char *) NULL; j++)
1896 tokens[j]=DestroyString(tokens[j]);
1897 tokens=(char **) RelinquishMagickMemory(tokens);
1905 if (LocaleCompare(keyword,"text-align") == 0)
1907 (void) FormatLocaleFile(svg_info->file,"text-align '%s'\n",
1911 if (LocaleCompare(keyword,"text-anchor") == 0)
1913 (void) FormatLocaleFile(svg_info->file,"text-anchor '%s'\n",
1917 if (LocaleCompare(keyword,"text-decoration") == 0)
1919 if (LocaleCompare(value,"underline") == 0)
1920 (void) FormatLocaleFile(svg_info->file,"decorate underline\n");
1921 if (LocaleCompare(value,"line-through") == 0)
1922 (void) FormatLocaleFile(svg_info->file,
1923 "decorate line-through\n");
1924 if (LocaleCompare(value,"overline") == 0)
1925 (void) FormatLocaleFile(svg_info->file,"decorate overline\n");
1928 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1930 (void) FormatLocaleFile(svg_info->file,"text-antialias %d\n",
1931 LocaleCompare(value,"true") == 0);
1934 if (LocaleCompare(keyword,"transform") == 0)
1941 GetAffineMatrix(&transform);
1942 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1943 tokens=GetTransformTokens(context,value,&number_tokens);
1944 if (tokens == (char **) NULL)
1946 for (j=0; j < (ssize_t) (number_tokens-1); j+=2)
1948 keyword=(char *) tokens[j];
1949 value=(char *) tokens[j+1];
1950 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1951 " %s: %s",keyword,value);
1953 GetAffineMatrix(&affine);
1959 if (LocaleCompare(keyword,"matrix") == 0)
1961 p=(const char *) value;
1962 GetNextToken(p,&p,MagickPathExtent,token);
1963 affine.sx=StringToDouble(value,(char **) NULL);
1964 GetNextToken(p,&p,MagickPathExtent,token);
1966 GetNextToken(p,&p,MagickPathExtent,token);
1967 affine.rx=StringToDouble(token,&next_token);
1968 GetNextToken(p,&p,MagickPathExtent,token);
1970 GetNextToken(p,&p,MagickPathExtent,token);
1971 affine.ry=StringToDouble(token,&next_token);
1972 GetNextToken(p,&p,MagickPathExtent,token);
1974 GetNextToken(p,&p,MagickPathExtent,token);
1975 affine.sy=StringToDouble(token,&next_token);
1976 GetNextToken(p,&p,MagickPathExtent,token);
1978 GetNextToken(p,&p,MagickPathExtent,token);
1979 affine.tx=StringToDouble(token,&next_token);
1980 GetNextToken(p,&p,MagickPathExtent,token);
1982 GetNextToken(p,&p,MagickPathExtent,token);
1983 affine.ty=StringToDouble(token,&next_token);
1991 if (LocaleCompare(keyword,"rotate") == 0)
1998 p=(const char *) value;
1999 GetNextToken(p,&p,MagickPathExtent,token);
2000 angle=StringToDouble(value,(char **) NULL);
2001 GetNextToken(p,&p,MagickPathExtent,token);
2003 GetNextToken(p,&p,MagickPathExtent,token);
2004 x=StringToDouble(token,&next_token);
2005 GetNextToken(p,&p,MagickPathExtent,token);
2007 GetNextToken(p,&p,MagickPathExtent,token);
2008 y=StringToDouble(token,&next_token);
2009 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
2010 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
2011 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
2012 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
2015 svg_info->center.x=x;
2016 svg_info->center.y=y;
2024 if (LocaleCompare(keyword,"scale") == 0)
2026 for (p=(const char *) value; *p != '\0'; p++)
2027 if ((isspace((int) ((unsigned char) *p)) != 0) ||
2030 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
2031 affine.sy=affine.sx;
2033 affine.sy=GetUserSpaceCoordinateValue(svg_info,-1,
2035 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
2038 if (LocaleCompare(keyword,"skewX") == 0)
2040 affine.sx=svg_info->affine.sx;
2041 affine.ry=tan(DegreesToRadians(fmod(
2042 GetUserSpaceCoordinateValue(svg_info,1,value),
2044 affine.sy=svg_info->affine.sy;
2047 if (LocaleCompare(keyword,"skewY") == 0)
2049 affine.sx=svg_info->affine.sx;
2050 affine.rx=tan(DegreesToRadians(fmod(
2051 GetUserSpaceCoordinateValue(svg_info,-1,value),
2053 affine.sy=svg_info->affine.sy;
2061 if (LocaleCompare(keyword,"translate") == 0)
2063 for (p=(const char *) value; *p != '\0'; p++)
2064 if ((isspace((int) ((unsigned char) *p)) != 0) ||
2067 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
2068 affine.ty=affine.tx;
2070 affine.ty=GetUserSpaceCoordinateValue(svg_info,-1,
2079 transform.sx=affine.sx*current.sx+affine.ry*current.rx;
2080 transform.rx=affine.rx*current.sx+affine.sy*current.rx;
2081 transform.ry=affine.sx*current.ry+affine.ry*current.sy;
2082 transform.sy=affine.rx*current.ry+affine.sy*current.sy;
2083 transform.tx=affine.tx*current.sx+affine.ty*current.ry+
2085 transform.ty=affine.tx*current.rx+affine.ty*current.sy+
2088 (void) FormatLocaleFile(svg_info->file,
2089 "affine %g %g %g %g %g %g\n",transform.sx,transform.rx,
2090 transform.ry,transform.sy,transform.tx,transform.ty);
2091 for (j=0; tokens[j] != (char *) NULL; j++)
2092 tokens[j]=DestroyString(tokens[j]);
2093 tokens=(char **) RelinquishMagickMemory(tokens);
2101 if (LocaleCompare(keyword,"verts") == 0)
2103 (void) CloneString(&svg_info->vertices,value);
2106 if (LocaleCompare(keyword,"viewBox") == 0)
2108 p=(const char *) value;
2109 GetNextToken(p,&p,MagickPathExtent,token);
2110 svg_info->view_box.x=StringToDouble(token,&next_token);
2111 GetNextToken(p,&p,MagickPathExtent,token);
2113 GetNextToken(p,&p,MagickPathExtent,token);
2114 svg_info->view_box.y=StringToDouble(token,&next_token);
2115 GetNextToken(p,&p,MagickPathExtent,token);
2117 GetNextToken(p,&p,MagickPathExtent,token);
2118 svg_info->view_box.width=StringToDouble(token,
2120 if (svg_info->bounds.width == 0)
2121 svg_info->bounds.width=svg_info->view_box.width;
2122 GetNextToken(p,&p,MagickPathExtent,token);
2124 GetNextToken(p,&p,MagickPathExtent,token);
2125 svg_info->view_box.height=StringToDouble(token,
2127 if (svg_info->bounds.height == 0)
2128 svg_info->bounds.height=svg_info->view_box.height;
2136 if (LocaleCompare(keyword,"width") == 0)
2138 svg_info->bounds.width=
2139 GetUserSpaceCoordinateValue(svg_info,1,value);
2147 if (LocaleCompare(keyword,"x") == 0)
2149 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value);
2152 if (LocaleCompare(keyword,"xlink:href") == 0)
2154 (void) CloneString(&svg_info->url,value);
2157 if (LocaleCompare(keyword,"x1") == 0)
2159 svg_info->segment.x1=
2160 GetUserSpaceCoordinateValue(svg_info,1,value);
2163 if (LocaleCompare(keyword,"x2") == 0)
2165 svg_info->segment.x2=
2166 GetUserSpaceCoordinateValue(svg_info,1,value);
2174 if (LocaleCompare(keyword,"y") == 0)
2176 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value);
2179 if (LocaleCompare(keyword,"y1") == 0)
2181 svg_info->segment.y1=
2182 GetUserSpaceCoordinateValue(svg_info,-1,value);
2185 if (LocaleCompare(keyword,"y2") == 0)
2187 svg_info->segment.y2=
2188 GetUserSpaceCoordinateValue(svg_info,-1,value);
2197 if (LocaleCompare((const char *) name,"svg") == 0)
2199 if (svg_info->document->encoding != (const xmlChar *) NULL)
2200 (void) FormatLocaleFile(svg_info->file,"encoding \"%s\"\n",
2201 (const char *) svg_info->document->encoding);
2202 if (attributes != (const xmlChar **) NULL)
2210 if ((svg_info->view_box.width == 0.0) ||
2211 (svg_info->view_box.height == 0.0))
2212 svg_info->view_box=svg_info->bounds;
2214 if (svg_info->bounds.width > 0.0)
2215 svg_info->width=(size_t) floor(svg_info->bounds.width+0.5);
2217 if (svg_info->bounds.height > 0.0)
2218 svg_info->height=(size_t) floor(svg_info->bounds.height+0.5);
2219 (void) FormatLocaleFile(svg_info->file,"viewbox 0 0 %.20g %.20g\n",
2220 (double) svg_info->width,(double) svg_info->height);
2221 sx=(double) svg_info->width/svg_info->view_box.width;
2222 sy=(double) svg_info->height/svg_info->view_box.height;
2223 tx=svg_info->view_box.x != 0.0 ? (double) -sx*svg_info->view_box.x :
2225 ty=svg_info->view_box.y != 0.0 ? (double) -sy*svg_info->view_box.y :
2227 (void) FormatLocaleFile(svg_info->file,"affine %g 0 0 %g %g %g\n",
2231 (void) LogMagickEvent(CoderEvent,GetMagickModule()," )");
2232 units=DestroyString(units);
2233 if (color != (char *) NULL)
2234 color=DestroyString(color);
2237 static void SVGEndElement(void *context,const xmlChar *name)
2243 Called when the end of an element has been detected.
2245 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2246 " SAX.endElement(%s)",name);
2247 svg_info=(SVGInfo *) context;
2248 if (strchr((char *) name,':') != (char *) NULL)
2251 Skip over namespace.
2253 for ( ; *name != ':'; name++) ;
2261 if (LocaleCompare((const char *) name,"circle") == 0)
2263 (void) FormatLocaleFile(svg_info->file,"circle %g,%g %g,%g\n",
2264 svg_info->element.cx,svg_info->element.cy,svg_info->element.cx,
2265 svg_info->element.cy+svg_info->element.minor);
2266 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2269 if (LocaleCompare((const char *) name,"clipPath") == 0)
2271 (void) FormatLocaleFile(svg_info->file,"pop clip-path\n");
2279 if (LocaleCompare((const char *) name,"defs") == 0)
2281 (void) FormatLocaleFile(svg_info->file,"pop defs\n");
2284 if (LocaleCompare((const char *) name,"desc") == 0)
2289 if (*svg_info->text == '\0')
2291 (void) fputc('#',svg_info->file);
2292 for (p=svg_info->text; *p != '\0'; p++)
2294 (void) fputc(*p,svg_info->file);
2296 (void) fputc('#',svg_info->file);
2298 (void) fputc('\n',svg_info->file);
2299 *svg_info->text='\0';
2307 if (LocaleCompare((const char *) name,"ellipse") == 0)
2312 angle=svg_info->element.angle;
2313 (void) FormatLocaleFile(svg_info->file,"ellipse %g,%g %g,%g 0,360\n",
2314 svg_info->element.cx,svg_info->element.cy,
2315 angle == 0.0 ? svg_info->element.major : svg_info->element.minor,
2316 angle == 0.0 ? svg_info->element.minor : svg_info->element.major);
2317 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2325 if (LocaleCompare((const char *) name,"g") == 0)
2327 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2335 if (LocaleCompare((const char *) name,"image") == 0)
2337 (void) FormatLocaleFile(svg_info->file,
2338 "image Over %g,%g %g,%g '%s'\n",svg_info->bounds.x,
2339 svg_info->bounds.y,svg_info->bounds.width,svg_info->bounds.height,
2341 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2349 if (LocaleCompare((const char *) name,"line") == 0)
2351 (void) FormatLocaleFile(svg_info->file,"line %g,%g %g,%g\n",
2352 svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
2353 svg_info->segment.y2);
2354 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2357 if (LocaleCompare((const char *) name,"linearGradient") == 0)
2359 (void) FormatLocaleFile(svg_info->file,"pop gradient\n");
2367 if (LocaleCompare((const char *) name,"pattern") == 0)
2369 (void) FormatLocaleFile(svg_info->file,"pop pattern\n");
2372 if (LocaleCompare((const char *) name,"path") == 0)
2374 (void) FormatLocaleFile(svg_info->file,"path '%s'\n",
2375 svg_info->vertices);
2376 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2379 if (LocaleCompare((const char *) name,"polygon") == 0)
2381 (void) FormatLocaleFile(svg_info->file,"polygon %s\n",
2382 svg_info->vertices);
2383 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2386 if (LocaleCompare((const char *) name,"polyline") == 0)
2388 (void) FormatLocaleFile(svg_info->file,"polyline %s\n",
2389 svg_info->vertices);
2390 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2398 if (LocaleCompare((const char *) name,"radialGradient") == 0)
2400 (void) FormatLocaleFile(svg_info->file,"pop gradient\n");
2403 if (LocaleCompare((const char *) name,"rect") == 0)
2405 if ((svg_info->radius.x == 0.0) && (svg_info->radius.y == 0.0))
2407 (void) FormatLocaleFile(svg_info->file,"rectangle %g,%g %g,%g\n",
2408 svg_info->bounds.x,svg_info->bounds.y,
2409 svg_info->bounds.x+svg_info->bounds.width,
2410 svg_info->bounds.y+svg_info->bounds.height);
2411 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2414 if (svg_info->radius.x == 0.0)
2415 svg_info->radius.x=svg_info->radius.y;
2416 if (svg_info->radius.y == 0.0)
2417 svg_info->radius.y=svg_info->radius.x;
2418 (void) FormatLocaleFile(svg_info->file,
2419 "roundRectangle %g,%g %g,%g %g,%g\n",
2420 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.x+
2421 svg_info->bounds.width,svg_info->bounds.y+svg_info->bounds.height,
2422 svg_info->radius.x,svg_info->radius.y);
2423 svg_info->radius.x=0.0;
2424 svg_info->radius.y=0.0;
2425 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2433 if (LocaleCompare((const char *) name,"stop") == 0)
2435 (void) FormatLocaleFile(svg_info->file,"stop-color '%s' %s\n",
2436 svg_info->stop_color,svg_info->offset);
2439 if (LocaleCompare((const char *) name,"svg") == 0)
2441 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2449 if (LocaleCompare((const char *) name,"text") == 0)
2451 if (*svg_info->text != '\0')
2456 text=EscapeString(svg_info->text,'\'');
2457 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
2458 svg_info->bounds.x,svg_info->bounds.y,text);
2459 text=DestroyString(text);
2460 *svg_info->text='\0';
2462 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2465 if (LocaleCompare((const char *) name,"tspan") == 0)
2467 if (*svg_info->text != '\0')
2478 text=EscapeString(svg_info->text,'\'');
2479 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
2480 svg_info->bounds.x,svg_info->bounds.y,text);
2481 text=DestroyString(text);
2482 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
2483 draw_info->pointsize=svg_info->pointsize;
2484 draw_info->text=AcquireString(svg_info->text);
2485 (void) ConcatenateString(&draw_info->text," ");
2486 (void) GetTypeMetrics(svg_info->image,draw_info,&metrics,
2487 svg_info->exception);
2488 svg_info->bounds.x+=metrics.width;
2489 draw_info=DestroyDrawInfo(draw_info);
2490 *svg_info->text='\0';
2492 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2495 if (LocaleCompare((const char *) name,"title") == 0)
2497 if (*svg_info->text == '\0')
2499 (void) CloneString(&svg_info->title,svg_info->text);
2500 *svg_info->text='\0';
2508 *svg_info->text='\0';
2509 (void) ResetMagickMemory(&svg_info->element,0,sizeof(svg_info->element));
2510 (void) ResetMagickMemory(&svg_info->segment,0,sizeof(svg_info->segment));
2514 static void SVGCharacters(void *context,const xmlChar *c,int length)
2529 Receiving some characters from the parser.
2531 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2532 " SAX.characters(%s,%.20g)",c,(double) length);
2533 svg_info=(SVGInfo *) context;
2534 text=(char *) AcquireQuantumMemory(length+1,sizeof(*text));
2535 if (text == (char *) NULL)
2538 for (i=0; i < (ssize_t) length; i++)
2542 if (svg_info->text == (char *) NULL)
2543 svg_info->text=text;
2546 (void) ConcatenateString(&svg_info->text,text);
2547 text=DestroyString(text);
2551 static void SVGReference(void *context,const xmlChar *name)
2560 Called when an entity reference is detected.
2562 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.reference(%s)",
2564 svg_info=(SVGInfo *) context;
2565 parser=svg_info->parser;
2566 if (parser == (xmlParserCtxtPtr) NULL)
2568 if (parser->node == (xmlNodePtr) NULL)
2571 (void) xmlAddChild(parser->node,xmlNewCharRef(svg_info->document,name));
2573 (void) xmlAddChild(parser->node,xmlNewReference(svg_info->document,name));
2576 static void SVGIgnorableWhitespace(void *context,const xmlChar *c,int length)
2582 Receiving some ignorable whitespaces from the parser.
2584 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2585 " SAX.ignorableWhitespace(%.30s, %d)",c,length);
2586 svg_info=(SVGInfo *) context;
2590 static void SVGProcessingInstructions(void *context,const xmlChar *target,
2591 const xmlChar *data)
2597 A processing instruction has been parsed.
2599 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2600 " SAX.processingInstruction(%s, %s)",target,data);
2601 svg_info=(SVGInfo *) context;
2605 static void SVGComment(void *context,const xmlChar *value)
2611 A comment has been parsed.
2613 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.comment(%s)",
2615 svg_info=(SVGInfo *) context;
2616 if (svg_info->comment != (char *) NULL)
2617 (void) ConcatenateString(&svg_info->comment,"\n");
2618 (void) ConcatenateString(&svg_info->comment,(const char *) value);
2621 static void SVGWarning(void *context,const char *format,...)
2625 reason[MagickPathExtent];
2634 Display and format a warning messages, gives file, line, position and
2637 va_start(operands,format);
2638 svg_info=(SVGInfo *) context;
2639 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.warning: ");
2640 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2641 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2642 (void) vsprintf(reason,format,operands);
2644 (void) vsnprintf(reason,MagickPathExtent,format,operands);
2646 message=GetExceptionMessage(errno);
2647 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
2648 DelegateWarning,reason,"`%s`",message);
2649 message=DestroyString(message);
2653 static void SVGError(void *context,const char *format,...)
2657 reason[MagickPathExtent];
2666 Display and format a error formats, gives file, line, position and
2669 va_start(operands,format);
2670 svg_info=(SVGInfo *) context;
2671 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.error: ");
2672 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2673 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2674 (void) vsprintf(reason,format,operands);
2676 (void) vsnprintf(reason,MagickPathExtent,format,operands);
2678 message=GetExceptionMessage(errno);
2679 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),CoderError,
2680 reason,"`%s`",message);
2681 message=DestroyString(message);
2685 static void SVGCDataBlock(void *context,const xmlChar *value,int length)
2697 Called when a pcdata block has been parsed.
2699 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.pcdata(%s, %d)",
2701 svg_info=(SVGInfo *) context;
2702 parser=svg_info->parser;
2703 child=xmlGetLastChild(parser->node);
2704 if ((child != (xmlNodePtr) NULL) && (child->type == XML_CDATA_SECTION_NODE))
2706 xmlTextConcat(child,value,length);
2709 (void) xmlAddChild(parser->node,xmlNewCDataBlock(parser->myDoc,value,length));
2712 static void SVGExternalSubset(void *context,const xmlChar *name,
2713 const xmlChar *external_id,const xmlChar *system_id)
2728 Does this document has an external subset?
2730 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2731 " SAX.externalSubset(%s, %s, %s)",name,
2732 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
2733 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
2734 svg_info=(SVGInfo *) context;
2735 parser=svg_info->parser;
2736 if (((external_id == NULL) && (system_id == NULL)) ||
2737 ((parser->validate == 0) || (parser->wellFormed == 0) ||
2738 (svg_info->document == 0)))
2740 input=SVGResolveEntity(context,external_id,system_id);
2743 (void) xmlNewDtd(svg_info->document,name,external_id,system_id);
2744 parser_context=(*parser);
2745 parser->inputTab=(xmlParserInputPtr *) xmlMalloc(5*sizeof(*parser->inputTab));
2746 if (parser->inputTab == (xmlParserInputPtr *) NULL)
2748 parser->errNo=XML_ERR_NO_MEMORY;
2749 parser->input=parser_context.input;
2750 parser->inputNr=parser_context.inputNr;
2751 parser->inputMax=parser_context.inputMax;
2752 parser->inputTab=parser_context.inputTab;
2758 xmlPushInput(parser,input);
2759 (void) xmlSwitchEncoding(parser,xmlDetectCharEncoding(parser->input->cur,4));
2760 if (input->filename == (char *) NULL)
2761 input->filename=(char *) xmlStrdup(system_id);
2764 input->base=parser->input->cur;
2765 input->cur=parser->input->cur;
2767 xmlParseExternalSubset(parser,external_id,system_id);
2768 while (parser->inputNr > 1)
2769 (void) xmlPopInput(parser);
2770 xmlFreeInputStream(parser->input);
2771 xmlFree(parser->inputTab);
2772 parser->input=parser_context.input;
2773 parser->inputNr=parser_context.inputNr;
2774 parser->inputMax=parser_context.inputMax;
2775 parser->inputTab=parser_context.inputTab;
2778 #if defined(__cplusplus) || defined(c_plusplus)
2783 Static declarations.
2786 SVGDensityGeometry[] = "96.0x96.0";
2789 static Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
2792 filename[MagickPathExtent];
2811 message[MagickPathExtent];
2822 assert(image_info != (const ImageInfo *) NULL);
2823 assert(image_info->signature == MagickCoreSignature);
2824 assert(exception != (ExceptionInfo *) NULL);
2825 if (image_info->debug != MagickFalse)
2826 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2827 image_info->filename);
2828 assert(exception->signature == MagickCoreSignature);
2829 image=AcquireImage(image_info,exception);
2830 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2831 if (status == MagickFalse)
2833 image=DestroyImageList(image);
2834 return((Image *) NULL);
2836 if ((fabs(image->resolution.x) < MagickEpsilon) ||
2837 (fabs(image->resolution.y) < MagickEpsilon))
2845 flags=ParseGeometry(SVGDensityGeometry,&geometry_info);
2846 image->resolution.x=geometry_info.rho;
2847 image->resolution.y=geometry_info.sigma;
2848 if ((flags & SigmaValue) == 0)
2849 image->resolution.y=image->resolution.x;
2851 if (LocaleCompare(image_info->magick,"MSVG") != 0)
2856 delegate_info=GetDelegateInfo("svg:decode",(char *) NULL,exception);
2857 if (delegate_info != (const DelegateInfo *) NULL)
2860 background[MagickPathExtent],
2861 command[MagickPathExtent],
2863 input_filename[MagickPathExtent],
2864 opacity[MagickPathExtent],
2865 output_filename[MagickPathExtent],
2866 unique[MagickPathExtent];
2875 Our best hope of compliance with the SVG standard.
2877 status=AcquireUniqueSymbolicLink(image->filename,input_filename);
2878 (void) AcquireUniqueFilename(output_filename);
2879 (void) AcquireUniqueFilename(unique);
2880 density=AcquireString("");
2881 (void) FormatLocaleString(density,MagickPathExtent,"%.20g,%.20g",
2882 image->resolution.x,image->resolution.y);
2883 (void) FormatLocaleString(background,MagickPathExtent,
2884 "rgb(%.20g%%,%.20g%%,%.20g%%)",
2885 100.0*QuantumScale*image->background_color.red,
2886 100.0*QuantumScale*image->background_color.green,
2887 100.0*QuantumScale*image->background_color.blue);
2888 (void) FormatLocaleString(opacity,MagickPathExtent,"%.20g",
2889 QuantumScale*image->background_color.alpha);
2890 (void) FormatLocaleString(command,MagickPathExtent,
2891 GetDelegateCommands(delegate_info),input_filename,output_filename,
2892 density,background,opacity,unique);
2893 density=DestroyString(density);
2894 status=ExternalDelegateCommand(MagickFalse,image_info->verbose,
2895 command,(char *) NULL,exception);
2896 (void) RelinquishUniqueFileResource(unique);
2897 (void) RelinquishUniqueFileResource(input_filename);
2898 if ((status == 0) && (stat(output_filename,&attributes) == 0) &&
2899 (attributes.st_size > 0))
2907 read_info=CloneImageInfo(image_info);
2908 (void) CopyMagickString(read_info->filename,output_filename,
2910 svg_image=ReadImage(read_info,exception);
2911 read_info=DestroyImageInfo(read_info);
2912 (void) RelinquishUniqueFileResource(output_filename);
2913 if (svg_image != (Image *) NULL)
2915 image=DestroyImage(image);
2919 (void) RelinquishUniqueFileResource(output_filename);
2922 #if defined(MAGICKCORE_RSVG_DELEGATE)
2923 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2936 register unsigned char
2949 register const guchar
2971 svg_handle=rsvg_handle_new();
2972 if (svg_handle == (RsvgHandle *) NULL)
2973 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2974 rsvg_handle_set_base_uri(svg_handle,image_info->filename);
2975 if ((fabs(image->resolution.x) > MagickEpsilon) &&
2976 (fabs(image->resolution.y) > MagickEpsilon))
2977 rsvg_handle_set_dpi_x_y(svg_handle,image->resolution.x,
2978 image->resolution.y);
2979 while ((n=ReadBlob(image,MagickPathExtent-1,message)) != 0)
2982 error=(GError *) NULL;
2983 (void) rsvg_handle_write(svg_handle,message,n,&error);
2984 if (error != (GError *) NULL)
2985 g_error_free(error);
2987 error=(GError *) NULL;
2988 rsvg_handle_close(svg_handle,&error);
2989 if (error != (GError *) NULL)
2990 g_error_free(error);
2991 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2992 apply_density=MagickTrue;
2993 rsvg_handle_get_dimensions(svg_handle,&dimension_info);
2994 if ((image->resolution.x > 0.0) && (image->resolution.y > 0.0))
3000 We should not apply the density when the internal 'factor' is 'i'.
3001 This can be checked by using the trick below.
3003 rsvg_handle_set_dpi_x_y(svg_handle,image->resolution.x*256,
3004 image->resolution.y*256);
3005 rsvg_handle_get_dimensions(svg_handle,&dpi_dimension_info);
3006 if ((dpi_dimension_info.width != dimension_info.width) ||
3007 (dpi_dimension_info.height != dimension_info.height))
3008 apply_density=MagickFalse;
3009 rsvg_handle_set_dpi_x_y(svg_handle,image->resolution.x,
3010 image->resolution.y);
3012 if (image_info->size != (char *) NULL)
3014 (void) GetGeometry(image_info->size,(ssize_t *) NULL,
3015 (ssize_t *) NULL,&image->columns,&image->rows);
3016 if ((image->columns != 0) || (image->rows != 0))
3018 image->resolution.x=96.0*image->columns/dimension_info.width;
3019 image->resolution.y=96.0*image->rows/dimension_info.height;
3020 if (fabs(image->resolution.x) < MagickEpsilon)
3021 image->resolution.x=image->resolution.y;
3023 if (fabs(image->resolution.y) < MagickEpsilon)
3024 image->resolution.y=image->resolution.x;
3026 image->resolution.x=image->resolution.y=MagickMin(
3027 image->resolution.x,image->resolution.y);
3028 apply_density=MagickTrue;
3031 if (apply_density != MagickFalse)
3033 image->columns=image->resolution.x*dimension_info.width/96.0;
3034 image->rows=image->resolution.y*dimension_info.height/96.0;
3038 image->columns=dimension_info.width;
3039 image->rows=dimension_info.height;
3041 pixel_info=(MemoryInfo *) NULL;
3043 pixel_buffer=rsvg_handle_get_pixbuf(svg_handle);
3044 rsvg_handle_free(svg_handle);
3045 image->columns=gdk_pixbuf_get_width(pixel_buffer);
3046 image->rows=gdk_pixbuf_get_height(pixel_buffer);
3048 image->alpha_trait=BlendPixelTrait;
3049 status=SetImageExtent(image,image->columns,image->rows,exception);
3050 if (status == MagickFalse)
3052 #if !defined(MAGICKCORE_CAIRO_DELEGATE)
3053 g_object_unref(G_OBJECT(pixel_buffer));
3055 g_object_unref(svg_handle);
3056 ThrowReaderException(MissingDelegateError,
3057 "NoDecodeDelegateForThisImageFormat");
3059 if (image_info->ping == MagickFalse)
3061 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3065 stride=4*image->columns;
3066 #if defined(MAGICKCORE_PANGOCAIRO_DELEGATE)
3067 stride=(size_t) cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32,
3068 (int) image->columns);
3070 pixel_info=AcquireVirtualMemory(stride,image->rows*sizeof(*pixels));
3071 if (pixel_info == (MemoryInfo *) NULL)
3073 g_object_unref(svg_handle);
3074 ThrowReaderException(ResourceLimitError,
3075 "MemoryAllocationFailed");
3077 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
3079 (void) SetImageBackgroundColor(image,exception);
3080 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3081 cairo_surface=cairo_image_surface_create_for_data(pixels,
3082 CAIRO_FORMAT_ARGB32,(int) image->columns,(int) image->rows,(int)
3084 if ((cairo_surface == (cairo_surface_t *) NULL) ||
3085 (cairo_surface_status(cairo_surface) != CAIRO_STATUS_SUCCESS))
3087 if (cairo_surface != (cairo_surface_t *) NULL)
3088 cairo_surface_destroy(cairo_surface);
3089 pixel_info=RelinquishVirtualMemory(pixel_info);
3090 g_object_unref(svg_handle);
3091 ThrowReaderException(ResourceLimitError,
3092 "MemoryAllocationFailed");
3094 cairo_image=cairo_create(cairo_surface);
3095 cairo_set_operator(cairo_image,CAIRO_OPERATOR_CLEAR);
3096 cairo_paint(cairo_image);
3097 cairo_set_operator(cairo_image,CAIRO_OPERATOR_OVER);
3098 if (apply_density != MagickFalse)
3099 cairo_scale(cairo_image,image->resolution.x/96.0,
3100 image->resolution.y/96.0);
3101 rsvg_handle_render_cairo(svg_handle,cairo_image);
3102 cairo_destroy(cairo_image);
3103 cairo_surface_destroy(cairo_surface);
3104 g_object_unref(svg_handle);
3107 p=gdk_pixbuf_get_pixels(pixel_buffer);
3109 GetPixelInfo(image,&fill_color);
3110 for (y=0; y < (ssize_t) image->rows; y++)
3112 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3113 if (q == (Quantum *) NULL)
3115 for (x=0; x < (ssize_t) image->columns; x++)
3117 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3118 fill_color.blue=ScaleCharToQuantum(*p++);
3119 fill_color.green=ScaleCharToQuantum(*p++);
3120 fill_color.red=ScaleCharToQuantum(*p++);
3122 fill_color.red=ScaleCharToQuantum(*p++);
3123 fill_color.green=ScaleCharToQuantum(*p++);
3124 fill_color.blue=ScaleCharToQuantum(*p++);
3126 fill_color.alpha=ScaleCharToQuantum(*p++);
3127 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3132 gamma=QuantumScale*fill_color.alpha;
3133 gamma=PerceptibleReciprocal(gamma);
3134 fill_color.blue*=gamma;
3135 fill_color.green*=gamma;
3136 fill_color.red*=gamma;
3139 CompositePixelOver(image,&fill_color,fill_color.alpha,q,(double)
3140 GetPixelAlpha(image,q),q);
3141 q+=GetPixelChannels(image);
3143 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3145 if (image->previous == (Image *) NULL)
3147 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
3149 if (status == MagickFalse)
3154 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3155 if (pixel_info != (MemoryInfo *) NULL)
3156 pixel_info=RelinquishVirtualMemory(pixel_info);
3158 g_object_unref(G_OBJECT(pixel_buffer));
3160 (void) CloseBlob(image);
3161 return(GetFirstImageInList(image));
3169 unique_file=AcquireUniqueFileResource(filename);
3170 if (unique_file != -1)
3171 file=fdopen(unique_file,"w");
3172 if ((unique_file == -1) || (file == (FILE *) NULL))
3174 (void) CopyMagickString(image->filename,filename,MagickPathExtent);
3175 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
3177 image=DestroyImageList(image);
3178 return((Image *) NULL);
3183 svg_info=AcquireSVGInfo();
3184 if (svg_info == (SVGInfo *) NULL)
3186 (void) fclose(file);
3187 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3189 svg_info->file=file;
3190 svg_info->exception=exception;
3191 svg_info->image=image;
3192 svg_info->image_info=image_info;
3193 svg_info->bounds.width=image->columns;
3194 svg_info->bounds.height=image->rows;
3195 if (image_info->size != (char *) NULL)
3196 (void) CloneString(&svg_info->size,image_info->size);
3197 if (image->debug != MagickFalse)
3198 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"begin SAX");
3199 (void) xmlSubstituteEntitiesDefault(1);
3200 (void) ResetMagickMemory(&sax_modules,0,sizeof(sax_modules));
3201 sax_modules.internalSubset=SVGInternalSubset;
3202 sax_modules.isStandalone=SVGIsStandalone;
3203 sax_modules.hasInternalSubset=SVGHasInternalSubset;
3204 sax_modules.hasExternalSubset=SVGHasExternalSubset;
3205 sax_modules.resolveEntity=SVGResolveEntity;
3206 sax_modules.getEntity=SVGGetEntity;
3207 sax_modules.entityDecl=SVGEntityDeclaration;
3208 sax_modules.notationDecl=SVGNotationDeclaration;
3209 sax_modules.attributeDecl=SVGAttributeDeclaration;
3210 sax_modules.elementDecl=SVGElementDeclaration;
3211 sax_modules.unparsedEntityDecl=SVGUnparsedEntityDeclaration;
3212 sax_modules.setDocumentLocator=SVGSetDocumentLocator;
3213 sax_modules.startDocument=SVGStartDocument;
3214 sax_modules.endDocument=SVGEndDocument;
3215 sax_modules.startElement=SVGStartElement;
3216 sax_modules.endElement=SVGEndElement;
3217 sax_modules.reference=SVGReference;
3218 sax_modules.characters=SVGCharacters;
3219 sax_modules.ignorableWhitespace=SVGIgnorableWhitespace;
3220 sax_modules.processingInstruction=SVGProcessingInstructions;
3221 sax_modules.comment=SVGComment;
3222 sax_modules.warning=SVGWarning;
3223 sax_modules.error=SVGError;
3224 sax_modules.fatalError=SVGError;
3225 sax_modules.getParameterEntity=SVGGetParameterEntity;
3226 sax_modules.cdataBlock=SVGCDataBlock;
3227 sax_modules.externalSubset=SVGExternalSubset;
3228 sax_handler=(&sax_modules);
3229 n=ReadBlob(image,MagickPathExtent-1,message);
3233 svg_info->parser=xmlCreatePushParserCtxt(sax_handler,svg_info,(char *)
3234 message,n,image->filename);
3235 while ((n=ReadBlob(image,MagickPathExtent-1,message)) != 0)
3238 status=xmlParseChunk(svg_info->parser,(char *) message,(int) n,0);
3243 (void) xmlParseChunk(svg_info->parser,(char *) message,0,1);
3244 SVGEndDocument(svg_info);
3245 xmlFreeParserCtxt(svg_info->parser);
3246 if (image->debug != MagickFalse)
3247 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"end SAX");
3248 (void) fclose(file);
3249 (void) CloseBlob(image);
3250 image->columns=svg_info->width;
3251 image->rows=svg_info->height;
3252 if (exception->severity >= ErrorException)
3254 svg_info=DestroySVGInfo(svg_info);
3255 (void) RelinquishUniqueFileResource(filename);
3256 image=DestroyImage(image);
3257 return((Image *) NULL);
3259 if (image_info->ping == MagickFalse)
3267 image=DestroyImage(image);
3268 image=(Image *) NULL;
3269 read_info=CloneImageInfo(image_info);
3270 SetImageInfoBlob(read_info,(void *) NULL,0);
3271 if (read_info->density != (char *) NULL)
3272 read_info->density=DestroyString(read_info->density);
3273 (void) FormatLocaleString(read_info->filename,MagickPathExtent,"mvg:%s",
3275 image=ReadImage(read_info,exception);
3276 read_info=DestroyImageInfo(read_info);
3277 if (image != (Image *) NULL)
3278 (void) CopyMagickString(image->filename,image_info->filename,
3282 Relinquish resources.
3284 if (image != (Image *) NULL)
3286 if (svg_info->title != (char *) NULL)
3287 (void) SetImageProperty(image,"svg:title",svg_info->title,exception);
3288 if (svg_info->comment != (char *) NULL)
3289 (void) SetImageProperty(image,"svg:comment",svg_info->comment,
3292 svg_info=DestroySVGInfo(svg_info);
3293 (void) RelinquishUniqueFileResource(filename);
3294 return(GetFirstImageInList(image));
3300 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3304 % R e g i s t e r S V G I m a g e %
3308 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3310 % RegisterSVGImage() adds attributes for the SVG image format to
3311 % the list of supported formats. The attributes include the image format
3312 % tag, a method to read and/or write the format, whether the format
3313 % supports the saving of more than one frame to the same file or blob,
3314 % whether the format supports native in-memory I/O, and a brief
3315 % description of the format.
3317 % The format of the RegisterSVGImage method is:
3319 % size_t RegisterSVGImage(void)
3322 ModuleExport size_t RegisterSVGImage(void)
3325 version[MagickPathExtent];
3331 #if defined(LIBXML_DOTTED_VERSION)
3332 (void) CopyMagickString(version,"XML " LIBXML_DOTTED_VERSION,
3335 #if defined(MAGICKCORE_RSVG_DELEGATE)
3336 #if !GLIB_CHECK_VERSION(2,35,0)
3339 #if defined(MAGICKCORE_XML_DELEGATE)
3342 (void) FormatLocaleString(version,MagickPathExtent,"RSVG %d.%d.%d",
3343 LIBRSVG_MAJOR_VERSION,LIBRSVG_MINOR_VERSION,LIBRSVG_MICRO_VERSION);
3345 entry=AcquireMagickInfo("SVG","SVG","Scalable Vector Graphics");
3346 #if defined(MAGICKCORE_XML_DELEGATE)
3347 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3349 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3350 entry->flags^=CoderBlobSupportFlag;
3351 #if defined(MAGICKCORE_RSVG_DELEGATE)
3352 entry->flags^=CoderDecoderThreadSupportFlag;
3354 entry->mime_type=ConstantString("image/svg+xml");
3355 if (*version != '\0')
3356 entry->version=ConstantString(version);
3357 entry->magick=(IsImageFormatHandler *) IsSVG;
3358 (void) RegisterMagickInfo(entry);
3359 entry=AcquireMagickInfo("SVG","SVGZ","Compressed Scalable Vector Graphics");
3360 #if defined(MAGICKCORE_XML_DELEGATE)
3361 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3363 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3364 entry->flags^=CoderBlobSupportFlag;
3365 #if defined(MAGICKCORE_RSVG_DELEGATE)
3366 entry->flags^=CoderDecoderThreadSupportFlag;
3368 entry->mime_type=ConstantString("image/svg+xml");
3369 if (*version != '\0')
3370 entry->version=ConstantString(version);
3371 entry->magick=(IsImageFormatHandler *) IsSVG;
3372 (void) RegisterMagickInfo(entry);
3373 entry=AcquireMagickInfo("SVG","MSVG",
3374 "ImageMagick's own SVG internal renderer");
3375 #if defined(MAGICKCORE_XML_DELEGATE)
3376 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3378 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3379 entry->flags^=CoderBlobSupportFlag;
3380 #if defined(MAGICKCORE_RSVG_DELEGATE)
3381 entry->flags^=CoderDecoderThreadSupportFlag;
3383 entry->magick=(IsImageFormatHandler *) IsSVG;
3384 (void) RegisterMagickInfo(entry);
3385 return(MagickImageCoderSignature);
3390 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3394 % U n r e g i s t e r S V G I m a g e %
3398 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3400 % UnregisterSVGImage() removes format registrations made by the
3401 % SVG module from the list of supported formats.
3403 % The format of the UnregisterSVGImage method is:
3405 % UnregisterSVGImage(void)
3408 ModuleExport void UnregisterSVGImage(void)
3410 (void) UnregisterMagickInfo("SVGZ");
3411 (void) UnregisterMagickInfo("SVG");
3412 (void) UnregisterMagickInfo("MSVG");
3413 #if defined(MAGICKCORE_XML_DELEGATE)
3420 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3424 % W r i t e S V G I m a g e %
3428 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3430 % WriteSVGImage() writes a image in the SVG - XML based W3C standard
3433 % The format of the WriteSVGImage method is:
3435 % MagickBooleanType WriteSVGImage(const ImageInfo *image_info,
3436 % Image *image,ExceptionInfo *exception)
3438 % A description of each parameter follows.
3440 % o image_info: the image info.
3442 % o image: The image.
3444 % o exception: return any errors or warnings in this structure.
3448 static void AffineToTransform(Image *image,AffineMatrix *affine)
3451 transform[MagickPathExtent];
3453 if ((fabs(affine->tx) < MagickEpsilon) && (fabs(affine->ty) < MagickEpsilon))
3455 if ((fabs(affine->rx) < MagickEpsilon) &&
3456 (fabs(affine->ry) < MagickEpsilon))
3458 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3459 (fabs(affine->sy-1.0) < MagickEpsilon))
3461 (void) WriteBlobString(image,"\">\n");
3464 (void) FormatLocaleString(transform,MagickPathExtent,
3465 "\" transform=\"scale(%g,%g)\">\n",affine->sx,affine->sy);
3466 (void) WriteBlobString(image,transform);
3471 if ((fabs(affine->sx-affine->sy) < MagickEpsilon) &&
3472 (fabs(affine->rx+affine->ry) < MagickEpsilon) &&
3473 (fabs(affine->sx*affine->sx+affine->rx*affine->rx-1.0) <
3479 theta=(180.0/MagickPI)*atan2(affine->rx,affine->sx);
3480 (void) FormatLocaleString(transform,MagickPathExtent,
3481 "\" transform=\"rotate(%g)\">\n",theta);
3482 (void) WriteBlobString(image,transform);
3489 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3490 (fabs(affine->rx) < MagickEpsilon) &&
3491 (fabs(affine->ry) < MagickEpsilon) &&
3492 (fabs(affine->sy-1.0) < MagickEpsilon))
3494 (void) FormatLocaleString(transform,MagickPathExtent,
3495 "\" transform=\"translate(%g,%g)\">\n",affine->tx,affine->ty);
3496 (void) WriteBlobString(image,transform);
3500 (void) FormatLocaleString(transform,MagickPathExtent,
3501 "\" transform=\"matrix(%g %g %g %g %g %g)\">\n",
3502 affine->sx,affine->rx,affine->ry,affine->sy,affine->tx,affine->ty);
3503 (void) WriteBlobString(image,transform);
3506 static MagickBooleanType IsPoint(const char *point)
3514 value=strtol(point,&p,10);
3516 return(p != point ? MagickTrue : MagickFalse);
3519 static MagickBooleanType TraceSVGImage(Image *image,ExceptionInfo *exception)
3521 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
3526 at_fitting_opts_type
3538 register const Quantum
3552 Trace image and write as SVG.
3554 fitting_options=at_fitting_opts_new();
3555 output_options=at_output_opts_new();
3556 (void) SetImageGray(image,exception);
3557 type=GetImageType(image);
3559 if ((type == BilevelType) || (type == GrayscaleType))
3561 trace=at_bitmap_new(image->columns,image->rows,number_planes);
3563 for (y=0; y < (ssize_t) image->rows; y++)
3565 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3566 if (p == (const Quantum *) NULL)
3568 for (x=0; x < (ssize_t) image->columns; x++)
3570 trace->bitmap[i++]=GetPixelRed(image,p);
3571 if (number_planes == 3)
3573 trace->bitmap[i++]=GetPixelGreen(image,p);
3574 trace->bitmap[i++]=GetPixelBlue(image,p);
3576 p+=GetPixelChannels(image);
3579 splines=at_splines_new_full(trace,fitting_options,NULL,NULL,NULL,NULL,NULL,
3581 at_splines_write(at_output_get_handler_by_suffix((char *) "svg"),
3582 GetBlobFileHandle(image),image->filename,output_options,splines,NULL,
3587 at_splines_free(splines);
3588 at_bitmap_free(trace);
3589 at_output_opts_free(output_options);
3590 at_fitting_opts_free(fitting_options);
3596 message[MagickPathExtent];
3617 (void) WriteBlobString(image,
3618 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");
3619 (void) WriteBlobString(image,
3620 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"");
3621 (void) WriteBlobString(image,
3622 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
3623 (void) FormatLocaleString(message,MagickPathExtent,
3624 "<svg version=\"1.1\" id=\"Layer_1\" "
3625 "xmlns=\"http://www.w3.org/2000/svg\" "
3626 "xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\" "
3627 "width=\"%.20gpx\" height=\"%.20gpx\" viewBox=\"0 0 %.20g %.20g\" "
3628 "enable-background=\"new 0 0 %.20g %.20g\" xml:space=\"preserve\">",
3629 (double) image->columns,(double) image->rows,
3630 (double) image->columns,(double) image->rows,
3631 (double) image->columns,(double) image->rows);
3632 (void) WriteBlobString(image,message);
3633 clone_image=CloneImage(image,0,0,MagickTrue,exception);
3634 if (clone_image == (Image *) NULL)
3635 return(MagickFalse);
3636 image_info=AcquireImageInfo();
3637 (void) CopyMagickString(image_info->magick,"PNG",MagickPathExtent);
3639 blob=(unsigned char *) ImageToBlob(image_info,clone_image,&blob_length,
3641 clone_image=DestroyImage(clone_image);
3642 image_info=DestroyImageInfo(image_info);
3643 if (blob == (unsigned char *) NULL)
3644 return(MagickFalse);
3646 base64=Base64Encode(blob,blob_length,&encode_length);
3647 blob=(unsigned char *) RelinquishMagickMemory(blob);
3648 (void) FormatLocaleString(message,MagickPathExtent,
3649 " <image id=\"image%.20g\" width=\"%.20g\" height=\"%.20g\" "
3650 "x=\"%.20g\" y=\"%.20g\"\n xlink:href=\"data:image/png;base64,",
3651 (double) image->scene,(double) image->columns,(double) image->rows,
3652 (double) image->page.x,(double) image->page.y);
3653 (void) WriteBlobString(image,message);
3655 for (i=(ssize_t) encode_length; i > 0; i-=76)
3657 (void) FormatLocaleString(message,MagickPathExtent,"%.76s",p);
3658 (void) WriteBlobString(image,message);
3661 (void) WriteBlobString(image,"\n");
3663 base64=DestroyString(base64);
3664 (void) WriteBlobString(image,"\" />\n");
3665 (void) WriteBlobString(image,"</svg>\n");
3672 static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
3673 ExceptionInfo *exception)
3675 #define BezierQuantum 200
3681 keyword[MagickPathExtent],
3682 message[MagickPathExtent],
3683 name[MagickPathExtent],
3686 type[MagickPathExtent];
3727 Open output image file.
3729 assert(image_info != (const ImageInfo *) NULL);
3730 assert(image_info->signature == MagickCoreSignature);
3731 assert(image != (Image *) NULL);
3732 assert(image->signature == MagickCoreSignature);
3733 if (image->debug != MagickFalse)
3734 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3735 assert(exception != (ExceptionInfo *) NULL);
3736 assert(exception->signature == MagickCoreSignature);
3737 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
3738 if (status == MagickFalse)
3740 value=GetImageArtifact(image,"SVG");
3741 if (value != (char *) NULL)
3743 (void) WriteBlobString(image,value);
3744 (void) CloseBlob(image);
3747 value=GetImageArtifact(image,"MVG");
3748 if (value == (char *) NULL)
3749 return(TraceSVGImage(image,exception));
3753 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3754 (void) WriteBlobString(image,
3755 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3756 (void) WriteBlobString(image,
3757 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3758 (void) FormatLocaleString(message,MagickPathExtent,
3759 "<svg width=\"%.20g\" height=\"%.20g\">\n",(double) image->columns,(double)
3761 (void) WriteBlobString(image,message);
3763 Allocate primitive info memory.
3766 primitive_info=(PrimitiveInfo *) AcquireQuantumMemory(number_points,
3767 sizeof(*primitive_info));
3768 if (primitive_info == (PrimitiveInfo *) NULL)
3769 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3770 GetAffineMatrix(&affine);
3771 token=AcquireString(value);
3772 extent=strlen(token)+MagickPathExtent;
3776 for (q=(const char *) value; *q != '\0'; )
3779 Interpret graphic primitive.
3781 GetNextToken(q,&q,MagickPathExtent,keyword);
3782 if (*keyword == '\0')
3784 if (*keyword == '#')
3789 if (active != MagickFalse)
3791 AffineToTransform(image,&affine);
3794 (void) WriteBlobString(image,"<desc>");
3795 (void) WriteBlobString(image,keyword+1);
3796 for ( ; (*q != '\n') && (*q != '\0'); q++)
3799 case '<': (void) WriteBlobString(image,"<"); break;
3800 case '>': (void) WriteBlobString(image,">"); break;
3801 case '&': (void) WriteBlobString(image,"&"); break;
3802 default: (void) WriteBlobByte(image,*q); break;
3804 (void) WriteBlobString(image,"</desc>\n");
3807 primitive_type=UndefinedPrimitive;
3815 if (LocaleCompare("affine",keyword) == 0)
3817 GetNextToken(q,&q,extent,token);
3818 affine.sx=StringToDouble(token,&next_token);
3819 GetNextToken(q,&q,extent,token);
3821 GetNextToken(q,&q,extent,token);
3822 affine.rx=StringToDouble(token,&next_token);
3823 GetNextToken(q,&q,extent,token);
3825 GetNextToken(q,&q,extent,token);
3826 affine.ry=StringToDouble(token,&next_token);
3827 GetNextToken(q,&q,extent,token);
3829 GetNextToken(q,&q,extent,token);
3830 affine.sy=StringToDouble(token,&next_token);
3831 GetNextToken(q,&q,extent,token);
3833 GetNextToken(q,&q,extent,token);
3834 affine.tx=StringToDouble(token,&next_token);
3835 GetNextToken(q,&q,extent,token);
3837 GetNextToken(q,&q,extent,token);
3838 affine.ty=StringToDouble(token,&next_token);
3841 if (LocaleCompare("alpha",keyword) == 0)
3843 primitive_type=AlphaPrimitive;
3846 if (LocaleCompare("angle",keyword) == 0)
3848 GetNextToken(q,&q,extent,token);
3849 affine.rx=StringToDouble(token,&next_token);
3850 affine.ry=StringToDouble(token,&next_token);
3853 if (LocaleCompare("arc",keyword) == 0)
3855 primitive_type=ArcPrimitive;
3864 if (LocaleCompare("bezier",keyword) == 0)
3866 primitive_type=BezierPrimitive;
3875 if (LocaleCompare("clip-path",keyword) == 0)
3877 GetNextToken(q,&q,extent,token);
3878 (void) FormatLocaleString(message,MagickPathExtent,
3879 "clip-path:url(#%s);",token);
3880 (void) WriteBlobString(image,message);
3883 if (LocaleCompare("clip-rule",keyword) == 0)
3885 GetNextToken(q,&q,extent,token);
3886 (void) FormatLocaleString(message,MagickPathExtent,
3887 "clip-rule:%s;",token);
3888 (void) WriteBlobString(image,message);
3891 if (LocaleCompare("clip-units",keyword) == 0)
3893 GetNextToken(q,&q,extent,token);
3894 (void) FormatLocaleString(message,MagickPathExtent,
3895 "clipPathUnits=%s;",token);
3896 (void) WriteBlobString(image,message);
3899 if (LocaleCompare("circle",keyword) == 0)
3901 primitive_type=CirclePrimitive;
3904 if (LocaleCompare("color",keyword) == 0)
3906 primitive_type=ColorPrimitive;
3915 if (LocaleCompare("decorate",keyword) == 0)
3917 GetNextToken(q,&q,extent,token);
3918 (void) FormatLocaleString(message,MagickPathExtent,
3919 "text-decoration:%s;",token);
3920 (void) WriteBlobString(image,message);
3929 if (LocaleCompare("ellipse",keyword) == 0)
3931 primitive_type=EllipsePrimitive;
3940 if (LocaleCompare("fill",keyword) == 0)
3942 GetNextToken(q,&q,extent,token);
3943 (void) FormatLocaleString(message,MagickPathExtent,"fill:%s;",
3945 (void) WriteBlobString(image,message);
3948 if (LocaleCompare("fill-rule",keyword) == 0)
3950 GetNextToken(q,&q,extent,token);
3951 (void) FormatLocaleString(message,MagickPathExtent,
3952 "fill-rule:%s;",token);
3953 (void) WriteBlobString(image,message);
3956 if (LocaleCompare("fill-opacity",keyword) == 0)
3958 GetNextToken(q,&q,extent,token);
3959 (void) FormatLocaleString(message,MagickPathExtent,
3960 "fill-opacity:%s;",token);
3961 (void) WriteBlobString(image,message);
3964 if (LocaleCompare("font-family",keyword) == 0)
3966 GetNextToken(q,&q,extent,token);
3967 (void) FormatLocaleString(message,MagickPathExtent,
3968 "font-family:%s;",token);
3969 (void) WriteBlobString(image,message);
3972 if (LocaleCompare("font-stretch",keyword) == 0)
3974 GetNextToken(q,&q,extent,token);
3975 (void) FormatLocaleString(message,MagickPathExtent,
3976 "font-stretch:%s;",token);
3977 (void) WriteBlobString(image,message);
3980 if (LocaleCompare("font-style",keyword) == 0)
3982 GetNextToken(q,&q,extent,token);
3983 (void) FormatLocaleString(message,MagickPathExtent,
3984 "font-style:%s;",token);
3985 (void) WriteBlobString(image,message);
3988 if (LocaleCompare("font-size",keyword) == 0)
3990 GetNextToken(q,&q,extent,token);
3991 (void) FormatLocaleString(message,MagickPathExtent,
3992 "font-size:%s;",token);
3993 (void) WriteBlobString(image,message);
3996 if (LocaleCompare("font-weight",keyword) == 0)
3998 GetNextToken(q,&q,extent,token);
3999 (void) FormatLocaleString(message,MagickPathExtent,
4000 "font-weight:%s;",token);
4001 (void) WriteBlobString(image,message);
4010 if (LocaleCompare("gradient-units",keyword) == 0)
4012 GetNextToken(q,&q,extent,token);
4015 if (LocaleCompare("text-align",keyword) == 0)
4017 GetNextToken(q,&q,extent,token);
4018 (void) FormatLocaleString(message,MagickPathExtent,
4019 "text-align %s ",token);
4020 (void) WriteBlobString(image,message);
4023 if (LocaleCompare("text-anchor",keyword) == 0)
4025 GetNextToken(q,&q,extent,token);
4026 (void) FormatLocaleString(message,MagickPathExtent,
4027 "text-anchor %s ",token);
4028 (void) WriteBlobString(image,message);
4037 if (LocaleCompare("image",keyword) == 0)
4039 GetNextToken(q,&q,extent,token);
4040 primitive_type=ImagePrimitive;
4049 if (LocaleCompare("line",keyword) == 0)
4051 primitive_type=LinePrimitive;
4060 if (LocaleCompare("opacity",keyword) == 0)
4062 GetNextToken(q,&q,extent,token);
4063 (void) FormatLocaleString(message,MagickPathExtent,"opacity %s ",
4065 (void) WriteBlobString(image,message);
4074 if (LocaleCompare("path",keyword) == 0)
4076 primitive_type=PathPrimitive;
4079 if (LocaleCompare("point",keyword) == 0)
4081 primitive_type=PointPrimitive;
4084 if (LocaleCompare("polyline",keyword) == 0)
4086 primitive_type=PolylinePrimitive;
4089 if (LocaleCompare("polygon",keyword) == 0)
4091 primitive_type=PolygonPrimitive;
4094 if (LocaleCompare("pop",keyword) == 0)
4096 GetNextToken(q,&q,extent,token);
4097 if (LocaleCompare("clip-path",token) == 0)
4099 (void) WriteBlobString(image,"</clipPath>\n");
4102 if (LocaleCompare("defs",token) == 0)
4104 (void) WriteBlobString(image,"</defs>\n");
4107 if (LocaleCompare("gradient",token) == 0)
4109 (void) FormatLocaleString(message,MagickPathExtent,
4110 "</%sGradient>\n",type);
4111 (void) WriteBlobString(image,message);
4114 if (LocaleCompare("graphic-context",token) == 0)
4118 ThrowWriterException(DrawError,
4119 "UnbalancedGraphicContextPushPop");
4120 (void) WriteBlobString(image,"</g>\n");
4122 if (LocaleCompare("pattern",token) == 0)
4124 (void) WriteBlobString(image,"</pattern>\n");
4127 if (LocaleCompare("defs",token) == 0)
4128 (void) WriteBlobString(image,"</g>\n");
4131 if (LocaleCompare("push",keyword) == 0)
4133 GetNextToken(q,&q,extent,token);
4134 if (LocaleCompare("clip-path",token) == 0)
4136 GetNextToken(q,&q,extent,token);
4137 (void) FormatLocaleString(message,MagickPathExtent,
4138 "<clipPath id=\"%s\">\n",token);
4139 (void) WriteBlobString(image,message);
4142 if (LocaleCompare("defs",token) == 0)
4144 (void) WriteBlobString(image,"<defs>\n");
4147 if (LocaleCompare("gradient",token) == 0)
4149 GetNextToken(q,&q,extent,token);
4150 (void) CopyMagickString(name,token,MagickPathExtent);
4151 GetNextToken(q,&q,extent,token);
4152 (void) CopyMagickString(type,token,MagickPathExtent);
4153 GetNextToken(q,&q,extent,token);
4154 svg_info.segment.x1=StringToDouble(token,&next_token);
4155 svg_info.element.cx=StringToDouble(token,&next_token);
4156 GetNextToken(q,&q,extent,token);
4158 GetNextToken(q,&q,extent,token);
4159 svg_info.segment.y1=StringToDouble(token,&next_token);
4160 svg_info.element.cy=StringToDouble(token,&next_token);
4161 GetNextToken(q,&q,extent,token);
4163 GetNextToken(q,&q,extent,token);
4164 svg_info.segment.x2=StringToDouble(token,&next_token);
4165 svg_info.element.major=StringToDouble(token,
4167 GetNextToken(q,&q,extent,token);
4169 GetNextToken(q,&q,extent,token);
4170 svg_info.segment.y2=StringToDouble(token,&next_token);
4171 svg_info.element.minor=StringToDouble(token,
4173 (void) FormatLocaleString(message,MagickPathExtent,
4174 "<%sGradient id=\"%s\" x1=\"%g\" y1=\"%g\" x2=\"%g\" "
4175 "y2=\"%g\">\n",type,name,svg_info.segment.x1,
4176 svg_info.segment.y1,svg_info.segment.x2,svg_info.segment.y2);
4177 if (LocaleCompare(type,"radial") == 0)
4179 GetNextToken(q,&q,extent,token);
4181 GetNextToken(q,&q,extent,token);
4182 svg_info.element.angle=StringToDouble(token,
4184 (void) FormatLocaleString(message,MagickPathExtent,
4185 "<%sGradient id=\"%s\" cx=\"%g\" cy=\"%g\" r=\"%g\" "
4186 "fx=\"%g\" fy=\"%g\">\n",type,name,
4187 svg_info.element.cx,svg_info.element.cy,
4188 svg_info.element.angle,svg_info.element.major,
4189 svg_info.element.minor);
4191 (void) WriteBlobString(image,message);
4194 if (LocaleCompare("graphic-context",token) == 0)
4199 AffineToTransform(image,&affine);
4202 (void) WriteBlobString(image,"<g style=\"");
4205 if (LocaleCompare("pattern",token) == 0)
4207 GetNextToken(q,&q,extent,token);
4208 (void) CopyMagickString(name,token,MagickPathExtent);
4209 GetNextToken(q,&q,extent,token);
4210 svg_info.bounds.x=StringToDouble(token,&next_token);
4211 GetNextToken(q,&q,extent,token);
4213 GetNextToken(q,&q,extent,token);
4214 svg_info.bounds.y=StringToDouble(token,&next_token);
4215 GetNextToken(q,&q,extent,token);
4217 GetNextToken(q,&q,extent,token);
4218 svg_info.bounds.width=StringToDouble(token,
4220 GetNextToken(q,&q,extent,token);
4222 GetNextToken(q,&q,extent,token);
4223 svg_info.bounds.height=StringToDouble(token,(char **) NULL);
4224 (void) FormatLocaleString(message,MagickPathExtent,
4225 "<pattern id=\"%s\" x=\"%g\" y=\"%g\" width=\"%g\" "
4226 "height=\"%g\">\n",name,svg_info.bounds.x,svg_info.bounds.y,
4227 svg_info.bounds.width,svg_info.bounds.height);
4228 (void) WriteBlobString(image,message);
4239 if (LocaleCompare("rectangle",keyword) == 0)
4241 primitive_type=RectanglePrimitive;
4244 if (LocaleCompare("roundRectangle",keyword) == 0)
4246 primitive_type=RoundRectanglePrimitive;
4249 if (LocaleCompare("rotate",keyword) == 0)
4251 GetNextToken(q,&q,extent,token);
4252 (void) FormatLocaleString(message,MagickPathExtent,"rotate(%s) ",
4254 (void) WriteBlobString(image,message);
4263 if (LocaleCompare("scale",keyword) == 0)
4265 GetNextToken(q,&q,extent,token);
4266 affine.sx=StringToDouble(token,&next_token);
4267 GetNextToken(q,&q,extent,token);
4269 GetNextToken(q,&q,extent,token);
4270 affine.sy=StringToDouble(token,&next_token);
4273 if (LocaleCompare("skewX",keyword) == 0)
4275 GetNextToken(q,&q,extent,token);
4276 (void) FormatLocaleString(message,MagickPathExtent,"skewX(%s) ",
4278 (void) WriteBlobString(image,message);
4281 if (LocaleCompare("skewY",keyword) == 0)
4283 GetNextToken(q,&q,extent,token);
4284 (void) FormatLocaleString(message,MagickPathExtent,"skewY(%s) ",
4286 (void) WriteBlobString(image,message);
4289 if (LocaleCompare("stop-color",keyword) == 0)
4292 color[MagickPathExtent];
4294 GetNextToken(q,&q,extent,token);
4295 (void) CopyMagickString(color,token,MagickPathExtent);
4296 GetNextToken(q,&q,extent,token);
4297 (void) FormatLocaleString(message,MagickPathExtent,
4298 " <stop offset=\"%s\" stop-color=\"%s\" />\n",token,color);
4299 (void) WriteBlobString(image,message);
4302 if (LocaleCompare("stroke",keyword) == 0)
4304 GetNextToken(q,&q,extent,token);
4305 (void) FormatLocaleString(message,MagickPathExtent,"stroke:%s;",
4307 (void) WriteBlobString(image,message);
4310 if (LocaleCompare("stroke-antialias",keyword) == 0)
4312 GetNextToken(q,&q,extent,token);
4313 (void) FormatLocaleString(message,MagickPathExtent,
4314 "stroke-antialias:%s;",token);
4315 (void) WriteBlobString(image,message);
4318 if (LocaleCompare("stroke-dasharray",keyword) == 0)
4326 GetNextToken(p,&p,extent,token);
4327 for (k=0; IsPoint(token); k++)
4328 GetNextToken(p,&p,extent,token);
4329 (void) WriteBlobString(image,"stroke-dasharray:");
4330 for (j=0; j < k; j++)
4332 GetNextToken(q,&q,extent,token);
4333 (void) FormatLocaleString(message,MagickPathExtent,"%s ",
4335 (void) WriteBlobString(image,message);
4337 (void) WriteBlobString(image,";");
4340 GetNextToken(q,&q,extent,token);
4341 (void) FormatLocaleString(message,MagickPathExtent,
4342 "stroke-dasharray:%s;",token);
4343 (void) WriteBlobString(image,message);
4346 if (LocaleCompare("stroke-dashoffset",keyword) == 0)
4348 GetNextToken(q,&q,extent,token);
4349 (void) FormatLocaleString(message,MagickPathExtent,
4350 "stroke-dashoffset:%s;",token);
4351 (void) WriteBlobString(image,message);
4354 if (LocaleCompare("stroke-linecap",keyword) == 0)
4356 GetNextToken(q,&q,extent,token);
4357 (void) FormatLocaleString(message,MagickPathExtent,
4358 "stroke-linecap:%s;",token);
4359 (void) WriteBlobString(image,message);
4362 if (LocaleCompare("stroke-linejoin",keyword) == 0)
4364 GetNextToken(q,&q,extent,token);
4365 (void) FormatLocaleString(message,MagickPathExtent,
4366 "stroke-linejoin:%s;",token);
4367 (void) WriteBlobString(image,message);
4370 if (LocaleCompare("stroke-miterlimit",keyword) == 0)
4372 GetNextToken(q,&q,extent,token);
4373 (void) FormatLocaleString(message,MagickPathExtent,
4374 "stroke-miterlimit:%s;",token);
4375 (void) WriteBlobString(image,message);
4378 if (LocaleCompare("stroke-opacity",keyword) == 0)
4380 GetNextToken(q,&q,extent,token);
4381 (void) FormatLocaleString(message,MagickPathExtent,
4382 "stroke-opacity:%s;",token);
4383 (void) WriteBlobString(image,message);
4386 if (LocaleCompare("stroke-width",keyword) == 0)
4388 GetNextToken(q,&q,extent,token);
4389 (void) FormatLocaleString(message,MagickPathExtent,
4390 "stroke-width:%s;",token);
4391 (void) WriteBlobString(image,message);
4400 if (LocaleCompare("text",keyword) == 0)
4402 primitive_type=TextPrimitive;
4405 if (LocaleCompare("text-antialias",keyword) == 0)
4407 GetNextToken(q,&q,extent,token);
4408 (void) FormatLocaleString(message,MagickPathExtent,
4409 "text-antialias:%s;",token);
4410 (void) WriteBlobString(image,message);
4413 if (LocaleCompare("tspan",keyword) == 0)
4415 primitive_type=TextPrimitive;
4418 if (LocaleCompare("translate",keyword) == 0)
4420 GetNextToken(q,&q,extent,token);
4421 affine.tx=StringToDouble(token,&next_token);
4422 GetNextToken(q,&q,extent,token);
4424 GetNextToken(q,&q,extent,token);
4425 affine.ty=StringToDouble(token,&next_token);
4434 if (LocaleCompare("viewbox",keyword) == 0)
4436 GetNextToken(q,&q,extent,token);
4438 GetNextToken(q,&q,extent,token);
4439 GetNextToken(q,&q,extent,token);
4441 GetNextToken(q,&q,extent,token);
4442 GetNextToken(q,&q,extent,token);
4444 GetNextToken(q,&q,extent,token);
4445 GetNextToken(q,&q,extent,token);
4457 if (status == MagickFalse)
4459 if (primitive_type == UndefinedPrimitive)
4462 Parse the primitive attributes.
4466 for (x=0; *q != '\0'; x++)
4471 if (IsPoint(q) == MagickFalse)
4473 GetNextToken(q,&q,extent,token);
4474 point.x=StringToDouble(token,&next_token);
4475 GetNextToken(q,&q,extent,token);
4477 GetNextToken(q,&q,extent,token);
4478 point.y=StringToDouble(token,&next_token);
4479 GetNextToken(q,(const char **) NULL,extent,token);
4481 GetNextToken(q,&q,extent,token);
4482 primitive_info[i].primitive=primitive_type;
4483 primitive_info[i].point=point;
4484 primitive_info[i].coordinates=0;
4485 primitive_info[i].method=FloodfillMethod;
4487 if (i < (ssize_t) (number_points-6*BezierQuantum-360))
4489 number_points+=6*BezierQuantum+360;
4490 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4491 number_points,sizeof(*primitive_info));
4492 if (primitive_info == (PrimitiveInfo *) NULL)
4494 (void) ThrowMagickException(exception,GetMagickModule(),
4495 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
4499 primitive_info[j].primitive=primitive_type;
4500 primitive_info[j].coordinates=x;
4501 primitive_info[j].method=FloodfillMethod;
4502 primitive_info[j].text=(char *) NULL;
4505 AffineToTransform(image,&affine);
4509 switch (primitive_type)
4511 case PointPrimitive:
4514 if (primitive_info[j].coordinates != 1)
4523 if (primitive_info[j].coordinates != 2)
4528 (void) FormatLocaleString(message,MagickPathExtent,
4529 " <line x1=\"%g\" y1=\"%g\" x2=\"%g\" y2=\"%g\"/>\n",
4530 primitive_info[j].point.x,primitive_info[j].point.y,
4531 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4532 (void) WriteBlobString(image,message);
4535 case RectanglePrimitive:
4537 if (primitive_info[j].coordinates != 2)
4542 (void) FormatLocaleString(message,MagickPathExtent,
4543 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"/>\n",
4544 primitive_info[j].point.x,primitive_info[j].point.y,
4545 primitive_info[j+1].point.x-primitive_info[j].point.x,
4546 primitive_info[j+1].point.y-primitive_info[j].point.y);
4547 (void) WriteBlobString(image,message);
4550 case RoundRectanglePrimitive:
4552 if (primitive_info[j].coordinates != 3)
4557 (void) FormatLocaleString(message,MagickPathExtent,
4558 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" rx=\"%g\" "
4559 "ry=\"%g\"/>\n",primitive_info[j].point.x,
4560 primitive_info[j].point.y,primitive_info[j+1].point.x-
4561 primitive_info[j].point.x,primitive_info[j+1].point.y-
4562 primitive_info[j].point.y,primitive_info[j+2].point.x,
4563 primitive_info[j+2].point.y);
4564 (void) WriteBlobString(image,message);
4569 if (primitive_info[j].coordinates != 3)
4576 case EllipsePrimitive:
4578 if (primitive_info[j].coordinates != 3)
4583 (void) FormatLocaleString(message,MagickPathExtent,
4584 " <ellipse cx=\"%g\" cy=\"%g\" rx=\"%g\" ry=\"%g\"/>\n",
4585 primitive_info[j].point.x,primitive_info[j].point.y,
4586 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4587 (void) WriteBlobString(image,message);
4590 case CirclePrimitive:
4596 if (primitive_info[j].coordinates != 2)
4601 alpha=primitive_info[j+1].point.x-primitive_info[j].point.x;
4602 beta=primitive_info[j+1].point.y-primitive_info[j].point.y;
4603 (void) FormatLocaleString(message,MagickPathExtent,
4604 " <circle cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
4605 primitive_info[j].point.x,primitive_info[j].point.y,
4607 (void) WriteBlobString(image,message);
4610 case PolylinePrimitive:
4612 if (primitive_info[j].coordinates < 2)
4617 (void) CopyMagickString(message," <polyline points=\"",
4619 (void) WriteBlobString(image,message);
4620 length=strlen(message);
4623 (void) FormatLocaleString(message,MagickPathExtent,"%g,%g ",
4624 primitive_info[j].point.x,primitive_info[j].point.y);
4625 length+=strlen(message);
4628 (void) WriteBlobString(image,"\n ");
4629 length=strlen(message)+5;
4631 (void) WriteBlobString(image,message);
4633 (void) WriteBlobString(image,"\"/>\n");
4636 case PolygonPrimitive:
4638 if (primitive_info[j].coordinates < 3)
4643 primitive_info[i]=primitive_info[j];
4644 primitive_info[i].coordinates=0;
4645 primitive_info[j].coordinates++;
4647 (void) CopyMagickString(message," <polygon points=\"",MagickPathExtent);
4648 (void) WriteBlobString(image,message);
4649 length=strlen(message);
4652 (void) FormatLocaleString(message,MagickPathExtent,"%g,%g ",
4653 primitive_info[j].point.x,primitive_info[j].point.y);
4654 length+=strlen(message);
4657 (void) WriteBlobString(image,"\n ");
4658 length=strlen(message)+5;
4660 (void) WriteBlobString(image,message);
4662 (void) WriteBlobString(image,"\"/>\n");
4665 case BezierPrimitive:
4667 if (primitive_info[j].coordinates < 3)
4679 GetNextToken(q,&q,extent,token);
4680 number_attributes=1;
4681 for (p=token; *p != '\0'; p++)
4682 if (isalpha((int) *p))
4683 number_attributes++;
4684 if (i > (ssize_t) (number_points-6*BezierQuantum*number_attributes-1))
4686 number_points+=6*BezierQuantum*number_attributes;
4687 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4688 number_points,sizeof(*primitive_info));
4689 if (primitive_info == (PrimitiveInfo *) NULL)
4691 (void) ThrowMagickException(exception,GetMagickModule(),
4692 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4697 (void) WriteBlobString(image," <path d=\"");
4698 (void) WriteBlobString(image,token);
4699 (void) WriteBlobString(image,"\"/>\n");
4702 case AlphaPrimitive:
4703 case ColorPrimitive:
4705 if (primitive_info[j].coordinates != 1)
4710 GetNextToken(q,&q,extent,token);
4711 if (LocaleCompare("point",token) == 0)
4712 primitive_info[j].method=PointMethod;
4713 if (LocaleCompare("replace",token) == 0)
4714 primitive_info[j].method=ReplaceMethod;
4715 if (LocaleCompare("floodfill",token) == 0)
4716 primitive_info[j].method=FloodfillMethod;
4717 if (LocaleCompare("filltoborder",token) == 0)
4718 primitive_info[j].method=FillToBorderMethod;
4719 if (LocaleCompare("reset",token) == 0)
4720 primitive_info[j].method=ResetMethod;
4728 if (primitive_info[j].coordinates != 1)
4733 GetNextToken(q,&q,extent,token);
4734 (void) FormatLocaleString(message,MagickPathExtent,
4735 " <text x=\"%g\" y=\"%g\">",primitive_info[j].point.x,
4736 primitive_info[j].point.y);
4737 (void) WriteBlobString(image,message);
4738 for (p=token; *p != '\0'; p++)
4741 case '<': (void) WriteBlobString(image,"<"); break;
4742 case '>': (void) WriteBlobString(image,">"); break;
4743 case '&': (void) WriteBlobString(image,"&"); break;
4744 default: (void) WriteBlobByte(image,*p); break;
4746 (void) WriteBlobString(image,"</text>\n");
4749 case ImagePrimitive:
4751 if (primitive_info[j].coordinates != 2)
4756 GetNextToken(q,&q,extent,token);
4757 (void) FormatLocaleString(message,MagickPathExtent,
4758 " <image x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" "
4759 "xlink:href=\"%s\"/>\n",primitive_info[j].point.x,
4760 primitive_info[j].point.y,primitive_info[j+1].point.x,
4761 primitive_info[j+1].point.y,token);
4762 (void) WriteBlobString(image,message);
4766 if (primitive_info == (PrimitiveInfo *) NULL)
4768 primitive_info[i].primitive=UndefinedPrimitive;
4769 if (status == MagickFalse)
4772 (void) WriteBlobString(image,"</svg>\n");
4774 Relinquish resources.
4776 token=DestroyString(token);
4777 if (primitive_info != (PrimitiveInfo *) NULL)
4778 primitive_info=(PrimitiveInfo *) RelinquishMagickMemory(primitive_info);
4779 (void) CloseBlob(image);