2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Scalable Vector Graphics Format %
21 % Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
22 % dedicated to making software imaging solutions freely available. %
24 % You may not use this file except in compliance with the License. You may %
25 % obtain a copy of the License at %
27 % http://www.imagemagick.org/script/license.php %
29 % Unless required by applicable law or agreed to in writing, software %
30 % distributed under the License is distributed on an "AS IS" BASIS, %
31 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
32 % See the License for the specific language governing permissions and %
33 % limitations under the License. %
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/annotate.h"
45 #include "MagickCore/artifact.h"
46 #include "MagickCore/attribute.h"
47 #include "MagickCore/blob.h"
48 #include "MagickCore/blob-private.h"
49 #include "MagickCore/cache.h"
50 #include "MagickCore/constitute.h"
51 #include "MagickCore/composite-private.h"
52 #include "MagickCore/draw.h"
53 #include "MagickCore/exception.h"
54 #include "MagickCore/exception-private.h"
55 #include "MagickCore/gem.h"
56 #include "MagickCore/image.h"
57 #include "MagickCore/image-private.h"
58 #include "MagickCore/list.h"
59 #include "MagickCore/log.h"
60 #include "MagickCore/magick.h"
61 #include "MagickCore/memory_.h"
62 #include "MagickCore/module.h"
63 #include "MagickCore/monitor.h"
64 #include "MagickCore/monitor-private.h"
65 #include "MagickCore/quantum-private.h"
66 #include "MagickCore/pixel-accessor.h"
67 #include "MagickCore/property.h"
68 #include "MagickCore/resource_.h"
69 #include "MagickCore/static.h"
70 #include "MagickCore/string_.h"
71 #include "MagickCore/string-private.h"
72 #include "MagickCore/token.h"
73 #include "MagickCore/utility.h"
74 #if defined(MAGICKCORE_XML_DELEGATE)
75 # if defined(MAGICKCORE_WINDOWS_SUPPORT)
76 # if defined(__MINGW32__)
79 # include <win32config.h>
82 # include <libxml/parser.h>
83 # include <libxml/xmlmemory.h>
84 # include <libxml/parserInternals.h>
85 # include <libxml/xmlerror.h>
88 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
89 #include "autotrace/autotrace.h"
92 #if defined(MAGICKCORE_RSVG_DELEGATE)
93 #include "librsvg/rsvg.h"
94 #if defined(MAGICKCORE_CAIRO_DELEGATE)
95 #include "librsvg/rsvg-cairo.h"
97 #include "librsvg/librsvg-features.h"
101 Typedef declarations.
103 typedef struct _BoundingBox
112 typedef struct _ElementInfo
122 typedef struct _SVGInfo
176 #if defined(MAGICKCORE_XML_DELEGATE)
186 Forward declarations.
188 static MagickBooleanType
189 WriteSVGImage(const ImageInfo *,Image *,ExceptionInfo *);
192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
200 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
202 % IsSVG()() returns MagickTrue if the image format type, identified by the
203 % magick string, is SVG.
205 % The format of the IsSVG method is:
207 % MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
209 % A description of each parameter follows:
211 % o magick: compare image format pattern against these bytes.
213 % o length: Specifies the length of the magick string.
216 static MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
220 if (LocaleNCompare((const char *) magick,"?xml",4) == 0)
225 #if defined(MAGICKCORE_XML_DELEGATE)
227 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
231 % R e a d S V G I m a g e %
235 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
237 % ReadSVGImage() reads a Scalable Vector Gaphics file and returns it. It
238 % allocates the memory necessary for the new Image structure and returns a
239 % pointer to the new image.
241 % The format of the ReadSVGImage method is:
243 % Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
245 % A description of each parameter follows:
247 % o image_info: the image info.
249 % o exception: return any errors or warnings in this structure.
253 static SVGInfo *AcquireSVGInfo(void)
258 svg_info=(SVGInfo *) AcquireMagickMemory(sizeof(*svg_info));
259 if (svg_info == (SVGInfo *) NULL)
260 return((SVGInfo *) NULL);
261 (void) ResetMagickMemory(svg_info,0,sizeof(*svg_info));
262 svg_info->text=AcquireString("");
263 svg_info->scale=(double *) AcquireMagickMemory(sizeof(*svg_info->scale));
264 if (svg_info->scale == (double *) NULL)
265 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
266 GetAffineMatrix(&svg_info->affine);
267 svg_info->scale[0]=ExpandAffine(&svg_info->affine);
271 static SVGInfo *DestroySVGInfo(SVGInfo *svg_info)
273 if (svg_info->text != (char *) NULL)
274 svg_info->text=DestroyString(svg_info->text);
275 if (svg_info->scale != (double *) NULL)
276 svg_info->scale=(double *) (svg_info->scale);
277 if (svg_info->title != (char *) NULL)
278 svg_info->title=DestroyString(svg_info->title);
279 if (svg_info->comment != (char *) NULL)
280 svg_info->comment=DestroyString(svg_info->comment);
281 return((SVGInfo *) RelinquishMagickMemory(svg_info));
284 static double GetUserSpaceCoordinateValue(const SVGInfo *svg_info,int type,
288 token[MaxTextExtent];
296 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",string);
297 assert(string != (const char *) NULL);
298 p=(const char *) string;
299 GetMagickToken(p,&p,token);
300 value=InterpretLocaleValue(token,(char **) NULL);
301 if (strchr(token,'%') != (char *) NULL)
309 if (svg_info->view_box.width == 0.0)
311 return(svg_info->view_box.width*value/100.0);
315 if (svg_info->view_box.height == 0.0)
317 return(svg_info->view_box.height*value/100.0);
319 alpha=value-svg_info->view_box.width;
320 beta=value-svg_info->view_box.height;
321 return(hypot(alpha,beta)/sqrt(2.0)/100.0);
323 GetMagickToken(p,&p,token);
324 if (LocaleNCompare(token,"cm",2) == 0)
325 return(DefaultResolution*svg_info->scale[0]/2.54*value);
326 if (LocaleNCompare(token,"em",2) == 0)
327 return(svg_info->pointsize*value);
328 if (LocaleNCompare(token,"ex",2) == 0)
329 return(svg_info->pointsize*value/2.0);
330 if (LocaleNCompare(token,"in",2) == 0)
331 return(DefaultResolution*svg_info->scale[0]*value);
332 if (LocaleNCompare(token,"mm",2) == 0)
333 return(DefaultResolution*svg_info->scale[0]/25.4*value);
334 if (LocaleNCompare(token,"pc",2) == 0)
335 return(DefaultResolution*svg_info->scale[0]/6.0*value);
336 if (LocaleNCompare(token,"pt",2) == 0)
337 return(svg_info->scale[0]*value);
338 if (LocaleNCompare(token,"px",2) == 0)
343 static void StripStyleTokens(char *message)
352 assert(message != (char *) NULL);
353 if (*message == '\0')
355 length=strlen(message);
357 while (isspace((int) ((unsigned char) *p)) != 0)
360 while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
362 (void) CopyMagickMemory(message,p,(size_t) (q-p+1));
364 StripString(message);
367 static char **GetStyleTokens(void *context,const char *style,int *number_tokens)
379 svg_info=(SVGInfo *) context;
382 if (style == (const char *) NULL)
383 return((char **) NULL);
384 text=AcquireString(style);
385 (void) SubstituteString(&text,":","\n");
386 (void) SubstituteString(&text,";","\n");
387 tokens=StringToList(text);
388 text=DestroyString(text);
389 for (i=0; tokens[i] != (char *) NULL; i++)
390 StripStyleTokens(tokens[i]);
395 static char **GetTransformTokens(void *context,const char *text,
411 svg_info=(SVGInfo *) context;
413 if (text == (const char *) NULL)
414 return((char **) NULL);
416 Determine the number of arguments.
418 for (p=text; *p != '\0'; p++)
423 tokens=(char **) AcquireQuantumMemory(*number_tokens+2UL,sizeof(*tokens));
424 if (tokens == (char **) NULL)
426 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
427 ResourceLimitError,"MemoryAllocationFailed","`%s'",text);
428 return((char **) NULL);
431 Convert string to an ASCII list.
435 for (q=p; *q != '\0'; q++)
437 if ((*q != '(') && (*q != ')') && (*q != '\0'))
439 tokens[i]=AcquireString(p);
440 (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
441 StripString(tokens[i++]);
444 tokens[i]=AcquireString(p);
445 (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
446 StripString(tokens[i++]);
447 tokens[i]=(char *) NULL;
451 #if defined(__cplusplus) || defined(c_plusplus)
455 static int SVGIsStandalone(void *context)
461 Is this document tagged standalone?
463 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGIsStandalone()");
464 svg_info=(SVGInfo *) context;
465 return(svg_info->document->standalone == 1);
468 static int SVGHasInternalSubset(void *context)
474 Does this document has an internal subset?
476 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
477 " SAX.SVGHasInternalSubset()");
478 svg_info=(SVGInfo *) context;
479 return(svg_info->document->intSubset != NULL);
482 static int SVGHasExternalSubset(void *context)
488 Does this document has an external subset?
490 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
491 " SAX.SVGHasExternalSubset()");
492 svg_info=(SVGInfo *) context;
493 return(svg_info->document->extSubset != NULL);
496 static void SVGInternalSubset(void *context,const xmlChar *name,
497 const xmlChar *external_id,const xmlChar *system_id)
503 Does this document has an internal subset?
505 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
506 " SAX.internalSubset(%s, %s, %s)",(const char *) name,
507 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
508 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
509 svg_info=(SVGInfo *) context;
510 (void) xmlCreateIntSubset(svg_info->document,name,external_id,system_id);
513 static xmlParserInputPtr SVGResolveEntity(void *context,
514 const xmlChar *public_id,const xmlChar *system_id)
523 Special entity resolver, better left to the parser, it has more
524 context than the application layer. The default behaviour is to
525 not resolve the entities, in that case the ENTITY_REF nodes are
526 built in the structure (and the parameter values).
528 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
529 " SAX.resolveEntity(%s, %s)",
530 (public_id != (const xmlChar *) NULL ? (const char *) public_id : "none"),
531 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
532 svg_info=(SVGInfo *) context;
533 stream=xmlLoadExternalEntity((const char *) system_id,(const char *)
534 public_id,svg_info->parser);
538 static xmlEntityPtr SVGGetEntity(void *context,const xmlChar *name)
544 Get an entity by name.
546 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGGetEntity(%s)",
548 svg_info=(SVGInfo *) context;
549 return(xmlGetDocEntity(svg_info->document,name));
552 static xmlEntityPtr SVGGetParameterEntity(void *context,const xmlChar *name)
558 Get a parameter entity by name.
560 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
561 " SAX.getParameterEntity(%s)",name);
562 svg_info=(SVGInfo *) context;
563 return(xmlGetParameterEntity(svg_info->document,name));
566 static void SVGEntityDeclaration(void *context,const xmlChar *name,int type,
567 const xmlChar *public_id,const xmlChar *system_id,xmlChar *content)
573 An entity definition has been parsed.
575 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
576 " SAX.entityDecl(%s, %d, %s, %s, %s)",name,type,
577 public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
578 system_id != (xmlChar *) NULL ? (const char *) system_id : "none",content);
579 svg_info=(SVGInfo *) context;
580 if (svg_info->parser->inSubset == 1)
581 (void) xmlAddDocEntity(svg_info->document,name,type,public_id,system_id,
584 if (svg_info->parser->inSubset == 2)
585 (void) xmlAddDtdEntity(svg_info->document,name,type,public_id,system_id,
589 static void SVGAttributeDeclaration(void *context,const xmlChar *element,
590 const xmlChar *name,int type,int value,const xmlChar *default_value,
591 xmlEnumerationPtr tree)
604 An attribute definition has been parsed.
606 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
607 " SAX.attributeDecl(%s, %s, %d, %d, %s, ...)",element,name,type,value,
609 svg_info=(SVGInfo *) context;
610 fullname=(xmlChar *) NULL;
611 prefix=(xmlChar *) NULL;
612 parser=svg_info->parser;
613 fullname=(xmlChar *) xmlSplitQName(parser,name,&prefix);
614 if (parser->inSubset == 1)
615 (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->intSubset,
616 element,fullname,prefix,(xmlAttributeType) type,
617 (xmlAttributeDefault) value,default_value,tree);
619 if (parser->inSubset == 2)
620 (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->extSubset,
621 element,fullname,prefix,(xmlAttributeType) type,
622 (xmlAttributeDefault) value,default_value,tree);
623 if (prefix != (xmlChar *) NULL)
625 if (fullname != (xmlChar *) NULL)
629 static void SVGElementDeclaration(void *context,const xmlChar *name,int type,
630 xmlElementContentPtr content)
639 An element definition has been parsed.
641 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
642 " SAX.elementDecl(%s, %d, ...)",name,type);
643 svg_info=(SVGInfo *) context;
644 parser=svg_info->parser;
645 if (parser->inSubset == 1)
646 (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->intSubset,
647 name,(xmlElementTypeVal) type,content);
649 if (parser->inSubset == 2)
650 (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->extSubset,
651 name,(xmlElementTypeVal) type,content);
654 static void SVGNotationDeclaration(void *context,const xmlChar *name,
655 const xmlChar *public_id,const xmlChar *system_id)
664 What to do when a notation declaration has been parsed.
666 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
667 " SAX.notationDecl(%s, %s, %s)",name,
668 public_id != (const xmlChar *) NULL ? (const char *) public_id : "none",
669 system_id != (const xmlChar *) NULL ? (const char *) system_id : "none");
670 svg_info=(SVGInfo *) context;
671 parser=svg_info->parser;
672 if (parser->inSubset == 1)
673 (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
674 name,public_id,system_id);
676 if (parser->inSubset == 2)
677 (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
678 name,public_id,system_id);
681 static void SVGUnparsedEntityDeclaration(void *context,const xmlChar *name,
682 const xmlChar *public_id,const xmlChar *system_id,const xmlChar *notation)
688 What to do when an unparsed entity declaration is parsed.
690 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
691 " SAX.unparsedEntityDecl(%s, %s, %s, %s)",name,
692 public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
693 system_id != (xmlChar *) NULL ? (const char *) system_id : "none",notation);
694 svg_info=(SVGInfo *) context;
695 (void) xmlAddDocEntity(svg_info->document,name,
696 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,public_id,system_id,notation);
700 static void SVGSetDocumentLocator(void *context,xmlSAXLocatorPtr location)
706 Receive the document locator at startup, actually xmlDefaultSAXLocator.
709 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
710 " SAX.setDocumentLocator()");
711 svg_info=(SVGInfo *) context;
715 static void SVGStartDocument(void *context)
724 Called when the document start being processed.
726 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startDocument()");
727 svg_info=(SVGInfo *) context;
728 GetExceptionInfo(svg_info->exception);
729 parser=svg_info->parser;
730 svg_info->document=xmlNewDoc(parser->version);
731 if (svg_info->document == (xmlDocPtr) NULL)
733 if (parser->encoding == NULL)
734 svg_info->document->encoding=(const xmlChar *) NULL;
736 svg_info->document->encoding=xmlStrdup(parser->encoding);
737 svg_info->document->standalone=parser->standalone;
740 static void SVGEndDocument(void *context)
746 Called when the document end has been detected.
748 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.endDocument()");
749 svg_info=(SVGInfo *) context;
750 if (svg_info->offset != (char *) NULL)
751 svg_info->offset=DestroyString(svg_info->offset);
752 if (svg_info->stop_color != (char *) NULL)
753 svg_info->stop_color=DestroyString(svg_info->stop_color);
754 if (svg_info->scale != (double *) NULL)
755 svg_info->scale=(double *) RelinquishMagickMemory(svg_info->scale);
756 if (svg_info->text != (char *) NULL)
757 svg_info->text=DestroyString(svg_info->text);
758 if (svg_info->vertices != (char *) NULL)
759 svg_info->vertices=DestroyString(svg_info->vertices);
760 if (svg_info->url != (char *) NULL)
761 svg_info->url=DestroyString(svg_info->url);
762 #if defined(MAGICKCORE_XML_DELEGATE)
763 if (svg_info->document != (xmlDocPtr) NULL)
765 xmlFreeDoc(svg_info->document);
766 svg_info->document=(xmlDocPtr) NULL;
771 static void SVGStartElement(void *context,const xmlChar *name,
772 const xmlChar **attributes)
777 token[MaxTextExtent],
797 Called when an opening tag has been processed.
799 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startElement(%s",
801 svg_info=(SVGInfo *) context;
803 svg_info->scale=(double *) ResizeQuantumMemory(svg_info->scale,
804 svg_info->n+1UL,sizeof(*svg_info->scale));
805 if (svg_info->scale == (double *) NULL)
807 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
808 ResourceLimitError,"MemoryAllocationFailed","`%s'",name);
811 svg_info->scale[svg_info->n]=svg_info->scale[svg_info->n-1];
812 color=AcquireString("none");
813 units=AcquireString("userSpaceOnUse");
814 value=(const char *) NULL;
815 if (attributes != (const xmlChar **) NULL)
816 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
818 keyword=(const char *) attributes[i];
819 value=(const char *) attributes[i+1];
825 if (LocaleCompare(keyword,"cx") == 0)
827 svg_info->element.cx=
828 GetUserSpaceCoordinateValue(svg_info,1,value);
831 if (LocaleCompare(keyword,"cy") == 0)
833 svg_info->element.cy=
834 GetUserSpaceCoordinateValue(svg_info,-1,value);
842 if (LocaleCompare(keyword,"fx") == 0)
844 svg_info->element.major=
845 GetUserSpaceCoordinateValue(svg_info,1,value);
848 if (LocaleCompare(keyword,"fy") == 0)
850 svg_info->element.minor=
851 GetUserSpaceCoordinateValue(svg_info,-1,value);
859 if (LocaleCompare(keyword,"height") == 0)
861 svg_info->bounds.height=
862 GetUserSpaceCoordinateValue(svg_info,-1,value);
870 if (LocaleCompare(keyword,"id") == 0)
872 (void) CopyMagickString(id,value,MaxTextExtent);
880 if (LocaleCompare(keyword,"r") == 0)
882 svg_info->element.angle=
883 GetUserSpaceCoordinateValue(svg_info,0,value);
891 if (LocaleCompare(keyword,"width") == 0)
893 svg_info->bounds.width=
894 GetUserSpaceCoordinateValue(svg_info,1,value);
902 if (LocaleCompare(keyword,"x") == 0)
904 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value)-
908 if (LocaleCompare(keyword,"x1") == 0)
910 svg_info->segment.x1=GetUserSpaceCoordinateValue(svg_info,1,
914 if (LocaleCompare(keyword,"x2") == 0)
916 svg_info->segment.x2=GetUserSpaceCoordinateValue(svg_info,1,
925 if (LocaleCompare(keyword,"y") == 0)
927 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value)-
931 if (LocaleCompare(keyword,"y1") == 0)
933 svg_info->segment.y1=
934 GetUserSpaceCoordinateValue(svg_info,-1,value);
937 if (LocaleCompare(keyword,"y2") == 0)
939 svg_info->segment.y2=
940 GetUserSpaceCoordinateValue(svg_info,-1,value);
949 if (strchr((char *) name,':') != (char *) NULL)
954 for ( ; *name != ':'; name++) ;
962 if (LocaleCompare((const char *) name,"circle") == 0)
964 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
967 if (LocaleCompare((const char *) name,"clipPath") == 0)
969 (void) FormatLocaleFile(svg_info->file,"push clip-path '%s'\n",id);
977 if (LocaleCompare((const char *) name,"defs") == 0)
979 (void) FormatLocaleFile(svg_info->file,"push defs\n");
987 if (LocaleCompare((const char *) name,"ellipse") == 0)
989 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
997 if (LocaleCompare((const char *) name,"g") == 0)
999 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1007 if (LocaleCompare((const char *) name,"image") == 0)
1009 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1017 if (LocaleCompare((const char *) name,"line") == 0)
1019 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1022 if (LocaleCompare((const char *) name,"linearGradient") == 0)
1024 (void) FormatLocaleFile(svg_info->file,
1025 "push gradient '%s' linear %g,%g %g,%g\n",id,
1026 svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
1027 svg_info->segment.y2);
1035 if (LocaleCompare((const char *) name,"path") == 0)
1037 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1040 if (LocaleCompare((const char *) name,"pattern") == 0)
1042 (void) FormatLocaleFile(svg_info->file,
1043 "push pattern '%s' %g,%g %g,%g\n",id,
1044 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.width,
1045 svg_info->bounds.height);
1048 if (LocaleCompare((const char *) name,"polygon") == 0)
1050 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1053 if (LocaleCompare((const char *) name,"polyline") == 0)
1055 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1063 if (LocaleCompare((const char *) name,"radialGradient") == 0)
1065 (void) FormatLocaleFile(svg_info->file,
1066 "push gradient '%s' radial %g,%g %g,%g %g\n",
1067 id,svg_info->element.cx,svg_info->element.cy,
1068 svg_info->element.major,svg_info->element.minor,
1069 svg_info->element.angle);
1072 if (LocaleCompare((const char *) name,"rect") == 0)
1074 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1082 if (LocaleCompare((const char *) name,"svg") == 0)
1084 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1092 if (LocaleCompare((const char *) name,"text") == 0)
1094 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1097 if (LocaleCompare((const char *) name,"tspan") == 0)
1099 if (*svg_info->text != '\0')
1110 text=EscapeString(svg_info->text,'\'');
1111 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
1112 svg_info->bounds.x-svg_info->center.x,svg_info->bounds.y-
1113 svg_info->center.y,text);
1114 text=DestroyString(text);
1115 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
1116 draw_info->pointsize=svg_info->pointsize;
1117 draw_info->text=AcquireString(svg_info->text);
1118 (void) ConcatenateString(&draw_info->text," ");
1119 (void) GetTypeMetrics(svg_info->image,draw_info,
1120 &metrics,svg_info->exception);
1121 svg_info->bounds.x+=metrics.width;
1122 draw_info=DestroyDrawInfo(draw_info);
1123 *svg_info->text='\0';
1125 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1133 if (attributes != (const xmlChar **) NULL)
1134 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
1136 keyword=(const char *) attributes[i];
1137 value=(const char *) attributes[i+1];
1138 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1139 " %s = %s",keyword,value);
1145 if (LocaleCompare(keyword,"angle") == 0)
1147 (void) FormatLocaleFile(svg_info->file,"angle %g\n",
1148 GetUserSpaceCoordinateValue(svg_info,0,value));
1156 if (LocaleCompare(keyword,"clip-path") == 0)
1158 (void) FormatLocaleFile(svg_info->file,"clip-path '%s'\n",value);
1161 if (LocaleCompare(keyword,"clip-rule") == 0)
1163 (void) FormatLocaleFile(svg_info->file,"clip-rule '%s'\n",value);
1166 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1168 (void) CloneString(&units,value);
1169 (void) FormatLocaleFile(svg_info->file,"clip-units '%s'\n",value);
1172 if (LocaleCompare(keyword,"color") == 0)
1174 (void) CloneString(&color,value);
1177 if (LocaleCompare(keyword,"cx") == 0)
1179 svg_info->element.cx=
1180 GetUserSpaceCoordinateValue(svg_info,1,value);
1183 if (LocaleCompare(keyword,"cy") == 0)
1185 svg_info->element.cy=
1186 GetUserSpaceCoordinateValue(svg_info,-1,value);
1194 if (LocaleCompare(keyword,"d") == 0)
1196 (void) CloneString(&svg_info->vertices,value);
1199 if (LocaleCompare(keyword,"dx") == 0)
1201 svg_info->bounds.x+=GetUserSpaceCoordinateValue(svg_info,1,value);
1204 if (LocaleCompare(keyword,"dy") == 0)
1206 svg_info->bounds.y+=
1207 GetUserSpaceCoordinateValue(svg_info,-1,value);
1215 if (LocaleCompare(keyword,"fill") == 0)
1217 if (LocaleCompare(value,"currentColor") == 0)
1219 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",color);
1222 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",value);
1225 if (LocaleCompare(keyword,"fillcolor") == 0)
1227 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",value);
1230 if (LocaleCompare(keyword,"fill-rule") == 0)
1232 (void) FormatLocaleFile(svg_info->file,"fill-rule '%s'\n",value);
1235 if (LocaleCompare(keyword,"fill-opacity") == 0)
1237 (void) FormatLocaleFile(svg_info->file,"fill-opacity '%s'\n",
1241 if (LocaleCompare(keyword,"font-family") == 0)
1243 (void) FormatLocaleFile(svg_info->file,"font-family '%s'\n",
1247 if (LocaleCompare(keyword,"font-stretch") == 0)
1249 (void) FormatLocaleFile(svg_info->file,"font-stretch '%s'\n",
1253 if (LocaleCompare(keyword,"font-style") == 0)
1255 (void) FormatLocaleFile(svg_info->file,"font-style '%s'\n",value);
1258 if (LocaleCompare(keyword,"font-size") == 0)
1260 svg_info->pointsize=GetUserSpaceCoordinateValue(svg_info,0,value);
1261 (void) FormatLocaleFile(svg_info->file,"font-size %g\n",
1262 svg_info->pointsize);
1265 if (LocaleCompare(keyword,"font-weight") == 0)
1267 (void) FormatLocaleFile(svg_info->file,"font-weight '%s'\n",
1276 if (LocaleCompare(keyword,"gradientTransform") == 0)
1283 GetAffineMatrix(&transform);
1284 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1285 tokens=GetTransformTokens(context,value,&number_tokens);
1286 for (j=0; j < (number_tokens-1); j+=2)
1288 keyword=(char *) tokens[j];
1289 if (keyword == (char *) NULL)
1291 value=(char *) tokens[j+1];
1292 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1293 " %s: %s",keyword,value);
1295 GetAffineMatrix(&affine);
1301 if (LocaleCompare(keyword,"matrix") == 0)
1303 p=(const char *) value;
1304 GetMagickToken(p,&p,token);
1305 affine.sx=InterpretLocaleValue(value,(char **) NULL);
1306 GetMagickToken(p,&p,token);
1308 GetMagickToken(p,&p,token);
1309 affine.rx=InterpretLocaleValue(token,(char **) NULL);
1310 GetMagickToken(p,&p,token);
1312 GetMagickToken(p,&p,token);
1313 affine.ry=InterpretLocaleValue(token,(char **) NULL);
1314 GetMagickToken(p,&p,token);
1316 GetMagickToken(p,&p,token);
1317 affine.sy=InterpretLocaleValue(token,(char **) NULL);
1318 GetMagickToken(p,&p,token);
1320 GetMagickToken(p,&p,token);
1321 affine.tx=InterpretLocaleValue(token,(char **) NULL);
1322 GetMagickToken(p,&p,token);
1324 GetMagickToken(p,&p,token);
1325 affine.ty=InterpretLocaleValue(token,(char **) NULL);
1333 if (LocaleCompare(keyword,"rotate") == 0)
1338 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1339 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1340 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1341 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1342 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1350 if (LocaleCompare(keyword,"scale") == 0)
1352 for (p=(const char *) value; *p != '\0'; p++)
1353 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1356 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1357 affine.sy=affine.sx;
1360 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1361 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
1364 if (LocaleCompare(keyword,"skewX") == 0)
1366 affine.sx=svg_info->affine.sx;
1367 affine.ry=tan(DegreesToRadians(fmod(
1368 GetUserSpaceCoordinateValue(svg_info,1,value),
1370 affine.sy=svg_info->affine.sy;
1373 if (LocaleCompare(keyword,"skewY") == 0)
1375 affine.sx=svg_info->affine.sx;
1376 affine.rx=tan(DegreesToRadians(fmod(
1377 GetUserSpaceCoordinateValue(svg_info,-1,value),
1379 affine.sy=svg_info->affine.sy;
1387 if (LocaleCompare(keyword,"translate") == 0)
1389 for (p=(const char *) value; *p != '\0'; p++)
1390 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1393 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
1394 affine.ty=affine.tx;
1397 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1405 transform.sx=affine.sx*current.sx+affine.ry*current.rx;
1406 transform.rx=affine.rx*current.sx+affine.sy*current.rx;
1407 transform.ry=affine.sx*current.ry+affine.ry*current.sy;
1408 transform.sy=affine.rx*current.ry+affine.sy*current.sy;
1409 transform.tx=affine.sx*current.tx+affine.ry*current.ty+
1411 transform.ty=affine.rx*current.tx+affine.sy*current.ty+
1414 (void) FormatLocaleFile(svg_info->file,
1415 "affine %g %g %g %g %g %g\n",transform.sx,
1416 transform.rx,transform.ry,transform.sy,transform.tx,
1418 for (j=0; tokens[j] != (char *) NULL; j++)
1419 tokens[j]=DestroyString(tokens[j]);
1420 tokens=(char **) RelinquishMagickMemory(tokens);
1423 if (LocaleCompare(keyword,"gradientUnits") == 0)
1425 (void) CloneString(&units,value);
1426 (void) FormatLocaleFile(svg_info->file,"gradient-units '%s'\n",
1435 if (LocaleCompare(keyword,"height") == 0)
1437 svg_info->bounds.height=
1438 GetUserSpaceCoordinateValue(svg_info,-1,value);
1441 if (LocaleCompare(keyword,"href") == 0)
1443 (void) CloneString(&svg_info->url,value);
1451 if (LocaleCompare(keyword,"major") == 0)
1453 svg_info->element.major=
1454 GetUserSpaceCoordinateValue(svg_info,1,value);
1457 if (LocaleCompare(keyword,"minor") == 0)
1459 svg_info->element.minor=
1460 GetUserSpaceCoordinateValue(svg_info,-1,value);
1468 if (LocaleCompare(keyword,"offset") == 0)
1470 (void) CloneString(&svg_info->offset,value);
1473 if (LocaleCompare(keyword,"opacity") == 0)
1475 (void) FormatLocaleFile(svg_info->file,"opacity '%s'\n",value);
1483 if (LocaleCompare(keyword,"path") == 0)
1485 (void) CloneString(&svg_info->url,value);
1488 if (LocaleCompare(keyword,"points") == 0)
1490 (void) CloneString(&svg_info->vertices,value);
1498 if (LocaleCompare(keyword,"r") == 0)
1500 svg_info->element.major=
1501 GetUserSpaceCoordinateValue(svg_info,1,value);
1502 svg_info->element.minor=
1503 GetUserSpaceCoordinateValue(svg_info,-1,value);
1506 if (LocaleCompare(keyword,"rotate") == 0)
1511 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1512 (void) FormatLocaleFile(svg_info->file,"translate %g,%g\n",
1513 svg_info->bounds.x,svg_info->bounds.y);
1514 svg_info->bounds.x=0;
1515 svg_info->bounds.y=0;
1516 (void) FormatLocaleFile(svg_info->file,"rotate %g\n",angle);
1519 if (LocaleCompare(keyword,"rx") == 0)
1521 if (LocaleCompare((const char *) name,"ellipse") == 0)
1522 svg_info->element.major=
1523 GetUserSpaceCoordinateValue(svg_info,1,value);
1526 GetUserSpaceCoordinateValue(svg_info,1,value);
1529 if (LocaleCompare(keyword,"ry") == 0)
1531 if (LocaleCompare((const char *) name,"ellipse") == 0)
1532 svg_info->element.minor=
1533 GetUserSpaceCoordinateValue(svg_info,-1,value);
1536 GetUserSpaceCoordinateValue(svg_info,-1,value);
1544 if (LocaleCompare(keyword,"stop-color") == 0)
1546 (void) CloneString(&svg_info->stop_color,value);
1549 if (LocaleCompare(keyword,"stroke") == 0)
1551 if (LocaleCompare(value,"currentColor") == 0)
1553 (void) FormatLocaleFile(svg_info->file,"stroke '%s'\n",color);
1556 (void) FormatLocaleFile(svg_info->file,"stroke '%s'\n",value);
1559 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1561 (void) FormatLocaleFile(svg_info->file,"stroke-antialias %d\n",
1562 LocaleCompare(value,"true") == 0);
1565 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1567 (void) FormatLocaleFile(svg_info->file,"stroke-dasharray %s\n",
1571 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1573 (void) FormatLocaleFile(svg_info->file,"stroke-dashoffset %s\n",
1577 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1579 (void) FormatLocaleFile(svg_info->file,"stroke-linecap '%s'\n",
1583 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1585 (void) FormatLocaleFile(svg_info->file,"stroke-linejoin '%s'\n",
1589 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1591 (void) FormatLocaleFile(svg_info->file,"stroke-miterlimit '%s'\n",
1595 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1597 (void) FormatLocaleFile(svg_info->file,"stroke-opacity '%s'\n",
1601 if (LocaleCompare(keyword,"stroke-width") == 0)
1603 (void) FormatLocaleFile(svg_info->file,"stroke-width %g\n",
1604 GetUserSpaceCoordinateValue(svg_info,1,value));
1607 if (LocaleCompare(keyword,"style") == 0)
1609 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1610 tokens=GetStyleTokens(context,value,&number_tokens);
1611 for (j=0; j < (number_tokens-1); j+=2)
1613 keyword=(char *) tokens[j];
1614 value=(char *) tokens[j+1];
1615 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1616 " %s: %s",keyword,value);
1622 if (LocaleCompare(keyword,"clip-path") == 0)
1624 (void) FormatLocaleFile(svg_info->file,
1625 "clip-path '%s'\n",value);
1628 if (LocaleCompare(keyword,"clip-rule") == 0)
1630 (void) FormatLocaleFile(svg_info->file,
1631 "clip-rule '%s'\n",value);
1634 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1636 (void) CloneString(&units,value);
1637 (void) FormatLocaleFile(svg_info->file,
1638 "clip-units '%s'\n",value);
1641 if (LocaleCompare(keyword,"color") == 0)
1643 (void) CloneString(&color,value);
1651 if (LocaleCompare(keyword,"fill") == 0)
1653 if (LocaleCompare(value,"currentColor") == 0)
1655 (void) FormatLocaleFile(svg_info->file,
1656 "fill '%s'\n",color);
1659 if (LocaleCompare(value,"#00000000") == 0)
1660 (void) FormatLocaleFile(svg_info->file,
1661 "fill '#000000'\n");
1663 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",
1667 if (LocaleCompare(keyword,"fillcolor") == 0)
1669 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",
1673 if (LocaleCompare(keyword,"fill-rule") == 0)
1675 (void) FormatLocaleFile(svg_info->file,
1676 "fill-rule '%s'\n",value);
1679 if (LocaleCompare(keyword,"fill-opacity") == 0)
1681 (void) FormatLocaleFile(svg_info->file,
1682 "fill-opacity '%s'\n",value);
1685 if (LocaleCompare(keyword,"font-family") == 0)
1687 (void) FormatLocaleFile(svg_info->file,
1688 "font-family '%s'\n",value);
1691 if (LocaleCompare(keyword,"font-stretch") == 0)
1693 (void) FormatLocaleFile(svg_info->file,
1694 "font-stretch '%s'\n",value);
1697 if (LocaleCompare(keyword,"font-style") == 0)
1699 (void) FormatLocaleFile(svg_info->file,
1700 "font-style '%s'\n",value);
1703 if (LocaleCompare(keyword,"font-size") == 0)
1705 svg_info->pointsize=GetUserSpaceCoordinateValue(
1707 (void) FormatLocaleFile(svg_info->file,"font-size %g\n",
1708 svg_info->pointsize);
1711 if (LocaleCompare(keyword,"font-weight") == 0)
1713 (void) FormatLocaleFile(svg_info->file,
1714 "font-weight '%s'\n",value);
1722 if (LocaleCompare(keyword,"offset") == 0)
1724 (void) FormatLocaleFile(svg_info->file,"offset %g\n",
1725 GetUserSpaceCoordinateValue(svg_info,1,value));
1728 if (LocaleCompare(keyword,"opacity") == 0)
1730 (void) FormatLocaleFile(svg_info->file,
1731 "opacity '%s'\n",value);
1739 if (LocaleCompare(keyword,"stop-color") == 0)
1741 (void) CloneString(&svg_info->stop_color,value);
1744 if (LocaleCompare(keyword,"stroke") == 0)
1746 if (LocaleCompare(value,"currentColor") == 0)
1748 (void) FormatLocaleFile(svg_info->file,
1749 "stroke '%s'\n",color);
1752 if (LocaleCompare(value,"#00000000") == 0)
1753 (void) FormatLocaleFile(svg_info->file,
1754 "fill '#000000'\n");
1756 (void) FormatLocaleFile(svg_info->file,
1757 "stroke '%s'\n",value);
1760 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1762 (void) FormatLocaleFile(svg_info->file,
1763 "stroke-antialias %d\n",
1764 LocaleCompare(value,"true") == 0);
1767 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1769 (void) FormatLocaleFile(svg_info->file,
1770 "stroke-dasharray %s\n",value);
1773 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1775 (void) FormatLocaleFile(svg_info->file,
1776 "stroke-dashoffset %s\n",
1780 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1782 (void) FormatLocaleFile(svg_info->file,
1783 "stroke-linecap '%s'\n",value);
1786 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1788 (void) FormatLocaleFile(svg_info->file,
1789 "stroke-linejoin '%s'\n",
1793 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1795 (void) FormatLocaleFile(svg_info->file,
1796 "stroke-miterlimit '%s'\n",
1800 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1802 (void) FormatLocaleFile(svg_info->file,
1803 "stroke-opacity '%s'\n",value);
1806 if (LocaleCompare(keyword,"stroke-width") == 0)
1808 (void) FormatLocaleFile(svg_info->file,
1809 "stroke-width %g\n",
1810 GetUserSpaceCoordinateValue(svg_info,1,value));
1818 if (LocaleCompare(keyword,"text-align") == 0)
1820 (void) FormatLocaleFile(svg_info->file,
1821 "text-align '%s'\n",value);
1824 if (LocaleCompare(keyword,"text-anchor") == 0)
1826 (void) FormatLocaleFile(svg_info->file,
1827 "text-anchor '%s'\n",value);
1830 if (LocaleCompare(keyword,"text-decoration") == 0)
1832 if (LocaleCompare(value,"underline") == 0)
1833 (void) FormatLocaleFile(svg_info->file,
1834 "decorate underline\n");
1835 if (LocaleCompare(value,"line-through") == 0)
1836 (void) FormatLocaleFile(svg_info->file,
1837 "decorate line-through\n");
1838 if (LocaleCompare(value,"overline") == 0)
1839 (void) FormatLocaleFile(svg_info->file,
1840 "decorate overline\n");
1843 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1845 (void) FormatLocaleFile(svg_info->file,
1846 "text-antialias %d\n",
1847 LocaleCompare(value,"true") == 0);
1856 for (j=0; tokens[j] != (char *) NULL; j++)
1857 tokens[j]=DestroyString(tokens[j]);
1858 tokens=(char **) RelinquishMagickMemory(tokens);
1866 if (LocaleCompare(keyword,"text-align") == 0)
1868 (void) FormatLocaleFile(svg_info->file,"text-align '%s'\n",
1872 if (LocaleCompare(keyword,"text-anchor") == 0)
1874 (void) FormatLocaleFile(svg_info->file,"text-anchor '%s'\n",
1878 if (LocaleCompare(keyword,"text-decoration") == 0)
1880 if (LocaleCompare(value,"underline") == 0)
1881 (void) FormatLocaleFile(svg_info->file,"decorate underline\n");
1882 if (LocaleCompare(value,"line-through") == 0)
1883 (void) FormatLocaleFile(svg_info->file,
1884 "decorate line-through\n");
1885 if (LocaleCompare(value,"overline") == 0)
1886 (void) FormatLocaleFile(svg_info->file,"decorate overline\n");
1889 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1891 (void) FormatLocaleFile(svg_info->file,"text-antialias %d\n",
1892 LocaleCompare(value,"true") == 0);
1895 if (LocaleCompare(keyword,"transform") == 0)
1902 GetAffineMatrix(&transform);
1903 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1904 tokens=GetTransformTokens(context,value,&number_tokens);
1905 for (j=0; j < (number_tokens-1); j+=2)
1907 keyword=(char *) tokens[j];
1908 value=(char *) tokens[j+1];
1909 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1910 " %s: %s",keyword,value);
1912 GetAffineMatrix(&affine);
1918 if (LocaleCompare(keyword,"matrix") == 0)
1920 p=(const char *) value;
1921 GetMagickToken(p,&p,token);
1922 affine.sx=InterpretLocaleValue(value,(char **) NULL);
1923 GetMagickToken(p,&p,token);
1925 GetMagickToken(p,&p,token);
1926 affine.rx=InterpretLocaleValue(token,(char **) NULL);
1927 GetMagickToken(p,&p,token);
1929 GetMagickToken(p,&p,token);
1930 affine.ry=InterpretLocaleValue(token,(char **) NULL);
1931 GetMagickToken(p,&p,token);
1933 GetMagickToken(p,&p,token);
1934 affine.sy=InterpretLocaleValue(token,(char **) NULL);
1935 GetMagickToken(p,&p,token);
1937 GetMagickToken(p,&p,token);
1938 affine.tx=InterpretLocaleValue(token,(char **) NULL);
1939 GetMagickToken(p,&p,token);
1941 GetMagickToken(p,&p,token);
1942 affine.ty=InterpretLocaleValue(token,(char **) NULL);
1950 if (LocaleCompare(keyword,"rotate") == 0)
1957 p=(const char *) value;
1958 GetMagickToken(p,&p,token);
1959 angle=InterpretLocaleValue(value,(char **) NULL);
1960 GetMagickToken(p,&p,token);
1962 GetMagickToken(p,&p,token);
1963 x=InterpretLocaleValue(token,(char **) NULL);
1964 GetMagickToken(p,&p,token);
1966 GetMagickToken(p,&p,token);
1967 y=InterpretLocaleValue(token,(char **) NULL);
1968 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1969 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1970 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1971 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1974 svg_info->center.x=x;
1975 svg_info->center.y=y;
1983 if (LocaleCompare(keyword,"scale") == 0)
1985 for (p=(const char *) value; *p != '\0'; p++)
1986 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1989 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1990 affine.sy=affine.sx;
1992 affine.sy=GetUserSpaceCoordinateValue(svg_info,-1,
1994 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
1997 if (LocaleCompare(keyword,"skewX") == 0)
1999 affine.sx=svg_info->affine.sx;
2000 affine.ry=tan(DegreesToRadians(fmod(
2001 GetUserSpaceCoordinateValue(svg_info,1,value),
2003 affine.sy=svg_info->affine.sy;
2006 if (LocaleCompare(keyword,"skewY") == 0)
2008 affine.sx=svg_info->affine.sx;
2009 affine.rx=tan(DegreesToRadians(fmod(
2010 GetUserSpaceCoordinateValue(svg_info,-1,value),
2012 affine.sy=svg_info->affine.sy;
2020 if (LocaleCompare(keyword,"translate") == 0)
2022 for (p=(const char *) value; *p != '\0'; p++)
2023 if ((isspace((int) ((unsigned char) *p)) != 0) ||
2026 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
2027 affine.ty=affine.tx;
2029 affine.ty=GetUserSpaceCoordinateValue(svg_info,-1,
2038 transform.sx=affine.sx*current.sx+affine.ry*current.rx;
2039 transform.rx=affine.rx*current.sx+affine.sy*current.rx;
2040 transform.ry=affine.sx*current.ry+affine.ry*current.sy;
2041 transform.sy=affine.rx*current.ry+affine.sy*current.sy;
2042 transform.tx=affine.sx*current.tx+affine.ry*current.ty+
2044 transform.ty=affine.rx*current.tx+affine.sy*current.ty+
2047 (void) FormatLocaleFile(svg_info->file,
2048 "affine %g %g %g %g 0.0 0.0\n",transform.sx,transform.rx,
2049 transform.ry,transform.sy);
2050 for (j=0; tokens[j] != (char *) NULL; j++)
2051 tokens[j]=DestroyString(tokens[j]);
2052 tokens=(char **) RelinquishMagickMemory(tokens);
2060 if (LocaleCompare(keyword,"verts") == 0)
2062 (void) CloneString(&svg_info->vertices,value);
2065 if (LocaleCompare(keyword,"viewBox") == 0)
2067 p=(const char *) value;
2068 GetMagickToken(p,&p,token);
2069 svg_info->view_box.x=InterpretLocaleValue(token,(char **) NULL);
2070 GetMagickToken(p,&p,token);
2072 GetMagickToken(p,&p,token);
2073 svg_info->view_box.y=InterpretLocaleValue(token,(char **) NULL);
2074 GetMagickToken(p,&p,token);
2076 GetMagickToken(p,&p,token);
2077 svg_info->view_box.width=InterpretLocaleValue(token,
2079 if (svg_info->bounds.width == 0)
2080 svg_info->bounds.width=svg_info->view_box.width;
2081 GetMagickToken(p,&p,token);
2083 GetMagickToken(p,&p,token);
2084 svg_info->view_box.height=InterpretLocaleValue(token,
2086 if (svg_info->bounds.height == 0)
2087 svg_info->bounds.height=svg_info->view_box.height;
2095 if (LocaleCompare(keyword,"width") == 0)
2097 svg_info->bounds.width=
2098 GetUserSpaceCoordinateValue(svg_info,1,value);
2106 if (LocaleCompare(keyword,"x") == 0)
2108 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value);
2111 if (LocaleCompare(keyword,"xlink:href") == 0)
2113 (void) CloneString(&svg_info->url,value);
2116 if (LocaleCompare(keyword,"x1") == 0)
2118 svg_info->segment.x1=
2119 GetUserSpaceCoordinateValue(svg_info,1,value);
2122 if (LocaleCompare(keyword,"x2") == 0)
2124 svg_info->segment.x2=
2125 GetUserSpaceCoordinateValue(svg_info,1,value);
2133 if (LocaleCompare(keyword,"y") == 0)
2135 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value);
2138 if (LocaleCompare(keyword,"y1") == 0)
2140 svg_info->segment.y1=
2141 GetUserSpaceCoordinateValue(svg_info,-1,value);
2144 if (LocaleCompare(keyword,"y2") == 0)
2146 svg_info->segment.y2=
2147 GetUserSpaceCoordinateValue(svg_info,-1,value);
2156 if (LocaleCompare((const char *) name,"svg") == 0)
2158 if (svg_info->document->encoding != (const xmlChar *) NULL)
2159 (void) FormatLocaleFile(svg_info->file,"encoding \"%s\"\n",
2160 (const char *) svg_info->document->encoding);
2161 if (attributes != (const xmlChar **) NULL)
2167 if ((svg_info->view_box.width == 0.0) ||
2168 (svg_info->view_box.height == 0.0))
2169 svg_info->view_box=svg_info->bounds;
2170 svg_info->width=(size_t) floor(svg_info->bounds.width+0.5);
2171 svg_info->height=(size_t) floor(svg_info->bounds.height+0.5);
2172 (void) FormatLocaleFile(svg_info->file,"viewbox 0 0 %.20g %.20g\n",
2173 (double) svg_info->width,(double) svg_info->height);
2174 sx=(double) svg_info->width/svg_info->view_box.width;
2175 sy=(double) svg_info->height/svg_info->view_box.height;
2176 (void) FormatLocaleFile(svg_info->file,"affine %g 0 0 %g 0.0 0.0\n",
2180 (void) LogMagickEvent(CoderEvent,GetMagickModule()," )");
2181 units=DestroyString(units);
2182 if (color != (char *) NULL)
2183 color=DestroyString(color);
2186 static void SVGEndElement(void *context,const xmlChar *name)
2192 Called when the end of an element has been detected.
2194 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2195 " SAX.endElement(%s)",name);
2196 svg_info=(SVGInfo *) context;
2197 if (strchr((char *) name,':') != (char *) NULL)
2200 Skip over namespace.
2202 for ( ; *name != ':'; name++) ;
2210 if (LocaleCompare((const char *) name,"circle") == 0)
2212 (void) FormatLocaleFile(svg_info->file,"circle %g,%g %g,%g\n",
2213 svg_info->element.cx,svg_info->element.cy,svg_info->element.cx,
2214 svg_info->element.cy+svg_info->element.minor);
2215 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2218 if (LocaleCompare((const char *) name,"clipPath") == 0)
2220 (void) FormatLocaleFile(svg_info->file,"pop clip-path\n");
2228 if (LocaleCompare((const char *) name,"defs") == 0)
2230 (void) FormatLocaleFile(svg_info->file,"pop defs\n");
2233 if (LocaleCompare((const char *) name,"desc") == 0)
2238 if (*svg_info->text == '\0')
2240 (void) fputc('#',svg_info->file);
2241 for (p=svg_info->text; *p != '\0'; p++)
2243 (void) fputc(*p,svg_info->file);
2245 (void) fputc('#',svg_info->file);
2247 (void) fputc('\n',svg_info->file);
2248 *svg_info->text='\0';
2256 if (LocaleCompare((const char *) name,"ellipse") == 0)
2261 angle=svg_info->element.angle;
2262 (void) FormatLocaleFile(svg_info->file,"ellipse %g,%g %g,%g 0,360\n",
2263 svg_info->element.cx,svg_info->element.cy,
2264 angle == 0.0 ? svg_info->element.major : svg_info->element.minor,
2265 angle == 0.0 ? svg_info->element.minor : svg_info->element.major);
2266 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2274 if (LocaleCompare((const char *) name,"g") == 0)
2276 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2284 if (LocaleCompare((const char *) name,"image") == 0)
2286 (void) FormatLocaleFile(svg_info->file,
2287 "image Over %g,%g %g,%g '%s'\n",svg_info->bounds.x,
2288 svg_info->bounds.y,svg_info->bounds.width,svg_info->bounds.height,
2290 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2298 if (LocaleCompare((const char *) name,"line") == 0)
2300 (void) FormatLocaleFile(svg_info->file,"line %g,%g %g,%g\n",
2301 svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
2302 svg_info->segment.y2);
2303 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2306 if (LocaleCompare((const char *) name,"linearGradient") == 0)
2308 (void) FormatLocaleFile(svg_info->file,"pop gradient\n");
2316 if (LocaleCompare((const char *) name,"pattern") == 0)
2318 (void) FormatLocaleFile(svg_info->file,"pop pattern\n");
2321 if (LocaleCompare((const char *) name,"path") == 0)
2323 (void) FormatLocaleFile(svg_info->file,"path '%s'\n",
2324 svg_info->vertices);
2325 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2328 if (LocaleCompare((const char *) name,"polygon") == 0)
2330 (void) FormatLocaleFile(svg_info->file,"polygon %s\n",
2331 svg_info->vertices);
2332 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2335 if (LocaleCompare((const char *) name,"polyline") == 0)
2337 (void) FormatLocaleFile(svg_info->file,"polyline %s\n",
2338 svg_info->vertices);
2339 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2347 if (LocaleCompare((const char *) name,"radialGradient") == 0)
2349 (void) FormatLocaleFile(svg_info->file,"pop gradient\n");
2352 if (LocaleCompare((const char *) name,"rect") == 0)
2354 if ((svg_info->radius.x == 0.0) && (svg_info->radius.y == 0.0))
2356 (void) FormatLocaleFile(svg_info->file,"rectangle %g,%g %g,%g\n",
2357 svg_info->bounds.x,svg_info->bounds.y,
2358 svg_info->bounds.x+svg_info->bounds.width,
2359 svg_info->bounds.y+svg_info->bounds.height);
2360 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2363 if (svg_info->radius.x == 0.0)
2364 svg_info->radius.x=svg_info->radius.y;
2365 if (svg_info->radius.y == 0.0)
2366 svg_info->radius.y=svg_info->radius.x;
2367 (void) FormatLocaleFile(svg_info->file,
2368 "roundRectangle %g,%g %g,%g %g,%g\n",
2369 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.x+
2370 svg_info->bounds.width,svg_info->bounds.y+svg_info->bounds.height,
2371 svg_info->radius.x,svg_info->radius.y);
2372 svg_info->radius.x=0.0;
2373 svg_info->radius.y=0.0;
2374 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2382 if (LocaleCompare((const char *) name,"stop") == 0)
2384 (void) FormatLocaleFile(svg_info->file,"stop-color '%s' %s\n",
2385 svg_info->stop_color,svg_info->offset);
2388 if (LocaleCompare((const char *) name,"svg") == 0)
2390 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2398 if (LocaleCompare((const char *) name,"text") == 0)
2400 if (*svg_info->text != '\0')
2405 text=EscapeString(svg_info->text,'\'');
2406 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
2407 svg_info->bounds.x,svg_info->bounds.y,text);
2408 text=DestroyString(text);
2409 *svg_info->text='\0';
2411 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2414 if (LocaleCompare((const char *) name,"tspan") == 0)
2416 if (*svg_info->text != '\0')
2427 text=EscapeString(svg_info->text,'\'');
2428 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
2429 svg_info->bounds.x,svg_info->bounds.y,text);
2430 text=DestroyString(text);
2431 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
2432 draw_info->pointsize=svg_info->pointsize;
2433 draw_info->text=AcquireString(svg_info->text);
2434 (void) ConcatenateString(&draw_info->text," ");
2435 (void) GetTypeMetrics(svg_info->image,draw_info,&metrics,
2436 svg_info->exception);
2437 svg_info->bounds.x+=metrics.width;
2438 draw_info=DestroyDrawInfo(draw_info);
2439 *svg_info->text='\0';
2441 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2444 if (LocaleCompare((const char *) name,"title") == 0)
2446 if (*svg_info->text == '\0')
2448 (void) CloneString(&svg_info->title,svg_info->text);
2449 *svg_info->text='\0';
2457 *svg_info->text='\0';
2458 (void) ResetMagickMemory(&svg_info->element,0,sizeof(svg_info->element));
2459 (void) ResetMagickMemory(&svg_info->segment,0,sizeof(svg_info->segment));
2463 static void SVGCharacters(void *context,const xmlChar *c,int length)
2475 Receiving some characters from the parser.
2477 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2478 " SAX.characters(%s,%.20g)",c,(double) length);
2479 svg_info=(SVGInfo *) context;
2480 if (svg_info->text != (char *) NULL)
2481 svg_info->text=(char *) ResizeQuantumMemory(svg_info->text,
2482 strlen(svg_info->text)+length+MaxTextExtent,sizeof(*svg_info->text));
2485 svg_info->text=(char *) AcquireQuantumMemory(length+MaxTextExtent,
2486 sizeof(*svg_info->text));
2487 if (svg_info->text != (char *) NULL)
2488 *svg_info->text='\0';
2490 if (svg_info->text == (char *) NULL)
2492 p=svg_info->text+strlen(svg_info->text);
2493 for (i=0; i < (ssize_t) length; i++)
2498 static void SVGReference(void *context,const xmlChar *name)
2507 Called when an entity reference is detected.
2509 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.reference(%s)",
2511 svg_info=(SVGInfo *) context;
2512 parser=svg_info->parser;
2513 if (parser == (xmlParserCtxtPtr) NULL)
2515 if (parser->node == (xmlNodePtr) NULL)
2518 (void) xmlAddChild(parser->node,xmlNewCharRef(svg_info->document,name));
2520 (void) xmlAddChild(parser->node,xmlNewReference(svg_info->document,name));
2523 static void SVGIgnorableWhitespace(void *context,const xmlChar *c,int length)
2529 Receiving some ignorable whitespaces from the parser.
2531 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2532 " SAX.ignorableWhitespace(%.30s, %d)",c,length);
2533 svg_info=(SVGInfo *) context;
2537 static void SVGProcessingInstructions(void *context,const xmlChar *target,
2538 const xmlChar *data)
2544 A processing instruction has been parsed.
2546 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2547 " SAX.processingInstruction(%s, %s)",target,data);
2548 svg_info=(SVGInfo *) context;
2552 static void SVGComment(void *context,const xmlChar *value)
2558 A comment has been parsed.
2560 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.comment(%s)",
2562 svg_info=(SVGInfo *) context;
2563 if (svg_info->comment != (char *) NULL)
2564 (void) ConcatenateString(&svg_info->comment,"\n");
2565 (void) ConcatenateString(&svg_info->comment,(const char *) value);
2568 static void SVGWarning(void *context,const char *format,...)
2572 reason[MaxTextExtent];
2581 Display and format a warning messages, gives file, line, position and
2584 va_start(operands,format);
2585 svg_info=(SVGInfo *) context;
2586 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.warning: ");
2587 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2588 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2589 (void) vsprintf(reason,format,operands);
2591 (void) vsnprintf(reason,MaxTextExtent,format,operands);
2593 message=GetExceptionMessage(errno);
2594 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
2595 DelegateWarning,reason,"`%s`",message);
2596 message=DestroyString(message);
2600 static void SVGError(void *context,const char *format,...)
2604 reason[MaxTextExtent];
2613 Display and format a error formats, gives file, line, position and
2616 va_start(operands,format);
2617 svg_info=(SVGInfo *) context;
2618 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.error: ");
2619 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2620 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2621 (void) vsprintf(reason,format,operands);
2623 (void) vsnprintf(reason,MaxTextExtent,format,operands);
2625 message=GetExceptionMessage(errno);
2626 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),CoderError,
2627 reason,"`%s`",message);
2628 message=DestroyString(message);
2632 static void SVGCDataBlock(void *context,const xmlChar *value,int length)
2644 Called when a pcdata block has been parsed.
2646 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.pcdata(%s, %d)",
2648 svg_info=(SVGInfo *) context;
2649 parser=svg_info->parser;
2650 child=xmlGetLastChild(parser->node);
2651 if ((child != (xmlNodePtr) NULL) && (child->type == XML_CDATA_SECTION_NODE))
2653 xmlTextConcat(child,value,length);
2656 (void) xmlAddChild(parser->node,xmlNewCDataBlock(parser->myDoc,value,length));
2659 static void SVGExternalSubset(void *context,const xmlChar *name,
2660 const xmlChar *external_id,const xmlChar *system_id)
2675 Does this document has an external subset?
2677 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2678 " SAX.externalSubset(%s, %s, %s)",name,
2679 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
2680 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
2681 svg_info=(SVGInfo *) context;
2682 parser=svg_info->parser;
2683 if (((external_id == NULL) && (system_id == NULL)) ||
2684 ((parser->validate == 0) || (parser->wellFormed == 0) ||
2685 (svg_info->document == 0)))
2687 input=SVGResolveEntity(context,external_id,system_id);
2690 (void) xmlNewDtd(svg_info->document,name,external_id,system_id);
2691 parser_context=(*parser);
2692 parser->inputTab=(xmlParserInputPtr *) xmlMalloc(5*sizeof(*parser->inputTab));
2693 if (parser->inputTab == (xmlParserInputPtr *) NULL)
2695 parser->errNo=XML_ERR_NO_MEMORY;
2696 parser->input=parser_context.input;
2697 parser->inputNr=parser_context.inputNr;
2698 parser->inputMax=parser_context.inputMax;
2699 parser->inputTab=parser_context.inputTab;
2705 xmlPushInput(parser,input);
2706 (void) xmlSwitchEncoding(parser,xmlDetectCharEncoding(parser->input->cur,4));
2707 if (input->filename == (char *) NULL)
2708 input->filename=(char *) xmlStrdup(system_id);
2711 input->base=parser->input->cur;
2712 input->cur=parser->input->cur;
2714 xmlParseExternalSubset(parser,external_id,system_id);
2715 while (parser->inputNr > 1)
2716 (void) xmlPopInput(parser);
2717 xmlFreeInputStream(parser->input);
2718 xmlFree(parser->inputTab);
2719 parser->input=parser_context.input;
2720 parser->inputNr=parser_context.inputNr;
2721 parser->inputMax=parser_context.inputMax;
2722 parser->inputTab=parser_context.inputTab;
2725 #if defined(MAGICKCORE_RSVG_DELEGATE)
2726 static void SVGSetImageSize(int *width,int *height,gpointer context)
2731 image=(Image *) context;
2732 *width=(int) (*width*image->x_resolution/72.0);
2733 *height=(int) (*height*image->y_resolution/72.0);
2737 #if defined(__cplusplus) || defined(c_plusplus)
2741 static Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
2744 filename[MaxTextExtent];
2763 message[MaxTextExtent];
2774 assert(image_info != (const ImageInfo *) NULL);
2775 assert(image_info->signature == MagickSignature);
2776 assert(exception != (ExceptionInfo *) NULL);
2777 if (image_info->debug != MagickFalse)
2778 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2779 image_info->filename);
2780 assert(exception->signature == MagickSignature);
2781 image=AcquireImage(image_info);
2782 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2783 if (status == MagickFalse)
2785 image=DestroyImageList(image);
2786 return((Image *) NULL);
2788 if (LocaleCompare(image_info->magick,"MSVG") != 0)
2790 #if defined(MAGICKCORE_RSVG_DELEGATE)
2791 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2798 register unsigned char
2811 register const guchar
2834 svg_handle=rsvg_handle_new();
2835 if (svg_handle == (RsvgHandle *) NULL)
2836 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2837 rsvg_handle_set_base_uri(svg_handle,image_info->filename);
2838 rsvg_handle_set_size_callback(svg_handle,SVGSetImageSize,image,NULL);
2839 if ((image->x_resolution != 72.0) && (image->y_resolution != 72.0))
2840 rsvg_handle_set_dpi_x_y(svg_handle,image->x_resolution,
2841 image->y_resolution);
2842 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
2844 error=(GError *) NULL;
2845 (void) rsvg_handle_write(svg_handle,message,n,&error);
2846 if (error != (GError *) NULL)
2847 g_error_free(error);
2849 error=(GError *) NULL;
2850 rsvg_handle_close(svg_handle,&error);
2851 if (error != (GError *) NULL)
2852 g_error_free(error);
2853 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2854 rsvg_handle_get_dimensions(svg_handle,&dimension_info);
2855 image->columns=dimension_info.width;
2856 image->rows=dimension_info.height;
2857 pixels=(unsigned char *) NULL;
2859 pixel_info=rsvg_handle_get_pixbuf(svg_handle);
2860 rsvg_handle_free(svg_handle);
2861 image->columns=gdk_pixbuf_get_width(pixel_info);
2862 image->rows=gdk_pixbuf_get_height(pixel_info);
2864 image->matte=MagickTrue;
2865 SetImageProperty(image,"svg:base-uri",
2866 rsvg_handle_get_base_uri(svg_handle));
2867 SetImageProperty(image,"svg:title",rsvg_handle_get_title(svg_handle));
2868 SetImageProperty(image,"svg:description",
2869 rsvg_handle_get_desc(svg_handle));
2870 if ((image->columns == 0) || (image->rows == 0))
2872 #if !defined(MAGICKCORE_CAIRO_DELEGATE)
2873 g_object_unref(G_OBJECT(pixel_info));
2875 g_object_unref(svg_handle);
2876 ThrowReaderException(MissingDelegateError,
2877 "NoDecodeDelegateForThisImageFormat");
2879 if (image_info->ping == MagickFalse)
2881 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2882 pixels=(unsigned char *) AcquireQuantumMemory(image->columns,4*
2883 image->rows*sizeof(*pixels));
2884 if (pixels == (unsigned char *) NULL)
2886 g_object_unref(svg_handle);
2887 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2890 (void) SetImageBackgroundColor(image);
2891 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2892 cairo_surface=cairo_image_surface_create_for_data(pixels,
2893 CAIRO_FORMAT_ARGB32,image->columns,image->rows,4*image->columns);
2894 if (cairo_surface == (cairo_surface_t *) NULL)
2896 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2897 g_object_unref(svg_handle);
2898 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2900 cairo_info=cairo_create(cairo_surface);
2901 cairo_set_operator(cairo_info,CAIRO_OPERATOR_CLEAR);
2902 cairo_paint(cairo_info);
2903 cairo_set_operator(cairo_info,CAIRO_OPERATOR_OVER);
2904 rsvg_handle_render_cairo(svg_handle,cairo_info);
2905 cairo_destroy(cairo_info);
2906 cairo_surface_destroy(cairo_surface);
2907 g_object_unref(svg_handle);
2910 p=gdk_pixbuf_get_pixels(pixel_info);
2912 for (y=0; y < (ssize_t) image->rows; y++)
2914 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
2915 if (q == (Quantum *) NULL)
2917 for (x=0; x < (ssize_t) image->columns; x++)
2919 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2920 fill_color.blue=ScaleCharToQuantum(*p++);
2921 fill_color.green=ScaleCharToQuantum(*p++);
2922 fill_color.red=ScaleCharToQuantum(*p++);
2924 fill_color.red=ScaleCharToQuantum(*p++);
2925 fill_color.green=ScaleCharToQuantum(*p++);
2926 fill_color.blue=ScaleCharToQuantum(*p++);
2928 fill_color.alpha=ScaleCharToQuantum(*p++);
2929 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2934 gamma=1.0-QuantumScale*fill_color.alpha;
2935 gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
2936 fill_color.blue*=gamma;
2937 fill_color.green*=gamma;
2938 fill_color.red*=gamma;
2941 CompositePixelOver(image,&fill_color,fill_color.alpha,q,
2942 (MagickRealType) GetPixelAlpha(image,q),q);
2943 q+=GetPixelChannels(image);
2945 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2947 if (image->previous == (Image *) NULL)
2949 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
2951 if (status == MagickFalse)
2956 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2957 if (pixels != (unsigned char *) NULL)
2958 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2960 g_object_unref(G_OBJECT(pixel_info));
2962 (void) CloseBlob(image);
2963 return(GetFirstImageInList(image));
2970 unique_file=AcquireUniqueFileResource(filename);
2971 if (unique_file != -1)
2972 file=fdopen(unique_file,"w");
2973 if ((unique_file == -1) || (file == (FILE *) NULL))
2975 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
2976 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
2978 image=DestroyImageList(image);
2979 return((Image *) NULL);
2984 svg_info=AcquireSVGInfo();
2985 if (svg_info == (SVGInfo *) NULL)
2986 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2987 svg_info->file=file;
2988 svg_info->exception=exception;
2989 svg_info->image=image;
2990 svg_info->image_info=image_info;
2991 svg_info->bounds.width=image->columns;
2992 svg_info->bounds.height=image->rows;
2993 if (image_info->size != (char *) NULL)
2994 (void) CloneString(&svg_info->size,image_info->size);
2995 if (image->debug != MagickFalse)
2996 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"begin SAX");
2998 (void) xmlSubstituteEntitiesDefault(1);
2999 (void) ResetMagickMemory(&sax_modules,0,sizeof(sax_modules));
3000 sax_modules.internalSubset=SVGInternalSubset;
3001 sax_modules.isStandalone=SVGIsStandalone;
3002 sax_modules.hasInternalSubset=SVGHasInternalSubset;
3003 sax_modules.hasExternalSubset=SVGHasExternalSubset;
3004 sax_modules.resolveEntity=SVGResolveEntity;
3005 sax_modules.getEntity=SVGGetEntity;
3006 sax_modules.entityDecl=SVGEntityDeclaration;
3007 sax_modules.notationDecl=SVGNotationDeclaration;
3008 sax_modules.attributeDecl=SVGAttributeDeclaration;
3009 sax_modules.elementDecl=SVGElementDeclaration;
3010 sax_modules.unparsedEntityDecl=SVGUnparsedEntityDeclaration;
3011 sax_modules.setDocumentLocator=SVGSetDocumentLocator;
3012 sax_modules.startDocument=SVGStartDocument;
3013 sax_modules.endDocument=SVGEndDocument;
3014 sax_modules.startElement=SVGStartElement;
3015 sax_modules.endElement=SVGEndElement;
3016 sax_modules.reference=SVGReference;
3017 sax_modules.characters=SVGCharacters;
3018 sax_modules.ignorableWhitespace=SVGIgnorableWhitespace;
3019 sax_modules.processingInstruction=SVGProcessingInstructions;
3020 sax_modules.comment=SVGComment;
3021 sax_modules.warning=SVGWarning;
3022 sax_modules.error=SVGError;
3023 sax_modules.fatalError=SVGError;
3024 sax_modules.getParameterEntity=SVGGetParameterEntity;
3025 sax_modules.cdataBlock=SVGCDataBlock;
3026 sax_modules.externalSubset=SVGExternalSubset;
3027 sax_handler=(&sax_modules);
3028 n=ReadBlob(image,MaxTextExtent,message);
3031 svg_info->parser=xmlCreatePushParserCtxt(sax_handler,svg_info,(char *)
3032 message,n,image->filename);
3033 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
3035 status=xmlParseChunk(svg_info->parser,(char *) message,(int) n,0);
3040 (void) xmlParseChunk(svg_info->parser,(char *) message,0,1);
3041 xmlFreeParserCtxt(svg_info->parser);
3042 if (image->debug != MagickFalse)
3043 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"end SAX");
3045 (void) fclose(file);
3046 (void) CloseBlob(image);
3047 image->columns=svg_info->width;
3048 image->rows=svg_info->height;
3049 if (exception->severity >= ErrorException)
3051 image=DestroyImage(image);
3052 return((Image *) NULL);
3054 if (image_info->ping == MagickFalse)
3062 image=DestroyImage(image);
3063 image=(Image *) NULL;
3064 read_info=CloneImageInfo(image_info);
3065 SetImageInfoBlob(read_info,(void *) NULL,0);
3066 if (read_info->density != (char *) NULL)
3067 read_info->density=DestroyString(read_info->density);
3068 (void) FormatLocaleString(read_info->filename,MaxTextExtent,"mvg:%s",
3070 image=ReadImage(read_info,exception);
3071 read_info=DestroyImageInfo(read_info);
3072 if (image != (Image *) NULL)
3073 (void) CopyMagickString(image->filename,image_info->filename,
3077 Relinquish resources.
3079 if (image != (Image *) NULL)
3081 if (svg_info->title != (char *) NULL)
3082 (void) SetImageProperty(image,"svg:title",svg_info->title);
3083 if (svg_info->comment != (char *) NULL)
3084 (void) SetImageProperty(image,"svg:comment",svg_info->comment);
3086 svg_info=DestroySVGInfo(svg_info);
3087 (void) RelinquishUniqueFileResource(filename);
3088 return(GetFirstImageInList(image));
3093 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3097 % R e g i s t e r S V G I m a g e %
3101 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3103 % RegisterSVGImage() adds attributes for the SVG image format to
3104 % the list of supported formats. The attributes include the image format
3105 % tag, a method to read and/or write the format, whether the format
3106 % supports the saving of more than one frame to the same file or blob,
3107 % whether the format supports native in-memory I/O, and a brief
3108 % description of the format.
3110 % The format of the RegisterSVGImage method is:
3112 % size_t RegisterSVGImage(void)
3115 ModuleExport size_t RegisterSVGImage(void)
3118 version[MaxTextExtent];
3124 #if defined(LIBXML_DOTTED_VERSION)
3125 (void) CopyMagickString(version,"XML " LIBXML_DOTTED_VERSION,MaxTextExtent);
3127 #if defined(MAGICKCORE_RSVG_DELEGATE)
3129 (void) FormatLocaleString(version,MaxTextExtent,"RSVG %d.%d.%d",
3130 LIBRSVG_MAJOR_VERSION,LIBRSVG_MINOR_VERSION,LIBRSVG_MICRO_VERSION);
3132 entry=SetMagickInfo("SVG");
3133 #if defined(MAGICKCORE_XML_DELEGATE)
3134 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3136 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3137 entry->blob_support=MagickFalse;
3138 entry->seekable_stream=MagickFalse;
3139 entry->description=ConstantString("Scalable Vector Graphics");
3140 if (*version != '\0')
3141 entry->version=ConstantString(version);
3142 entry->magick=(IsImageFormatHandler *) IsSVG;
3143 entry->module=ConstantString("SVG");
3144 (void) RegisterMagickInfo(entry);
3145 entry=SetMagickInfo("SVGZ");
3146 #if defined(MAGICKCORE_XML_DELEGATE)
3147 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3149 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3150 entry->blob_support=MagickFalse;
3151 entry->seekable_stream=MagickFalse;
3152 entry->description=ConstantString("Compressed Scalable Vector Graphics");
3153 if (*version != '\0')
3154 entry->version=ConstantString(version);
3155 entry->magick=(IsImageFormatHandler *) IsSVG;
3156 entry->module=ConstantString("SVG");
3157 (void) RegisterMagickInfo(entry);
3158 entry=SetMagickInfo("MSVG");
3159 #if defined(MAGICKCORE_XML_DELEGATE)
3160 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3162 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3163 entry->blob_support=MagickFalse;
3164 entry->seekable_stream=MagickFalse;
3165 entry->description=ConstantString("ImageMagick's own SVG internal renderer");
3166 entry->magick=(IsImageFormatHandler *) IsSVG;
3167 entry->module=ConstantString("SVG");
3168 (void) RegisterMagickInfo(entry);
3169 return(MagickImageCoderSignature);
3173 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3177 % U n r e g i s t e r S V G I m a g e %
3181 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3183 % UnregisterSVGImage() removes format registrations made by the
3184 % SVG module from the list of supported formats.
3186 % The format of the UnregisterSVGImage method is:
3188 % UnregisterSVGImage(void)
3191 ModuleExport void UnregisterSVGImage(void)
3193 (void) UnregisterMagickInfo("SVGZ");
3194 (void) UnregisterMagickInfo("SVG");
3195 (void) UnregisterMagickInfo("MSVG");
3196 #if defined(MAGICKCORE_RSVG_DELEGATE)
3202 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3206 % W r i t e S V G I m a g e %
3210 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3212 % WriteSVGImage() writes a image in the SVG - XML based W3C standard
3215 % The format of the WriteSVGImage method is:
3217 % MagickBooleanType WriteSVGImage(const ImageInfo *image_info,
3218 % Image *image,ExceptionInfo *exception)
3220 % A description of each parameter follows.
3222 % o image_info: the image info.
3224 % o image: The image.
3226 % o exception: return any errors or warnings in this structure.
3230 static void AffineToTransform(Image *image,AffineMatrix *affine)
3233 transform[MaxTextExtent];
3235 if ((fabs(affine->tx) < MagickEpsilon) && (fabs(affine->ty) < MagickEpsilon))
3237 if ((fabs(affine->rx) < MagickEpsilon) &&
3238 (fabs(affine->ry) < MagickEpsilon))
3240 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3241 (fabs(affine->sy-1.0) < MagickEpsilon))
3243 (void) WriteBlobString(image,"\">\n");
3246 (void) FormatLocaleString(transform,MaxTextExtent,
3247 "\" transform=\"scale(%g,%g)\">\n",affine->sx,affine->sy);
3248 (void) WriteBlobString(image,transform);
3253 if ((fabs(affine->sx-affine->sy) < MagickEpsilon) &&
3254 (fabs(affine->rx+affine->ry) < MagickEpsilon) &&
3255 (fabs(affine->sx*affine->sx+affine->rx*affine->rx-1.0) <
3261 theta=(180.0/MagickPI)*atan2(affine->rx,affine->sx);
3262 (void) FormatLocaleString(transform,MaxTextExtent,
3263 "\" transform=\"rotate(%g)\">\n",theta);
3264 (void) WriteBlobString(image,transform);
3271 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3272 (fabs(affine->rx) < MagickEpsilon) &&
3273 (fabs(affine->ry) < MagickEpsilon) &&
3274 (fabs(affine->sy-1.0) < MagickEpsilon))
3276 (void) FormatLocaleString(transform,MaxTextExtent,
3277 "\" transform=\"translate(%g,%g)\">\n",affine->tx,affine->ty);
3278 (void) WriteBlobString(image,transform);
3282 (void) FormatLocaleString(transform,MaxTextExtent,
3283 "\" transform=\"matrix(%g %g %g %g %g %g)\">\n",
3284 affine->sx,affine->rx,affine->ry,affine->sy,affine->tx,affine->ty);
3285 (void) WriteBlobString(image,transform);
3288 static MagickBooleanType IsPoint(const char *point)
3296 value=strtol(point,&p,10);
3298 return(p != point ? MagickTrue : MagickFalse);
3301 static MagickBooleanType TraceSVGImage(Image *image)
3306 register const Quantum
3312 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
3317 at_fitting_opts_type
3336 Trace image and write as SVG.
3338 fitting_options=at_fitting_opts_new();
3339 output_options=at_output_opts_new();
3340 type=GetImageType(image,&image->exception);
3342 if ((type == BilevelType) || (type == GrayscaleType))
3344 trace=at_bitmap_new(image->columns,image->rows,number_planes);
3346 for (y=0; y < (ssize_t) image->rows; y++)
3348 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
3349 if (p == (const Quantum *) NULL)
3351 for (x=0; x < (ssize_t) image->columns; x++)
3353 trace->bitmap[i++]=GetPixelRed(image,p);
3354 if (number_planes == 3)
3356 trace->bitmap[i++]=GetPixelGreen(image,p);
3357 trace->bitmap[i++]=GetPixelBlue(image,p);
3359 p+=GetPixelChannels(image);
3362 splines=at_splines_new_full(trace,fitting_options,NULL,NULL,NULL,NULL,NULL,
3364 at_splines_write(at_output_get_handler_by_suffix((char *) "svg"),
3365 GetBlobFileHandle(image),image->filename,output_options,splines,NULL,
3370 at_splines_free(splines);
3371 at_bitmap_free(trace);
3372 at_output_opts_free(output_options);
3373 at_fitting_opts_free(fitting_options);
3378 message[MaxTextExtent],
3379 tuple[MaxTextExtent];
3384 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3385 (void) WriteBlobString(image,
3386 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3387 (void) WriteBlobString(image,
3388 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3389 (void) FormatLocaleString(message,MaxTextExtent,
3390 "<svg width=\"%.20g\" height=\"%.20g\">\n",(double) image->columns,
3391 (double) image->rows);
3392 (void) WriteBlobString(image,message);
3393 GetPixelInfo(image,&pixel);
3394 for (y=0; y < (ssize_t) image->rows; y++)
3396 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
3397 if (p == (const Quantum *) NULL)
3399 for (x=0; x < (ssize_t) image->columns; x++)
3401 SetPixelInfo(image,p,&pixel);
3402 (void) QueryMagickColorname(image,&pixel,SVGCompliance,tuple,
3404 (void) FormatLocaleString(message,MaxTextExtent,
3405 " <circle cx=\"%.20g\" cy=\"%.20g\" r=\"1\" fill=\"%s\"/>\n",
3406 (double) x,(double) y,tuple);
3407 (void) WriteBlobString(image,message);
3408 p+=GetPixelChannels(image);
3411 (void) WriteBlobString(image,"</svg>\n");
3417 static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
3418 ExceptionInfo *exception)
3420 #define BezierQuantum 200
3426 keyword[MaxTextExtent],
3427 message[MaxTextExtent],
3428 name[MaxTextExtent],
3430 type[MaxTextExtent];
3472 Open output image file.
3474 assert(image_info != (const ImageInfo *) NULL);
3475 assert(image_info->signature == MagickSignature);
3476 assert(image != (Image *) NULL);
3477 assert(image->signature == MagickSignature);
3478 if (image->debug != MagickFalse)
3479 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3480 assert(exception != (ExceptionInfo *) NULL);
3481 assert(exception->signature == MagickSignature);
3482 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
3483 if (status == MagickFalse)
3485 value=GetImageArtifact(image,"SVG");
3486 if (value != (char *) NULL)
3488 (void) WriteBlobString(image,value);
3489 (void) CloseBlob(image);
3492 value=GetImageArtifact(image,"MVG");
3493 if (value == (char *) NULL)
3494 return(TraceSVGImage(image));
3498 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3499 (void) WriteBlobString(image,
3500 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3501 (void) WriteBlobString(image,
3502 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3503 (void) FormatLocaleString(message,MaxTextExtent,
3504 "<svg width=\"%.20g\" height=\"%.20g\">\n",(double) image->columns,(double)
3506 (void) WriteBlobString(image,message);
3508 Allocate primitive info memory.
3511 primitive_info=(PrimitiveInfo *) AcquireQuantumMemory(number_points,
3512 sizeof(*primitive_info));
3513 if (primitive_info == (PrimitiveInfo *) NULL)
3514 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3515 GetAffineMatrix(&affine);
3516 token=AcquireString(value);
3520 for (q=(const char *) value; *q != '\0'; )
3523 Interpret graphic primitive.
3525 GetMagickToken(q,&q,keyword);
3526 if (*keyword == '\0')
3528 if (*keyword == '#')
3533 if (active != MagickFalse)
3535 AffineToTransform(image,&affine);
3538 (void) WriteBlobString(image,"<desc>");
3539 (void) WriteBlobString(image,keyword+1);
3540 for ( ; (*q != '\n') && (*q != '\0'); q++)
3543 case '<': (void) WriteBlobString(image,"<"); break;
3544 case '>': (void) WriteBlobString(image,">"); break;
3545 case '&': (void) WriteBlobString(image,"&"); break;
3546 default: (void) WriteBlobByte(image,*q); break;
3548 (void) WriteBlobString(image,"</desc>\n");
3551 primitive_type=UndefinedPrimitive;
3559 if (LocaleCompare("affine",keyword) == 0)
3561 GetMagickToken(q,&q,token);
3562 affine.sx=InterpretLocaleValue(token,(char **) NULL);
3563 GetMagickToken(q,&q,token);
3565 GetMagickToken(q,&q,token);
3566 affine.rx=InterpretLocaleValue(token,(char **) NULL);
3567 GetMagickToken(q,&q,token);
3569 GetMagickToken(q,&q,token);
3570 affine.ry=InterpretLocaleValue(token,(char **) NULL);
3571 GetMagickToken(q,&q,token);
3573 GetMagickToken(q,&q,token);
3574 affine.sy=InterpretLocaleValue(token,(char **) NULL);
3575 GetMagickToken(q,&q,token);
3577 GetMagickToken(q,&q,token);
3578 affine.tx=InterpretLocaleValue(token,(char **) NULL);
3579 GetMagickToken(q,&q,token);
3581 GetMagickToken(q,&q,token);
3582 affine.ty=InterpretLocaleValue(token,(char **) NULL);
3585 if (LocaleCompare("angle",keyword) == 0)
3587 GetMagickToken(q,&q,token);
3588 affine.rx=InterpretLocaleValue(token,(char **) NULL);
3589 affine.ry=InterpretLocaleValue(token,(char **) NULL);
3592 if (LocaleCompare("arc",keyword) == 0)
3594 primitive_type=ArcPrimitive;
3603 if (LocaleCompare("bezier",keyword) == 0)
3605 primitive_type=BezierPrimitive;
3614 if (LocaleCompare("clip-path",keyword) == 0)
3616 GetMagickToken(q,&q,token);
3617 (void) FormatLocaleString(message,MaxTextExtent,
3618 "clip-path:url(#%s);",token);
3619 (void) WriteBlobString(image,message);
3622 if (LocaleCompare("clip-rule",keyword) == 0)
3624 GetMagickToken(q,&q,token);
3625 (void) FormatLocaleString(message,MaxTextExtent,
3626 "clip-rule:%s;",token);
3627 (void) WriteBlobString(image,message);
3630 if (LocaleCompare("clip-units",keyword) == 0)
3632 GetMagickToken(q,&q,token);
3633 (void) FormatLocaleString(message,MaxTextExtent,
3634 "clipPathUnits=%s;",token);
3635 (void) WriteBlobString(image,message);
3638 if (LocaleCompare("circle",keyword) == 0)
3640 primitive_type=CirclePrimitive;
3643 if (LocaleCompare("color",keyword) == 0)
3645 primitive_type=ColorPrimitive;
3654 if (LocaleCompare("decorate",keyword) == 0)
3656 GetMagickToken(q,&q,token);
3657 (void) FormatLocaleString(message,MaxTextExtent,
3658 "text-decoration:%s;",token);
3659 (void) WriteBlobString(image,message);
3668 if (LocaleCompare("ellipse",keyword) == 0)
3670 primitive_type=EllipsePrimitive;
3679 if (LocaleCompare("fill",keyword) == 0)
3681 GetMagickToken(q,&q,token);
3682 (void) FormatLocaleString(message,MaxTextExtent,"fill:%s;",
3684 (void) WriteBlobString(image,message);
3687 if (LocaleCompare("fill-rule",keyword) == 0)
3689 GetMagickToken(q,&q,token);
3690 (void) FormatLocaleString(message,MaxTextExtent,
3691 "fill-rule:%s;",token);
3692 (void) WriteBlobString(image,message);
3695 if (LocaleCompare("fill-opacity",keyword) == 0)
3697 GetMagickToken(q,&q,token);
3698 (void) FormatLocaleString(message,MaxTextExtent,
3699 "fill-opacity:%s;",token);
3700 (void) WriteBlobString(image,message);
3703 if (LocaleCompare("font-family",keyword) == 0)
3705 GetMagickToken(q,&q,token);
3706 (void) FormatLocaleString(message,MaxTextExtent,
3707 "font-family:%s;",token);
3708 (void) WriteBlobString(image,message);
3711 if (LocaleCompare("font-stretch",keyword) == 0)
3713 GetMagickToken(q,&q,token);
3714 (void) FormatLocaleString(message,MaxTextExtent,
3715 "font-stretch:%s;",token);
3716 (void) WriteBlobString(image,message);
3719 if (LocaleCompare("font-style",keyword) == 0)
3721 GetMagickToken(q,&q,token);
3722 (void) FormatLocaleString(message,MaxTextExtent,
3723 "font-style:%s;",token);
3724 (void) WriteBlobString(image,message);
3727 if (LocaleCompare("font-size",keyword) == 0)
3729 GetMagickToken(q,&q,token);
3730 (void) FormatLocaleString(message,MaxTextExtent,
3731 "font-size:%s;",token);
3732 (void) WriteBlobString(image,message);
3735 if (LocaleCompare("font-weight",keyword) == 0)
3737 GetMagickToken(q,&q,token);
3738 (void) FormatLocaleString(message,MaxTextExtent,
3739 "font-weight:%s;",token);
3740 (void) WriteBlobString(image,message);
3749 if (LocaleCompare("gradient-units",keyword) == 0)
3751 GetMagickToken(q,&q,token);
3754 if (LocaleCompare("text-align",keyword) == 0)
3756 GetMagickToken(q,&q,token);
3757 (void) FormatLocaleString(message,MaxTextExtent,
3758 "text-align %s ",token);
3759 (void) WriteBlobString(image,message);
3762 if (LocaleCompare("text-anchor",keyword) == 0)
3764 GetMagickToken(q,&q,token);
3765 (void) FormatLocaleString(message,MaxTextExtent,
3766 "text-anchor %s ",token);
3767 (void) WriteBlobString(image,message);
3776 if (LocaleCompare("image",keyword) == 0)
3778 GetMagickToken(q,&q,token);
3779 primitive_type=ImagePrimitive;
3788 if (LocaleCompare("line",keyword) == 0)
3790 primitive_type=LinePrimitive;
3799 if (LocaleCompare("matte",keyword) == 0)
3801 primitive_type=MattePrimitive;
3810 if (LocaleCompare("opacity",keyword) == 0)
3812 GetMagickToken(q,&q,token);
3813 (void) FormatLocaleString(message,MaxTextExtent,"opacity %s ",
3815 (void) WriteBlobString(image,message);
3824 if (LocaleCompare("path",keyword) == 0)
3826 primitive_type=PathPrimitive;
3829 if (LocaleCompare("point",keyword) == 0)
3831 primitive_type=PointPrimitive;
3834 if (LocaleCompare("polyline",keyword) == 0)
3836 primitive_type=PolylinePrimitive;
3839 if (LocaleCompare("polygon",keyword) == 0)
3841 primitive_type=PolygonPrimitive;
3844 if (LocaleCompare("pop",keyword) == 0)
3846 GetMagickToken(q,&q,token);
3847 if (LocaleCompare("clip-path",token) == 0)
3849 (void) WriteBlobString(image,"</clipPath>\n");
3852 if (LocaleCompare("defs",token) == 0)
3854 (void) WriteBlobString(image,"</defs>\n");
3857 if (LocaleCompare("gradient",token) == 0)
3859 (void) FormatLocaleString(message,MaxTextExtent,
3860 "</%sGradient>\n",type);
3861 (void) WriteBlobString(image,message);
3864 if (LocaleCompare("graphic-context",token) == 0)
3868 ThrowWriterException(DrawError,
3869 "UnbalancedGraphicContextPushPop");
3870 (void) WriteBlobString(image,"</g>\n");
3872 if (LocaleCompare("pattern",token) == 0)
3874 (void) WriteBlobString(image,"</pattern>\n");
3877 if (LocaleCompare("defs",token) == 0)
3878 (void) WriteBlobString(image,"</g>\n");
3881 if (LocaleCompare("push",keyword) == 0)
3883 GetMagickToken(q,&q,token);
3884 if (LocaleCompare("clip-path",token) == 0)
3886 GetMagickToken(q,&q,token);
3887 (void) FormatLocaleString(message,MaxTextExtent,
3888 "<clipPath id=\"%s\">\n",token);
3889 (void) WriteBlobString(image,message);
3892 if (LocaleCompare("defs",token) == 0)
3894 (void) WriteBlobString(image,"<defs>\n");
3897 if (LocaleCompare("gradient",token) == 0)
3899 GetMagickToken(q,&q,token);
3900 (void) CopyMagickString(name,token,MaxTextExtent);
3901 GetMagickToken(q,&q,token);
3902 (void) CopyMagickString(type,token,MaxTextExtent);
3903 GetMagickToken(q,&q,token);
3904 svg_info.segment.x1=InterpretLocaleValue(token,(char **) NULL);
3905 svg_info.element.cx=InterpretLocaleValue(token,(char **) NULL);
3906 GetMagickToken(q,&q,token);
3908 GetMagickToken(q,&q,token);
3909 svg_info.segment.y1=InterpretLocaleValue(token,(char **) NULL);
3910 svg_info.element.cy=InterpretLocaleValue(token,(char **) NULL);
3911 GetMagickToken(q,&q,token);
3913 GetMagickToken(q,&q,token);
3914 svg_info.segment.x2=InterpretLocaleValue(token,(char **) NULL);
3915 svg_info.element.major=InterpretLocaleValue(token,
3917 GetMagickToken(q,&q,token);
3919 GetMagickToken(q,&q,token);
3920 svg_info.segment.y2=InterpretLocaleValue(token,(char **) NULL);
3921 svg_info.element.minor=InterpretLocaleValue(token,
3923 (void) FormatLocaleString(message,MaxTextExtent,
3924 "<%sGradient id=\"%s\" x1=\"%g\" y1=\"%g\" x2=\"%g\" "
3925 "y2=\"%g\">\n",type,name,svg_info.segment.x1,
3926 svg_info.segment.y1,svg_info.segment.x2,svg_info.segment.y2);
3927 if (LocaleCompare(type,"radial") == 0)
3929 GetMagickToken(q,&q,token);
3931 GetMagickToken(q,&q,token);
3932 svg_info.element.angle=InterpretLocaleValue(token,
3934 (void) FormatLocaleString(message,MaxTextExtent,
3935 "<%sGradient id=\"%s\" cx=\"%g\" cy=\"%g\" r=\"%g\" "
3936 "fx=\"%g\" fy=\"%g\">\n",type,name,
3937 svg_info.element.cx,svg_info.element.cy,
3938 svg_info.element.angle,svg_info.element.major,
3939 svg_info.element.minor);
3941 (void) WriteBlobString(image,message);
3944 if (LocaleCompare("graphic-context",token) == 0)
3949 AffineToTransform(image,&affine);
3952 (void) WriteBlobString(image,"<g style=\"");
3955 if (LocaleCompare("pattern",token) == 0)
3957 GetMagickToken(q,&q,token);
3958 (void) CopyMagickString(name,token,MaxTextExtent);
3959 GetMagickToken(q,&q,token);
3960 svg_info.bounds.x=InterpretLocaleValue(token,(char **) NULL);
3961 GetMagickToken(q,&q,token);
3963 GetMagickToken(q,&q,token);
3964 svg_info.bounds.y=InterpretLocaleValue(token,(char **) NULL);
3965 GetMagickToken(q,&q,token);
3967 GetMagickToken(q,&q,token);
3968 svg_info.bounds.width=InterpretLocaleValue(token,
3970 GetMagickToken(q,&q,token);
3972 GetMagickToken(q,&q,token);
3973 svg_info.bounds.height=InterpretLocaleValue(token,
3975 (void) FormatLocaleString(message,MaxTextExtent,
3976 "<pattern id=\"%s\" x=\"%g\" y=\"%g\" width=\"%g\" "
3977 "height=\"%g\">\n",name,svg_info.bounds.x,
3978 svg_info.bounds.y,svg_info.bounds.width,
3979 svg_info.bounds.height);
3980 (void) WriteBlobString(image,message);
3991 if (LocaleCompare("rectangle",keyword) == 0)
3993 primitive_type=RectanglePrimitive;
3996 if (LocaleCompare("roundRectangle",keyword) == 0)
3998 primitive_type=RoundRectanglePrimitive;
4001 if (LocaleCompare("rotate",keyword) == 0)
4003 GetMagickToken(q,&q,token);
4004 (void) FormatLocaleString(message,MaxTextExtent,"rotate(%s) ",
4006 (void) WriteBlobString(image,message);
4015 if (LocaleCompare("scale",keyword) == 0)
4017 GetMagickToken(q,&q,token);
4018 affine.sx=InterpretLocaleValue(token,(char **) NULL);
4019 GetMagickToken(q,&q,token);
4021 GetMagickToken(q,&q,token);
4022 affine.sy=InterpretLocaleValue(token,(char **) NULL);
4025 if (LocaleCompare("skewX",keyword) == 0)
4027 GetMagickToken(q,&q,token);
4028 (void) FormatLocaleString(message,MaxTextExtent,"skewX(%s) ",
4030 (void) WriteBlobString(image,message);
4033 if (LocaleCompare("skewY",keyword) == 0)
4035 GetMagickToken(q,&q,token);
4036 (void) FormatLocaleString(message,MaxTextExtent,"skewY(%s) ",
4038 (void) WriteBlobString(image,message);
4041 if (LocaleCompare("stop-color",keyword) == 0)
4044 color[MaxTextExtent];
4046 GetMagickToken(q,&q,token);
4047 (void) CopyMagickString(color,token,MaxTextExtent);
4048 GetMagickToken(q,&q,token);
4049 (void) FormatLocaleString(message,MaxTextExtent,
4050 " <stop offset=\"%s\" stop-color=\"%s\" />\n",token,color);
4051 (void) WriteBlobString(image,message);
4054 if (LocaleCompare("stroke",keyword) == 0)
4056 GetMagickToken(q,&q,token);
4057 (void) FormatLocaleString(message,MaxTextExtent,"stroke:%s;",
4059 (void) WriteBlobString(image,message);
4062 if (LocaleCompare("stroke-antialias",keyword) == 0)
4064 GetMagickToken(q,&q,token);
4065 (void) FormatLocaleString(message,MaxTextExtent,
4066 "stroke-antialias:%s;",token);
4067 (void) WriteBlobString(image,message);
4070 if (LocaleCompare("stroke-dasharray",keyword) == 0)
4078 GetMagickToken(p,&p,token);
4079 for (k=0; IsPoint(token); k++)
4080 GetMagickToken(p,&p,token);
4081 (void) WriteBlobString(image,"stroke-dasharray:");
4082 for (j=0; j < k; j++)
4084 GetMagickToken(q,&q,token);
4085 (void) FormatLocaleString(message,MaxTextExtent,"%s ",
4087 (void) WriteBlobString(image,message);
4089 (void) WriteBlobString(image,";");
4092 GetMagickToken(q,&q,token);
4093 (void) FormatLocaleString(message,MaxTextExtent,
4094 "stroke-dasharray:%s;",token);
4095 (void) WriteBlobString(image,message);
4098 if (LocaleCompare("stroke-dashoffset",keyword) == 0)
4100 GetMagickToken(q,&q,token);
4101 (void) FormatLocaleString(message,MaxTextExtent,
4102 "stroke-dashoffset:%s;",token);
4103 (void) WriteBlobString(image,message);
4106 if (LocaleCompare("stroke-linecap",keyword) == 0)
4108 GetMagickToken(q,&q,token);
4109 (void) FormatLocaleString(message,MaxTextExtent,
4110 "stroke-linecap:%s;",token);
4111 (void) WriteBlobString(image,message);
4114 if (LocaleCompare("stroke-linejoin",keyword) == 0)
4116 GetMagickToken(q,&q,token);
4117 (void) FormatLocaleString(message,MaxTextExtent,
4118 "stroke-linejoin:%s;",token);
4119 (void) WriteBlobString(image,message);
4122 if (LocaleCompare("stroke-miterlimit",keyword) == 0)
4124 GetMagickToken(q,&q,token);
4125 (void) FormatLocaleString(message,MaxTextExtent,
4126 "stroke-miterlimit:%s;",token);
4127 (void) WriteBlobString(image,message);
4130 if (LocaleCompare("stroke-opacity",keyword) == 0)
4132 GetMagickToken(q,&q,token);
4133 (void) FormatLocaleString(message,MaxTextExtent,
4134 "stroke-opacity:%s;",token);
4135 (void) WriteBlobString(image,message);
4138 if (LocaleCompare("stroke-width",keyword) == 0)
4140 GetMagickToken(q,&q,token);
4141 (void) FormatLocaleString(message,MaxTextExtent,
4142 "stroke-width:%s;",token);
4143 (void) WriteBlobString(image,message);
4152 if (LocaleCompare("text",keyword) == 0)
4154 primitive_type=TextPrimitive;
4157 if (LocaleCompare("text-antialias",keyword) == 0)
4159 GetMagickToken(q,&q,token);
4160 (void) FormatLocaleString(message,MaxTextExtent,
4161 "text-antialias:%s;",token);
4162 (void) WriteBlobString(image,message);
4165 if (LocaleCompare("tspan",keyword) == 0)
4167 primitive_type=TextPrimitive;
4170 if (LocaleCompare("translate",keyword) == 0)
4172 GetMagickToken(q,&q,token);
4173 affine.tx=InterpretLocaleValue(token,(char **) NULL);
4174 GetMagickToken(q,&q,token);
4176 GetMagickToken(q,&q,token);
4177 affine.ty=InterpretLocaleValue(token,(char **) NULL);
4186 if (LocaleCompare("viewbox",keyword) == 0)
4188 GetMagickToken(q,&q,token);
4190 GetMagickToken(q,&q,token);
4191 GetMagickToken(q,&q,token);
4193 GetMagickToken(q,&q,token);
4194 GetMagickToken(q,&q,token);
4196 GetMagickToken(q,&q,token);
4197 GetMagickToken(q,&q,token);
4209 if (status == MagickFalse)
4211 if (primitive_type == UndefinedPrimitive)
4214 Parse the primitive attributes.
4218 for (x=0; *q != '\0'; x++)
4223 if (IsPoint(q) == MagickFalse)
4225 GetMagickToken(q,&q,token);
4226 point.x=InterpretLocaleValue(token,(char **) NULL);
4227 GetMagickToken(q,&q,token);
4229 GetMagickToken(q,&q,token);
4230 point.y=InterpretLocaleValue(token,(char **) NULL);
4231 GetMagickToken(q,(const char **) NULL,token);
4233 GetMagickToken(q,&q,token);
4234 primitive_info[i].primitive=primitive_type;
4235 primitive_info[i].point=point;
4236 primitive_info[i].coordinates=0;
4237 primitive_info[i].method=FloodfillMethod;
4239 if (i < (ssize_t) (number_points-6*BezierQuantum-360))
4241 number_points+=6*BezierQuantum+360;
4242 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4243 number_points,sizeof(*primitive_info));
4244 if (primitive_info == (PrimitiveInfo *) NULL)
4246 (void) ThrowMagickException(exception,GetMagickModule(),
4247 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
4251 primitive_info[j].primitive=primitive_type;
4252 primitive_info[j].coordinates=x;
4253 primitive_info[j].method=FloodfillMethod;
4254 primitive_info[j].text=(char *) NULL;
4257 AffineToTransform(image,&affine);
4261 switch (primitive_type)
4263 case PointPrimitive:
4266 if (primitive_info[j].coordinates != 1)
4275 if (primitive_info[j].coordinates != 2)
4280 (void) FormatLocaleString(message,MaxTextExtent,
4281 " <line x1=\"%g\" y1=\"%g\" x2=\"%g\" y2=\"%g\"/>\n",
4282 primitive_info[j].point.x,primitive_info[j].point.y,
4283 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4284 (void) WriteBlobString(image,message);
4287 case RectanglePrimitive:
4289 if (primitive_info[j].coordinates != 2)
4294 (void) FormatLocaleString(message,MaxTextExtent,
4295 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"/>\n",
4296 primitive_info[j].point.x,primitive_info[j].point.y,
4297 primitive_info[j+1].point.x-primitive_info[j].point.x,
4298 primitive_info[j+1].point.y-primitive_info[j].point.y);
4299 (void) WriteBlobString(image,message);
4302 case RoundRectanglePrimitive:
4304 if (primitive_info[j].coordinates != 3)
4309 (void) FormatLocaleString(message,MaxTextExtent,
4310 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" rx=\"%g\" "
4311 "ry=\"%g\"/>\n",primitive_info[j].point.x,
4312 primitive_info[j].point.y,primitive_info[j+1].point.x-
4313 primitive_info[j].point.x,primitive_info[j+1].point.y-
4314 primitive_info[j].point.y,primitive_info[j+2].point.x,
4315 primitive_info[j+2].point.y);
4316 (void) WriteBlobString(image,message);
4321 if (primitive_info[j].coordinates != 3)
4328 case EllipsePrimitive:
4330 if (primitive_info[j].coordinates != 3)
4335 (void) FormatLocaleString(message,MaxTextExtent,
4336 " <ellipse cx=\"%g\" cy=\"%g\" rx=\"%g\" ry=\"%g\"/>\n",
4337 primitive_info[j].point.x,primitive_info[j].point.y,
4338 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4339 (void) WriteBlobString(image,message);
4342 case CirclePrimitive:
4348 if (primitive_info[j].coordinates != 2)
4353 alpha=primitive_info[j+1].point.x-primitive_info[j].point.x;
4354 beta=primitive_info[j+1].point.y-primitive_info[j].point.y;
4355 (void) FormatLocaleString(message,MaxTextExtent,
4356 " <circle cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
4357 primitive_info[j].point.x,primitive_info[j].point.y,
4359 (void) WriteBlobString(image,message);
4362 case PolylinePrimitive:
4364 if (primitive_info[j].coordinates < 2)
4369 (void) CopyMagickString(message," <polyline points=\"",MaxTextExtent);
4370 (void) WriteBlobString(image,message);
4371 length=strlen(message);
4374 (void) FormatLocaleString(message,MaxTextExtent,"%g,%g ",
4375 primitive_info[j].point.x,primitive_info[j].point.y);
4376 length+=strlen(message);
4379 (void) WriteBlobString(image,"\n ");
4380 length=strlen(message)+5;
4382 (void) WriteBlobString(image,message);
4384 (void) WriteBlobString(image,"\"/>\n");
4387 case PolygonPrimitive:
4389 if (primitive_info[j].coordinates < 3)
4394 primitive_info[i]=primitive_info[j];
4395 primitive_info[i].coordinates=0;
4396 primitive_info[j].coordinates++;
4398 (void) CopyMagickString(message," <polygon points=\"",MaxTextExtent);
4399 (void) WriteBlobString(image,message);
4400 length=strlen(message);
4403 (void) FormatLocaleString(message,MaxTextExtent,"%g,%g ",
4404 primitive_info[j].point.x,primitive_info[j].point.y);
4405 length+=strlen(message);
4408 (void) WriteBlobString(image,"\n ");
4409 length=strlen(message)+5;
4411 (void) WriteBlobString(image,message);
4413 (void) WriteBlobString(image,"\"/>\n");
4416 case BezierPrimitive:
4418 if (primitive_info[j].coordinates < 3)
4430 GetMagickToken(q,&q,token);
4431 number_attributes=1;
4432 for (p=token; *p != '\0'; p++)
4433 if (isalpha((int) *p))
4434 number_attributes++;
4435 if (i > (ssize_t) (number_points-6*BezierQuantum*number_attributes-1))
4437 number_points+=6*BezierQuantum*number_attributes;
4438 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4439 number_points,sizeof(*primitive_info));
4440 if (primitive_info == (PrimitiveInfo *) NULL)
4442 (void) ThrowMagickException(exception,GetMagickModule(),
4443 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4448 (void) WriteBlobString(image," <path d=\"");
4449 (void) WriteBlobString(image,token);
4450 (void) WriteBlobString(image,"\"/>\n");
4453 case ColorPrimitive:
4454 case MattePrimitive:
4456 if (primitive_info[j].coordinates != 1)
4461 GetMagickToken(q,&q,token);
4462 if (LocaleCompare("point",token) == 0)
4463 primitive_info[j].method=PointMethod;
4464 if (LocaleCompare("replace",token) == 0)
4465 primitive_info[j].method=ReplaceMethod;
4466 if (LocaleCompare("floodfill",token) == 0)
4467 primitive_info[j].method=FloodfillMethod;
4468 if (LocaleCompare("filltoborder",token) == 0)
4469 primitive_info[j].method=FillToBorderMethod;
4470 if (LocaleCompare("reset",token) == 0)
4471 primitive_info[j].method=ResetMethod;
4479 if (primitive_info[j].coordinates != 1)
4484 GetMagickToken(q,&q,token);
4485 (void) FormatLocaleString(message,MaxTextExtent,
4486 " <text x=\"%g\" y=\"%g\">",primitive_info[j].point.x,
4487 primitive_info[j].point.y);
4488 (void) WriteBlobString(image,message);
4489 for (p=token; *p != '\0'; p++)
4492 case '<': (void) WriteBlobString(image,"<"); break;
4493 case '>': (void) WriteBlobString(image,">"); break;
4494 case '&': (void) WriteBlobString(image,"&"); break;
4495 default: (void) WriteBlobByte(image,*p); break;
4497 (void) WriteBlobString(image,"</text>\n");
4500 case ImagePrimitive:
4502 if (primitive_info[j].coordinates != 2)
4507 GetMagickToken(q,&q,token);
4508 (void) FormatLocaleString(message,MaxTextExtent,
4509 " <image x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" "
4510 "xlink:href=\"%s\"/>\n",primitive_info[j].point.x,
4511 primitive_info[j].point.y,primitive_info[j+1].point.x,
4512 primitive_info[j+1].point.y,token);
4513 (void) WriteBlobString(image,message);
4517 if (primitive_info == (PrimitiveInfo *) NULL)
4519 primitive_info[i].primitive=UndefinedPrimitive;
4520 if (status == MagickFalse)
4523 (void) WriteBlobString(image,"</svg>\n");
4525 Relinquish resources.
4527 token=DestroyString(token);
4528 if (primitive_info != (PrimitiveInfo *) NULL)
4529 primitive_info=(PrimitiveInfo *) RelinquishMagickMemory(primitive_info);
4530 (void) CloseBlob(image);