2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Scalable Vector Graphics Format %
21 % Copyright 1999-2017 ImageMagick Studio LLC, a non-profit organization %
22 % dedicated to making software imaging solutions freely available. %
24 % You may not use this file except in compliance with the License. You may %
25 % obtain a copy of the License at %
27 % https://www.imagemagick.org/script/license.php %
29 % Unless required by applicable law or agreed to in writing, software %
30 % distributed under the License is distributed on an "AS IS" BASIS, %
31 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
32 % See the License for the specific language governing permissions and %
33 % limitations under the License. %
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
44 #include "MagickCore/studio.h"
45 #include "MagickCore/annotate.h"
46 #include "MagickCore/artifact.h"
47 #include "MagickCore/attribute.h"
48 #include "MagickCore/blob.h"
49 #include "MagickCore/blob-private.h"
50 #include "MagickCore/cache.h"
51 #include "MagickCore/constitute.h"
52 #include "MagickCore/composite-private.h"
53 #include "MagickCore/delegate.h"
54 #include "MagickCore/delegate-private.h"
55 #include "MagickCore/draw.h"
56 #include "MagickCore/exception.h"
57 #include "MagickCore/exception-private.h"
58 #include "MagickCore/gem.h"
59 #include "MagickCore/image.h"
60 #include "MagickCore/image-private.h"
61 #include "MagickCore/list.h"
62 #include "MagickCore/log.h"
63 #include "MagickCore/magick.h"
64 #include "MagickCore/memory_.h"
65 #include "MagickCore/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)
3086 pixel_info=RelinquishVirtualMemory(pixel_info);
3087 g_object_unref(svg_handle);
3088 ThrowReaderException(ResourceLimitError,
3089 "MemoryAllocationFailed");
3091 cairo_image=cairo_create(cairo_surface);
3092 cairo_set_operator(cairo_image,CAIRO_OPERATOR_CLEAR);
3093 cairo_paint(cairo_image);
3094 cairo_set_operator(cairo_image,CAIRO_OPERATOR_OVER);
3095 if (apply_density != MagickFalse)
3096 cairo_scale(cairo_image,image->resolution.x/96.0,
3097 image->resolution.y/96.0);
3098 rsvg_handle_render_cairo(svg_handle,cairo_image);
3099 cairo_destroy(cairo_image);
3100 cairo_surface_destroy(cairo_surface);
3101 g_object_unref(svg_handle);
3104 p=gdk_pixbuf_get_pixels(pixel_buffer);
3106 GetPixelInfo(image,&fill_color);
3107 for (y=0; y < (ssize_t) image->rows; y++)
3109 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3110 if (q == (Quantum *) NULL)
3112 for (x=0; x < (ssize_t) image->columns; x++)
3114 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3115 fill_color.blue=ScaleCharToQuantum(*p++);
3116 fill_color.green=ScaleCharToQuantum(*p++);
3117 fill_color.red=ScaleCharToQuantum(*p++);
3119 fill_color.red=ScaleCharToQuantum(*p++);
3120 fill_color.green=ScaleCharToQuantum(*p++);
3121 fill_color.blue=ScaleCharToQuantum(*p++);
3123 fill_color.alpha=ScaleCharToQuantum(*p++);
3124 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3129 gamma=QuantumScale*fill_color.alpha;
3130 gamma=PerceptibleReciprocal(gamma);
3131 fill_color.blue*=gamma;
3132 fill_color.green*=gamma;
3133 fill_color.red*=gamma;
3136 CompositePixelOver(image,&fill_color,fill_color.alpha,q,(double)
3137 GetPixelAlpha(image,q),q);
3138 q+=GetPixelChannels(image);
3140 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3142 if (image->previous == (Image *) NULL)
3144 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
3146 if (status == MagickFalse)
3151 #if defined(MAGICKCORE_CAIRO_DELEGATE)
3152 if (pixel_info != (MemoryInfo *) NULL)
3153 pixel_info=RelinquishVirtualMemory(pixel_info);
3155 g_object_unref(G_OBJECT(pixel_buffer));
3157 (void) CloseBlob(image);
3158 return(GetFirstImageInList(image));
3166 unique_file=AcquireUniqueFileResource(filename);
3167 if (unique_file != -1)
3168 file=fdopen(unique_file,"w");
3169 if ((unique_file == -1) || (file == (FILE *) NULL))
3171 (void) CopyMagickString(image->filename,filename,MagickPathExtent);
3172 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
3174 image=DestroyImageList(image);
3175 return((Image *) NULL);
3180 svg_info=AcquireSVGInfo();
3181 if (svg_info == (SVGInfo *) NULL)
3183 (void) fclose(file);
3184 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3186 svg_info->file=file;
3187 svg_info->exception=exception;
3188 svg_info->image=image;
3189 svg_info->image_info=image_info;
3190 svg_info->bounds.width=image->columns;
3191 svg_info->bounds.height=image->rows;
3192 if (image_info->size != (char *) NULL)
3193 (void) CloneString(&svg_info->size,image_info->size);
3194 if (image->debug != MagickFalse)
3195 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"begin SAX");
3196 (void) xmlSubstituteEntitiesDefault(1);
3197 (void) ResetMagickMemory(&sax_modules,0,sizeof(sax_modules));
3198 sax_modules.internalSubset=SVGInternalSubset;
3199 sax_modules.isStandalone=SVGIsStandalone;
3200 sax_modules.hasInternalSubset=SVGHasInternalSubset;
3201 sax_modules.hasExternalSubset=SVGHasExternalSubset;
3202 sax_modules.resolveEntity=SVGResolveEntity;
3203 sax_modules.getEntity=SVGGetEntity;
3204 sax_modules.entityDecl=SVGEntityDeclaration;
3205 sax_modules.notationDecl=SVGNotationDeclaration;
3206 sax_modules.attributeDecl=SVGAttributeDeclaration;
3207 sax_modules.elementDecl=SVGElementDeclaration;
3208 sax_modules.unparsedEntityDecl=SVGUnparsedEntityDeclaration;
3209 sax_modules.setDocumentLocator=SVGSetDocumentLocator;
3210 sax_modules.startDocument=SVGStartDocument;
3211 sax_modules.endDocument=SVGEndDocument;
3212 sax_modules.startElement=SVGStartElement;
3213 sax_modules.endElement=SVGEndElement;
3214 sax_modules.reference=SVGReference;
3215 sax_modules.characters=SVGCharacters;
3216 sax_modules.ignorableWhitespace=SVGIgnorableWhitespace;
3217 sax_modules.processingInstruction=SVGProcessingInstructions;
3218 sax_modules.comment=SVGComment;
3219 sax_modules.warning=SVGWarning;
3220 sax_modules.error=SVGError;
3221 sax_modules.fatalError=SVGError;
3222 sax_modules.getParameterEntity=SVGGetParameterEntity;
3223 sax_modules.cdataBlock=SVGCDataBlock;
3224 sax_modules.externalSubset=SVGExternalSubset;
3225 sax_handler=(&sax_modules);
3226 n=ReadBlob(image,MagickPathExtent-1,message);
3230 svg_info->parser=xmlCreatePushParserCtxt(sax_handler,svg_info,(char *)
3231 message,n,image->filename);
3232 while ((n=ReadBlob(image,MagickPathExtent-1,message)) != 0)
3235 status=xmlParseChunk(svg_info->parser,(char *) message,(int) n,0);
3240 (void) xmlParseChunk(svg_info->parser,(char *) message,0,1);
3241 SVGEndDocument(svg_info);
3242 xmlFreeParserCtxt(svg_info->parser);
3243 if (image->debug != MagickFalse)
3244 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"end SAX");
3245 (void) fclose(file);
3246 (void) CloseBlob(image);
3247 image->columns=svg_info->width;
3248 image->rows=svg_info->height;
3249 if (exception->severity >= ErrorException)
3251 svg_info=DestroySVGInfo(svg_info);
3252 (void) RelinquishUniqueFileResource(filename);
3253 image=DestroyImage(image);
3254 return((Image *) NULL);
3256 if (image_info->ping == MagickFalse)
3264 image=DestroyImage(image);
3265 image=(Image *) NULL;
3266 read_info=CloneImageInfo(image_info);
3267 SetImageInfoBlob(read_info,(void *) NULL,0);
3268 if (read_info->density != (char *) NULL)
3269 read_info->density=DestroyString(read_info->density);
3270 (void) FormatLocaleString(read_info->filename,MagickPathExtent,"mvg:%s",
3272 image=ReadImage(read_info,exception);
3273 read_info=DestroyImageInfo(read_info);
3274 if (image != (Image *) NULL)
3275 (void) CopyMagickString(image->filename,image_info->filename,
3279 Relinquish resources.
3281 if (image != (Image *) NULL)
3283 if (svg_info->title != (char *) NULL)
3284 (void) SetImageProperty(image,"svg:title",svg_info->title,exception);
3285 if (svg_info->comment != (char *) NULL)
3286 (void) SetImageProperty(image,"svg:comment",svg_info->comment,
3289 svg_info=DestroySVGInfo(svg_info);
3290 (void) RelinquishUniqueFileResource(filename);
3291 return(GetFirstImageInList(image));
3297 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3301 % R e g i s t e r S V G I m a g e %
3305 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3307 % RegisterSVGImage() adds attributes for the SVG image format to
3308 % the list of supported formats. The attributes include the image format
3309 % tag, a method to read and/or write the format, whether the format
3310 % supports the saving of more than one frame to the same file or blob,
3311 % whether the format supports native in-memory I/O, and a brief
3312 % description of the format.
3314 % The format of the RegisterSVGImage method is:
3316 % size_t RegisterSVGImage(void)
3319 ModuleExport size_t RegisterSVGImage(void)
3322 version[MagickPathExtent];
3328 #if defined(LIBXML_DOTTED_VERSION)
3329 (void) CopyMagickString(version,"XML " LIBXML_DOTTED_VERSION,
3332 #if defined(MAGICKCORE_RSVG_DELEGATE)
3333 #if !GLIB_CHECK_VERSION(2,35,0)
3336 #if defined(MAGICKCORE_XML_DELEGATE)
3339 (void) FormatLocaleString(version,MagickPathExtent,"RSVG %d.%d.%d",
3340 LIBRSVG_MAJOR_VERSION,LIBRSVG_MINOR_VERSION,LIBRSVG_MICRO_VERSION);
3342 entry=AcquireMagickInfo("SVG","SVG","Scalable Vector Graphics");
3343 #if defined(MAGICKCORE_XML_DELEGATE)
3344 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3346 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3347 entry->flags^=CoderBlobSupportFlag;
3348 #if defined(MAGICKCORE_RSVG_DELEGATE)
3349 entry->flags^=CoderDecoderThreadSupportFlag;
3351 entry->mime_type=ConstantString("image/svg+xml");
3352 if (*version != '\0')
3353 entry->version=ConstantString(version);
3354 entry->magick=(IsImageFormatHandler *) IsSVG;
3355 (void) RegisterMagickInfo(entry);
3356 entry=AcquireMagickInfo("SVG","SVGZ","Compressed Scalable Vector Graphics");
3357 #if defined(MAGICKCORE_XML_DELEGATE)
3358 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3360 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3361 entry->flags^=CoderBlobSupportFlag;
3362 #if defined(MAGICKCORE_RSVG_DELEGATE)
3363 entry->flags^=CoderDecoderThreadSupportFlag;
3365 entry->mime_type=ConstantString("image/svg+xml");
3366 if (*version != '\0')
3367 entry->version=ConstantString(version);
3368 entry->magick=(IsImageFormatHandler *) IsSVG;
3369 (void) RegisterMagickInfo(entry);
3370 entry=AcquireMagickInfo("SVG","MSVG",
3371 "ImageMagick's own SVG internal renderer");
3372 #if defined(MAGICKCORE_XML_DELEGATE)
3373 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3375 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3376 entry->flags^=CoderBlobSupportFlag;
3377 #if defined(MAGICKCORE_RSVG_DELEGATE)
3378 entry->flags^=CoderDecoderThreadSupportFlag;
3380 entry->magick=(IsImageFormatHandler *) IsSVG;
3381 (void) RegisterMagickInfo(entry);
3382 return(MagickImageCoderSignature);
3387 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3391 % U n r e g i s t e r S V G I m a g e %
3395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3397 % UnregisterSVGImage() removes format registrations made by the
3398 % SVG module from the list of supported formats.
3400 % The format of the UnregisterSVGImage method is:
3402 % UnregisterSVGImage(void)
3405 ModuleExport void UnregisterSVGImage(void)
3407 (void) UnregisterMagickInfo("SVGZ");
3408 (void) UnregisterMagickInfo("SVG");
3409 (void) UnregisterMagickInfo("MSVG");
3410 #if defined(MAGICKCORE_XML_DELEGATE)
3417 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3421 % W r i t e S V G I m a g e %
3425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3427 % WriteSVGImage() writes a image in the SVG - XML based W3C standard
3430 % The format of the WriteSVGImage method is:
3432 % MagickBooleanType WriteSVGImage(const ImageInfo *image_info,
3433 % Image *image,ExceptionInfo *exception)
3435 % A description of each parameter follows.
3437 % o image_info: the image info.
3439 % o image: The image.
3441 % o exception: return any errors or warnings in this structure.
3445 static void AffineToTransform(Image *image,AffineMatrix *affine)
3448 transform[MagickPathExtent];
3450 if ((fabs(affine->tx) < MagickEpsilon) && (fabs(affine->ty) < MagickEpsilon))
3452 if ((fabs(affine->rx) < MagickEpsilon) &&
3453 (fabs(affine->ry) < MagickEpsilon))
3455 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3456 (fabs(affine->sy-1.0) < MagickEpsilon))
3458 (void) WriteBlobString(image,"\">\n");
3461 (void) FormatLocaleString(transform,MagickPathExtent,
3462 "\" transform=\"scale(%g,%g)\">\n",affine->sx,affine->sy);
3463 (void) WriteBlobString(image,transform);
3468 if ((fabs(affine->sx-affine->sy) < MagickEpsilon) &&
3469 (fabs(affine->rx+affine->ry) < MagickEpsilon) &&
3470 (fabs(affine->sx*affine->sx+affine->rx*affine->rx-1.0) <
3476 theta=(180.0/MagickPI)*atan2(affine->rx,affine->sx);
3477 (void) FormatLocaleString(transform,MagickPathExtent,
3478 "\" transform=\"rotate(%g)\">\n",theta);
3479 (void) WriteBlobString(image,transform);
3486 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3487 (fabs(affine->rx) < MagickEpsilon) &&
3488 (fabs(affine->ry) < MagickEpsilon) &&
3489 (fabs(affine->sy-1.0) < MagickEpsilon))
3491 (void) FormatLocaleString(transform,MagickPathExtent,
3492 "\" transform=\"translate(%g,%g)\">\n",affine->tx,affine->ty);
3493 (void) WriteBlobString(image,transform);
3497 (void) FormatLocaleString(transform,MagickPathExtent,
3498 "\" transform=\"matrix(%g %g %g %g %g %g)\">\n",
3499 affine->sx,affine->rx,affine->ry,affine->sy,affine->tx,affine->ty);
3500 (void) WriteBlobString(image,transform);
3503 static MagickBooleanType IsPoint(const char *point)
3511 value=strtol(point,&p,10);
3513 return(p != point ? MagickTrue : MagickFalse);
3516 static MagickBooleanType TraceSVGImage(Image *image,ExceptionInfo *exception)
3518 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
3523 at_fitting_opts_type
3535 register const Quantum
3549 Trace image and write as SVG.
3551 fitting_options=at_fitting_opts_new();
3552 output_options=at_output_opts_new();
3553 (void) SetImageGray(image,exception);
3554 type=GetImageType(image);
3556 if ((type == BilevelType) || (type == GrayscaleType))
3558 trace=at_bitmap_new(image->columns,image->rows,number_planes);
3560 for (y=0; y < (ssize_t) image->rows; y++)
3562 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3563 if (p == (const Quantum *) NULL)
3565 for (x=0; x < (ssize_t) image->columns; x++)
3567 trace->bitmap[i++]=GetPixelRed(image,p);
3568 if (number_planes == 3)
3570 trace->bitmap[i++]=GetPixelGreen(image,p);
3571 trace->bitmap[i++]=GetPixelBlue(image,p);
3573 p+=GetPixelChannels(image);
3576 splines=at_splines_new_full(trace,fitting_options,NULL,NULL,NULL,NULL,NULL,
3578 at_splines_write(at_output_get_handler_by_suffix((char *) "svg"),
3579 GetBlobFileHandle(image),image->filename,output_options,splines,NULL,
3584 at_splines_free(splines);
3585 at_bitmap_free(trace);
3586 at_output_opts_free(output_options);
3587 at_fitting_opts_free(fitting_options);
3593 message[MagickPathExtent];
3614 (void) WriteBlobString(image,
3615 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");
3616 (void) WriteBlobString(image,
3617 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"");
3618 (void) WriteBlobString(image,
3619 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
3620 (void) FormatLocaleString(message,MagickPathExtent,
3621 "<svg version=\"1.1\" id=\"Layer_1\" "
3622 "xmlns=\"http://www.w3.org/2000/svg\" "
3623 "xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\" "
3624 "width=\"%.20gpx\" height=\"%.20gpx\" viewBox=\"0 0 %.20g %.20g\" "
3625 "enable-background=\"new 0 0 %.20g %.20g\" xml:space=\"preserve\">",
3626 (double) image->columns,(double) image->rows,
3627 (double) image->columns,(double) image->rows,
3628 (double) image->columns,(double) image->rows);
3629 (void) WriteBlobString(image,message);
3630 clone_image=CloneImage(image,0,0,MagickTrue,exception);
3631 if (clone_image == (Image *) NULL)
3632 return(MagickFalse);
3633 image_info=AcquireImageInfo();
3634 (void) CopyMagickString(image_info->magick,"PNG",MagickPathExtent);
3636 blob=(unsigned char *) ImageToBlob(image_info,clone_image,&blob_length,
3638 clone_image=DestroyImage(clone_image);
3639 image_info=DestroyImageInfo(image_info);
3640 if (blob == (unsigned char *) NULL)
3641 return(MagickFalse);
3643 base64=Base64Encode(blob,blob_length,&encode_length);
3644 blob=(unsigned char *) RelinquishMagickMemory(blob);
3645 (void) FormatLocaleString(message,MagickPathExtent,
3646 " <image id=\"image%.20g\" width=\"%.20g\" height=\"%.20g\" "
3647 "x=\"%.20g\" y=\"%.20g\"\n xlink:href=\"data:image/png;base64,",
3648 (double) image->scene,(double) image->columns,(double) image->rows,
3649 (double) image->page.x,(double) image->page.y);
3650 (void) WriteBlobString(image,message);
3652 for (i=(ssize_t) encode_length; i > 0; i-=76)
3654 (void) FormatLocaleString(message,MagickPathExtent,"%.76s",p);
3655 (void) WriteBlobString(image,message);
3658 (void) WriteBlobString(image,"\n");
3660 base64=DestroyString(base64);
3661 (void) WriteBlobString(image,"\" />\n");
3662 (void) WriteBlobString(image,"</svg>\n");
3669 static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
3670 ExceptionInfo *exception)
3672 #define BezierQuantum 200
3678 keyword[MagickPathExtent],
3679 message[MagickPathExtent],
3680 name[MagickPathExtent],
3683 type[MagickPathExtent];
3724 Open output image file.
3726 assert(image_info != (const ImageInfo *) NULL);
3727 assert(image_info->signature == MagickCoreSignature);
3728 assert(image != (Image *) NULL);
3729 assert(image->signature == MagickCoreSignature);
3730 if (image->debug != MagickFalse)
3731 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3732 assert(exception != (ExceptionInfo *) NULL);
3733 assert(exception->signature == MagickCoreSignature);
3734 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
3735 if (status == MagickFalse)
3737 value=GetImageArtifact(image,"SVG");
3738 if (value != (char *) NULL)
3740 (void) WriteBlobString(image,value);
3741 (void) CloseBlob(image);
3744 value=GetImageArtifact(image,"MVG");
3745 if (value == (char *) NULL)
3746 return(TraceSVGImage(image,exception));
3750 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3751 (void) WriteBlobString(image,
3752 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3753 (void) WriteBlobString(image,
3754 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3755 (void) FormatLocaleString(message,MagickPathExtent,
3756 "<svg width=\"%.20g\" height=\"%.20g\">\n",(double) image->columns,(double)
3758 (void) WriteBlobString(image,message);
3760 Allocate primitive info memory.
3763 primitive_info=(PrimitiveInfo *) AcquireQuantumMemory(number_points,
3764 sizeof(*primitive_info));
3765 if (primitive_info == (PrimitiveInfo *) NULL)
3766 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3767 GetAffineMatrix(&affine);
3768 token=AcquireString(value);
3769 extent=strlen(token)+MagickPathExtent;
3773 for (q=(const char *) value; *q != '\0'; )
3776 Interpret graphic primitive.
3778 GetNextToken(q,&q,MagickPathExtent,keyword);
3779 if (*keyword == '\0')
3781 if (*keyword == '#')
3786 if (active != MagickFalse)
3788 AffineToTransform(image,&affine);
3791 (void) WriteBlobString(image,"<desc>");
3792 (void) WriteBlobString(image,keyword+1);
3793 for ( ; (*q != '\n') && (*q != '\0'); q++)
3796 case '<': (void) WriteBlobString(image,"<"); break;
3797 case '>': (void) WriteBlobString(image,">"); break;
3798 case '&': (void) WriteBlobString(image,"&"); break;
3799 default: (void) WriteBlobByte(image,*q); break;
3801 (void) WriteBlobString(image,"</desc>\n");
3804 primitive_type=UndefinedPrimitive;
3812 if (LocaleCompare("affine",keyword) == 0)
3814 GetNextToken(q,&q,extent,token);
3815 affine.sx=StringToDouble(token,&next_token);
3816 GetNextToken(q,&q,extent,token);
3818 GetNextToken(q,&q,extent,token);
3819 affine.rx=StringToDouble(token,&next_token);
3820 GetNextToken(q,&q,extent,token);
3822 GetNextToken(q,&q,extent,token);
3823 affine.ry=StringToDouble(token,&next_token);
3824 GetNextToken(q,&q,extent,token);
3826 GetNextToken(q,&q,extent,token);
3827 affine.sy=StringToDouble(token,&next_token);
3828 GetNextToken(q,&q,extent,token);
3830 GetNextToken(q,&q,extent,token);
3831 affine.tx=StringToDouble(token,&next_token);
3832 GetNextToken(q,&q,extent,token);
3834 GetNextToken(q,&q,extent,token);
3835 affine.ty=StringToDouble(token,&next_token);
3838 if (LocaleCompare("alpha",keyword) == 0)
3840 primitive_type=AlphaPrimitive;
3843 if (LocaleCompare("angle",keyword) == 0)
3845 GetNextToken(q,&q,extent,token);
3846 affine.rx=StringToDouble(token,&next_token);
3847 affine.ry=StringToDouble(token,&next_token);
3850 if (LocaleCompare("arc",keyword) == 0)
3852 primitive_type=ArcPrimitive;
3861 if (LocaleCompare("bezier",keyword) == 0)
3863 primitive_type=BezierPrimitive;
3872 if (LocaleCompare("clip-path",keyword) == 0)
3874 GetNextToken(q,&q,extent,token);
3875 (void) FormatLocaleString(message,MagickPathExtent,
3876 "clip-path:url(#%s);",token);
3877 (void) WriteBlobString(image,message);
3880 if (LocaleCompare("clip-rule",keyword) == 0)
3882 GetNextToken(q,&q,extent,token);
3883 (void) FormatLocaleString(message,MagickPathExtent,
3884 "clip-rule:%s;",token);
3885 (void) WriteBlobString(image,message);
3888 if (LocaleCompare("clip-units",keyword) == 0)
3890 GetNextToken(q,&q,extent,token);
3891 (void) FormatLocaleString(message,MagickPathExtent,
3892 "clipPathUnits=%s;",token);
3893 (void) WriteBlobString(image,message);
3896 if (LocaleCompare("circle",keyword) == 0)
3898 primitive_type=CirclePrimitive;
3901 if (LocaleCompare("color",keyword) == 0)
3903 primitive_type=ColorPrimitive;
3912 if (LocaleCompare("decorate",keyword) == 0)
3914 GetNextToken(q,&q,extent,token);
3915 (void) FormatLocaleString(message,MagickPathExtent,
3916 "text-decoration:%s;",token);
3917 (void) WriteBlobString(image,message);
3926 if (LocaleCompare("ellipse",keyword) == 0)
3928 primitive_type=EllipsePrimitive;
3937 if (LocaleCompare("fill",keyword) == 0)
3939 GetNextToken(q,&q,extent,token);
3940 (void) FormatLocaleString(message,MagickPathExtent,"fill:%s;",
3942 (void) WriteBlobString(image,message);
3945 if (LocaleCompare("fill-rule",keyword) == 0)
3947 GetNextToken(q,&q,extent,token);
3948 (void) FormatLocaleString(message,MagickPathExtent,
3949 "fill-rule:%s;",token);
3950 (void) WriteBlobString(image,message);
3953 if (LocaleCompare("fill-opacity",keyword) == 0)
3955 GetNextToken(q,&q,extent,token);
3956 (void) FormatLocaleString(message,MagickPathExtent,
3957 "fill-opacity:%s;",token);
3958 (void) WriteBlobString(image,message);
3961 if (LocaleCompare("font-family",keyword) == 0)
3963 GetNextToken(q,&q,extent,token);
3964 (void) FormatLocaleString(message,MagickPathExtent,
3965 "font-family:%s;",token);
3966 (void) WriteBlobString(image,message);
3969 if (LocaleCompare("font-stretch",keyword) == 0)
3971 GetNextToken(q,&q,extent,token);
3972 (void) FormatLocaleString(message,MagickPathExtent,
3973 "font-stretch:%s;",token);
3974 (void) WriteBlobString(image,message);
3977 if (LocaleCompare("font-style",keyword) == 0)
3979 GetNextToken(q,&q,extent,token);
3980 (void) FormatLocaleString(message,MagickPathExtent,
3981 "font-style:%s;",token);
3982 (void) WriteBlobString(image,message);
3985 if (LocaleCompare("font-size",keyword) == 0)
3987 GetNextToken(q,&q,extent,token);
3988 (void) FormatLocaleString(message,MagickPathExtent,
3989 "font-size:%s;",token);
3990 (void) WriteBlobString(image,message);
3993 if (LocaleCompare("font-weight",keyword) == 0)
3995 GetNextToken(q,&q,extent,token);
3996 (void) FormatLocaleString(message,MagickPathExtent,
3997 "font-weight:%s;",token);
3998 (void) WriteBlobString(image,message);
4007 if (LocaleCompare("gradient-units",keyword) == 0)
4009 GetNextToken(q,&q,extent,token);
4012 if (LocaleCompare("text-align",keyword) == 0)
4014 GetNextToken(q,&q,extent,token);
4015 (void) FormatLocaleString(message,MagickPathExtent,
4016 "text-align %s ",token);
4017 (void) WriteBlobString(image,message);
4020 if (LocaleCompare("text-anchor",keyword) == 0)
4022 GetNextToken(q,&q,extent,token);
4023 (void) FormatLocaleString(message,MagickPathExtent,
4024 "text-anchor %s ",token);
4025 (void) WriteBlobString(image,message);
4034 if (LocaleCompare("image",keyword) == 0)
4036 GetNextToken(q,&q,extent,token);
4037 primitive_type=ImagePrimitive;
4046 if (LocaleCompare("line",keyword) == 0)
4048 primitive_type=LinePrimitive;
4057 if (LocaleCompare("opacity",keyword) == 0)
4059 GetNextToken(q,&q,extent,token);
4060 (void) FormatLocaleString(message,MagickPathExtent,"opacity %s ",
4062 (void) WriteBlobString(image,message);
4071 if (LocaleCompare("path",keyword) == 0)
4073 primitive_type=PathPrimitive;
4076 if (LocaleCompare("point",keyword) == 0)
4078 primitive_type=PointPrimitive;
4081 if (LocaleCompare("polyline",keyword) == 0)
4083 primitive_type=PolylinePrimitive;
4086 if (LocaleCompare("polygon",keyword) == 0)
4088 primitive_type=PolygonPrimitive;
4091 if (LocaleCompare("pop",keyword) == 0)
4093 GetNextToken(q,&q,extent,token);
4094 if (LocaleCompare("clip-path",token) == 0)
4096 (void) WriteBlobString(image,"</clipPath>\n");
4099 if (LocaleCompare("defs",token) == 0)
4101 (void) WriteBlobString(image,"</defs>\n");
4104 if (LocaleCompare("gradient",token) == 0)
4106 (void) FormatLocaleString(message,MagickPathExtent,
4107 "</%sGradient>\n",type);
4108 (void) WriteBlobString(image,message);
4111 if (LocaleCompare("graphic-context",token) == 0)
4115 ThrowWriterException(DrawError,
4116 "UnbalancedGraphicContextPushPop");
4117 (void) WriteBlobString(image,"</g>\n");
4119 if (LocaleCompare("pattern",token) == 0)
4121 (void) WriteBlobString(image,"</pattern>\n");
4124 if (LocaleCompare("defs",token) == 0)
4125 (void) WriteBlobString(image,"</g>\n");
4128 if (LocaleCompare("push",keyword) == 0)
4130 GetNextToken(q,&q,extent,token);
4131 if (LocaleCompare("clip-path",token) == 0)
4133 GetNextToken(q,&q,extent,token);
4134 (void) FormatLocaleString(message,MagickPathExtent,
4135 "<clipPath id=\"%s\">\n",token);
4136 (void) WriteBlobString(image,message);
4139 if (LocaleCompare("defs",token) == 0)
4141 (void) WriteBlobString(image,"<defs>\n");
4144 if (LocaleCompare("gradient",token) == 0)
4146 GetNextToken(q,&q,extent,token);
4147 (void) CopyMagickString(name,token,MagickPathExtent);
4148 GetNextToken(q,&q,extent,token);
4149 (void) CopyMagickString(type,token,MagickPathExtent);
4150 GetNextToken(q,&q,extent,token);
4151 svg_info.segment.x1=StringToDouble(token,&next_token);
4152 svg_info.element.cx=StringToDouble(token,&next_token);
4153 GetNextToken(q,&q,extent,token);
4155 GetNextToken(q,&q,extent,token);
4156 svg_info.segment.y1=StringToDouble(token,&next_token);
4157 svg_info.element.cy=StringToDouble(token,&next_token);
4158 GetNextToken(q,&q,extent,token);
4160 GetNextToken(q,&q,extent,token);
4161 svg_info.segment.x2=StringToDouble(token,&next_token);
4162 svg_info.element.major=StringToDouble(token,
4164 GetNextToken(q,&q,extent,token);
4166 GetNextToken(q,&q,extent,token);
4167 svg_info.segment.y2=StringToDouble(token,&next_token);
4168 svg_info.element.minor=StringToDouble(token,
4170 (void) FormatLocaleString(message,MagickPathExtent,
4171 "<%sGradient id=\"%s\" x1=\"%g\" y1=\"%g\" x2=\"%g\" "
4172 "y2=\"%g\">\n",type,name,svg_info.segment.x1,
4173 svg_info.segment.y1,svg_info.segment.x2,svg_info.segment.y2);
4174 if (LocaleCompare(type,"radial") == 0)
4176 GetNextToken(q,&q,extent,token);
4178 GetNextToken(q,&q,extent,token);
4179 svg_info.element.angle=StringToDouble(token,
4181 (void) FormatLocaleString(message,MagickPathExtent,
4182 "<%sGradient id=\"%s\" cx=\"%g\" cy=\"%g\" r=\"%g\" "
4183 "fx=\"%g\" fy=\"%g\">\n",type,name,
4184 svg_info.element.cx,svg_info.element.cy,
4185 svg_info.element.angle,svg_info.element.major,
4186 svg_info.element.minor);
4188 (void) WriteBlobString(image,message);
4191 if (LocaleCompare("graphic-context",token) == 0)
4196 AffineToTransform(image,&affine);
4199 (void) WriteBlobString(image,"<g style=\"");
4202 if (LocaleCompare("pattern",token) == 0)
4204 GetNextToken(q,&q,extent,token);
4205 (void) CopyMagickString(name,token,MagickPathExtent);
4206 GetNextToken(q,&q,extent,token);
4207 svg_info.bounds.x=StringToDouble(token,&next_token);
4208 GetNextToken(q,&q,extent,token);
4210 GetNextToken(q,&q,extent,token);
4211 svg_info.bounds.y=StringToDouble(token,&next_token);
4212 GetNextToken(q,&q,extent,token);
4214 GetNextToken(q,&q,extent,token);
4215 svg_info.bounds.width=StringToDouble(token,
4217 GetNextToken(q,&q,extent,token);
4219 GetNextToken(q,&q,extent,token);
4220 svg_info.bounds.height=StringToDouble(token,(char **) NULL);
4221 (void) FormatLocaleString(message,MagickPathExtent,
4222 "<pattern id=\"%s\" x=\"%g\" y=\"%g\" width=\"%g\" "
4223 "height=\"%g\">\n",name,svg_info.bounds.x,svg_info.bounds.y,
4224 svg_info.bounds.width,svg_info.bounds.height);
4225 (void) WriteBlobString(image,message);
4236 if (LocaleCompare("rectangle",keyword) == 0)
4238 primitive_type=RectanglePrimitive;
4241 if (LocaleCompare("roundRectangle",keyword) == 0)
4243 primitive_type=RoundRectanglePrimitive;
4246 if (LocaleCompare("rotate",keyword) == 0)
4248 GetNextToken(q,&q,extent,token);
4249 (void) FormatLocaleString(message,MagickPathExtent,"rotate(%s) ",
4251 (void) WriteBlobString(image,message);
4260 if (LocaleCompare("scale",keyword) == 0)
4262 GetNextToken(q,&q,extent,token);
4263 affine.sx=StringToDouble(token,&next_token);
4264 GetNextToken(q,&q,extent,token);
4266 GetNextToken(q,&q,extent,token);
4267 affine.sy=StringToDouble(token,&next_token);
4270 if (LocaleCompare("skewX",keyword) == 0)
4272 GetNextToken(q,&q,extent,token);
4273 (void) FormatLocaleString(message,MagickPathExtent,"skewX(%s) ",
4275 (void) WriteBlobString(image,message);
4278 if (LocaleCompare("skewY",keyword) == 0)
4280 GetNextToken(q,&q,extent,token);
4281 (void) FormatLocaleString(message,MagickPathExtent,"skewY(%s) ",
4283 (void) WriteBlobString(image,message);
4286 if (LocaleCompare("stop-color",keyword) == 0)
4289 color[MagickPathExtent];
4291 GetNextToken(q,&q,extent,token);
4292 (void) CopyMagickString(color,token,MagickPathExtent);
4293 GetNextToken(q,&q,extent,token);
4294 (void) FormatLocaleString(message,MagickPathExtent,
4295 " <stop offset=\"%s\" stop-color=\"%s\" />\n",token,color);
4296 (void) WriteBlobString(image,message);
4299 if (LocaleCompare("stroke",keyword) == 0)
4301 GetNextToken(q,&q,extent,token);
4302 (void) FormatLocaleString(message,MagickPathExtent,"stroke:%s;",
4304 (void) WriteBlobString(image,message);
4307 if (LocaleCompare("stroke-antialias",keyword) == 0)
4309 GetNextToken(q,&q,extent,token);
4310 (void) FormatLocaleString(message,MagickPathExtent,
4311 "stroke-antialias:%s;",token);
4312 (void) WriteBlobString(image,message);
4315 if (LocaleCompare("stroke-dasharray",keyword) == 0)
4323 GetNextToken(p,&p,extent,token);
4324 for (k=0; IsPoint(token); k++)
4325 GetNextToken(p,&p,extent,token);
4326 (void) WriteBlobString(image,"stroke-dasharray:");
4327 for (j=0; j < k; j++)
4329 GetNextToken(q,&q,extent,token);
4330 (void) FormatLocaleString(message,MagickPathExtent,"%s ",
4332 (void) WriteBlobString(image,message);
4334 (void) WriteBlobString(image,";");
4337 GetNextToken(q,&q,extent,token);
4338 (void) FormatLocaleString(message,MagickPathExtent,
4339 "stroke-dasharray:%s;",token);
4340 (void) WriteBlobString(image,message);
4343 if (LocaleCompare("stroke-dashoffset",keyword) == 0)
4345 GetNextToken(q,&q,extent,token);
4346 (void) FormatLocaleString(message,MagickPathExtent,
4347 "stroke-dashoffset:%s;",token);
4348 (void) WriteBlobString(image,message);
4351 if (LocaleCompare("stroke-linecap",keyword) == 0)
4353 GetNextToken(q,&q,extent,token);
4354 (void) FormatLocaleString(message,MagickPathExtent,
4355 "stroke-linecap:%s;",token);
4356 (void) WriteBlobString(image,message);
4359 if (LocaleCompare("stroke-linejoin",keyword) == 0)
4361 GetNextToken(q,&q,extent,token);
4362 (void) FormatLocaleString(message,MagickPathExtent,
4363 "stroke-linejoin:%s;",token);
4364 (void) WriteBlobString(image,message);
4367 if (LocaleCompare("stroke-miterlimit",keyword) == 0)
4369 GetNextToken(q,&q,extent,token);
4370 (void) FormatLocaleString(message,MagickPathExtent,
4371 "stroke-miterlimit:%s;",token);
4372 (void) WriteBlobString(image,message);
4375 if (LocaleCompare("stroke-opacity",keyword) == 0)
4377 GetNextToken(q,&q,extent,token);
4378 (void) FormatLocaleString(message,MagickPathExtent,
4379 "stroke-opacity:%s;",token);
4380 (void) WriteBlobString(image,message);
4383 if (LocaleCompare("stroke-width",keyword) == 0)
4385 GetNextToken(q,&q,extent,token);
4386 (void) FormatLocaleString(message,MagickPathExtent,
4387 "stroke-width:%s;",token);
4388 (void) WriteBlobString(image,message);
4397 if (LocaleCompare("text",keyword) == 0)
4399 primitive_type=TextPrimitive;
4402 if (LocaleCompare("text-antialias",keyword) == 0)
4404 GetNextToken(q,&q,extent,token);
4405 (void) FormatLocaleString(message,MagickPathExtent,
4406 "text-antialias:%s;",token);
4407 (void) WriteBlobString(image,message);
4410 if (LocaleCompare("tspan",keyword) == 0)
4412 primitive_type=TextPrimitive;
4415 if (LocaleCompare("translate",keyword) == 0)
4417 GetNextToken(q,&q,extent,token);
4418 affine.tx=StringToDouble(token,&next_token);
4419 GetNextToken(q,&q,extent,token);
4421 GetNextToken(q,&q,extent,token);
4422 affine.ty=StringToDouble(token,&next_token);
4431 if (LocaleCompare("viewbox",keyword) == 0)
4433 GetNextToken(q,&q,extent,token);
4435 GetNextToken(q,&q,extent,token);
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);
4454 if (status == MagickFalse)
4456 if (primitive_type == UndefinedPrimitive)
4459 Parse the primitive attributes.
4463 for (x=0; *q != '\0'; x++)
4468 if (IsPoint(q) == MagickFalse)
4470 GetNextToken(q,&q,extent,token);
4471 point.x=StringToDouble(token,&next_token);
4472 GetNextToken(q,&q,extent,token);
4474 GetNextToken(q,&q,extent,token);
4475 point.y=StringToDouble(token,&next_token);
4476 GetNextToken(q,(const char **) NULL,extent,token);
4478 GetNextToken(q,&q,extent,token);
4479 primitive_info[i].primitive=primitive_type;
4480 primitive_info[i].point=point;
4481 primitive_info[i].coordinates=0;
4482 primitive_info[i].method=FloodfillMethod;
4484 if (i < (ssize_t) (number_points-6*BezierQuantum-360))
4486 number_points+=6*BezierQuantum+360;
4487 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4488 number_points,sizeof(*primitive_info));
4489 if (primitive_info == (PrimitiveInfo *) NULL)
4491 (void) ThrowMagickException(exception,GetMagickModule(),
4492 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
4496 primitive_info[j].primitive=primitive_type;
4497 primitive_info[j].coordinates=x;
4498 primitive_info[j].method=FloodfillMethod;
4499 primitive_info[j].text=(char *) NULL;
4502 AffineToTransform(image,&affine);
4506 switch (primitive_type)
4508 case PointPrimitive:
4511 if (primitive_info[j].coordinates != 1)
4520 if (primitive_info[j].coordinates != 2)
4525 (void) FormatLocaleString(message,MagickPathExtent,
4526 " <line x1=\"%g\" y1=\"%g\" x2=\"%g\" y2=\"%g\"/>\n",
4527 primitive_info[j].point.x,primitive_info[j].point.y,
4528 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4529 (void) WriteBlobString(image,message);
4532 case RectanglePrimitive:
4534 if (primitive_info[j].coordinates != 2)
4539 (void) FormatLocaleString(message,MagickPathExtent,
4540 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"/>\n",
4541 primitive_info[j].point.x,primitive_info[j].point.y,
4542 primitive_info[j+1].point.x-primitive_info[j].point.x,
4543 primitive_info[j+1].point.y-primitive_info[j].point.y);
4544 (void) WriteBlobString(image,message);
4547 case RoundRectanglePrimitive:
4549 if (primitive_info[j].coordinates != 3)
4554 (void) FormatLocaleString(message,MagickPathExtent,
4555 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" rx=\"%g\" "
4556 "ry=\"%g\"/>\n",primitive_info[j].point.x,
4557 primitive_info[j].point.y,primitive_info[j+1].point.x-
4558 primitive_info[j].point.x,primitive_info[j+1].point.y-
4559 primitive_info[j].point.y,primitive_info[j+2].point.x,
4560 primitive_info[j+2].point.y);
4561 (void) WriteBlobString(image,message);
4566 if (primitive_info[j].coordinates != 3)
4573 case EllipsePrimitive:
4575 if (primitive_info[j].coordinates != 3)
4580 (void) FormatLocaleString(message,MagickPathExtent,
4581 " <ellipse cx=\"%g\" cy=\"%g\" rx=\"%g\" ry=\"%g\"/>\n",
4582 primitive_info[j].point.x,primitive_info[j].point.y,
4583 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4584 (void) WriteBlobString(image,message);
4587 case CirclePrimitive:
4593 if (primitive_info[j].coordinates != 2)
4598 alpha=primitive_info[j+1].point.x-primitive_info[j].point.x;
4599 beta=primitive_info[j+1].point.y-primitive_info[j].point.y;
4600 (void) FormatLocaleString(message,MagickPathExtent,
4601 " <circle cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
4602 primitive_info[j].point.x,primitive_info[j].point.y,
4604 (void) WriteBlobString(image,message);
4607 case PolylinePrimitive:
4609 if (primitive_info[j].coordinates < 2)
4614 (void) CopyMagickString(message," <polyline points=\"",
4616 (void) WriteBlobString(image,message);
4617 length=strlen(message);
4620 (void) FormatLocaleString(message,MagickPathExtent,"%g,%g ",
4621 primitive_info[j].point.x,primitive_info[j].point.y);
4622 length+=strlen(message);
4625 (void) WriteBlobString(image,"\n ");
4626 length=strlen(message)+5;
4628 (void) WriteBlobString(image,message);
4630 (void) WriteBlobString(image,"\"/>\n");
4633 case PolygonPrimitive:
4635 if (primitive_info[j].coordinates < 3)
4640 primitive_info[i]=primitive_info[j];
4641 primitive_info[i].coordinates=0;
4642 primitive_info[j].coordinates++;
4644 (void) CopyMagickString(message," <polygon points=\"",MagickPathExtent);
4645 (void) WriteBlobString(image,message);
4646 length=strlen(message);
4649 (void) FormatLocaleString(message,MagickPathExtent,"%g,%g ",
4650 primitive_info[j].point.x,primitive_info[j].point.y);
4651 length+=strlen(message);
4654 (void) WriteBlobString(image,"\n ");
4655 length=strlen(message)+5;
4657 (void) WriteBlobString(image,message);
4659 (void) WriteBlobString(image,"\"/>\n");
4662 case BezierPrimitive:
4664 if (primitive_info[j].coordinates < 3)
4676 GetNextToken(q,&q,extent,token);
4677 number_attributes=1;
4678 for (p=token; *p != '\0'; p++)
4679 if (isalpha((int) *p))
4680 number_attributes++;
4681 if (i > (ssize_t) (number_points-6*BezierQuantum*number_attributes-1))
4683 number_points+=6*BezierQuantum*number_attributes;
4684 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4685 number_points,sizeof(*primitive_info));
4686 if (primitive_info == (PrimitiveInfo *) NULL)
4688 (void) ThrowMagickException(exception,GetMagickModule(),
4689 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4694 (void) WriteBlobString(image," <path d=\"");
4695 (void) WriteBlobString(image,token);
4696 (void) WriteBlobString(image,"\"/>\n");
4699 case AlphaPrimitive:
4700 case ColorPrimitive:
4702 if (primitive_info[j].coordinates != 1)
4707 GetNextToken(q,&q,extent,token);
4708 if (LocaleCompare("point",token) == 0)
4709 primitive_info[j].method=PointMethod;
4710 if (LocaleCompare("replace",token) == 0)
4711 primitive_info[j].method=ReplaceMethod;
4712 if (LocaleCompare("floodfill",token) == 0)
4713 primitive_info[j].method=FloodfillMethod;
4714 if (LocaleCompare("filltoborder",token) == 0)
4715 primitive_info[j].method=FillToBorderMethod;
4716 if (LocaleCompare("reset",token) == 0)
4717 primitive_info[j].method=ResetMethod;
4725 if (primitive_info[j].coordinates != 1)
4730 GetNextToken(q,&q,extent,token);
4731 (void) FormatLocaleString(message,MagickPathExtent,
4732 " <text x=\"%g\" y=\"%g\">",primitive_info[j].point.x,
4733 primitive_info[j].point.y);
4734 (void) WriteBlobString(image,message);
4735 for (p=token; *p != '\0'; p++)
4738 case '<': (void) WriteBlobString(image,"<"); break;
4739 case '>': (void) WriteBlobString(image,">"); break;
4740 case '&': (void) WriteBlobString(image,"&"); break;
4741 default: (void) WriteBlobByte(image,*p); break;
4743 (void) WriteBlobString(image,"</text>\n");
4746 case ImagePrimitive:
4748 if (primitive_info[j].coordinates != 2)
4753 GetNextToken(q,&q,extent,token);
4754 (void) FormatLocaleString(message,MagickPathExtent,
4755 " <image x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" "
4756 "xlink:href=\"%s\"/>\n",primitive_info[j].point.x,
4757 primitive_info[j].point.y,primitive_info[j+1].point.x,
4758 primitive_info[j+1].point.y,token);
4759 (void) WriteBlobString(image,message);
4763 if (primitive_info == (PrimitiveInfo *) NULL)
4765 primitive_info[i].primitive=UndefinedPrimitive;
4766 if (status == MagickFalse)
4769 (void) WriteBlobString(image,"</svg>\n");
4771 Relinquish resources.
4773 token=DestroyString(token);
4774 if (primitive_info != (PrimitiveInfo *) NULL)
4775 primitive_info=(PrimitiveInfo *) RelinquishMagickMemory(primitive_info);
4776 (void) CloseBlob(image);